Die nachfolgende Routine ist eine Weiterentwicklung von Beispiel B12, denn hier wird der verschlüsselte String (ciphertext) nicht in Form eines Byte Arrays „weitergegeben“, sondern die Übergaben erfolgen über einen Base64-kodierten String (eine kleine Erläuterung findet Ihr im Beispiel A09 Base64-Kodierung). Der große Vorteil besteht darin, das diese Daten sehr einfach mittels Email weitergegeben werden können und der verwendete Zeichensatz auf nahezu allen (zumindest den mit lateinischem Zeichensatz) Computersystemen verwendet wird.
Hier der Steckbrief des Verfahrens:
Verschlüsselungssteckbrief | |
Name des Verfahrens | AES/GCM/NOPADDING |
Langname | GCM Galois_Counter Mode |
Art der Chiffre | Blockchiffre, auch Stream-Chiffre |
Blocklänge (Byte) | 16 |
Schlüssellänge (Byte/Bit) | 16/128, 24/192, 32/256 |
Padding genutzt | Nein |
Sicherheit | sicher bei Nutzung von unterschiedlichen Initialvektoren |
Besonderes | Benötigt einen Initialvektor, der als Zufallszahl erzeugt wird. Möglich ist auch die Verbindung eines Nonce mit einem fortlaufenden Zähler. |
Bitte die nachfolgende Routine nur nach einer gründlichen Überprüfung für den Echteinsatz nutzen. Aus kryptographischer Sicht dürfte sie für viele Einsatzgebiete nutzbar sein.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
package net.bplaced.javacrypto.symmetricencryption; /* * Herkunft/Origin: http://javacrypto.bplaced.net/ * Programmierer/Programmer: Michael Fehr * Copyright/Copyright: frei verwendbares Programm (Public Domain) * Copyright: This is free and unencumbered software released into the public domain. * Lizenttext/Licence: <http://unlicense.org> * getestet mit/tested with: Java Runtime Environment 8 Update 191 x64 * Datum/Date (dd.mm.jjjj): 15.11.2018 * Funktion: verschlüsselt einen Text im AESs GCM Modus kein Padding * die Ausgabe erfolgt als Base64-kodierter String * Function: encrypts a text string using AES GCM modus with no padding * the output is decode as a Base64-string * * Sicherheitshinweis/Security notice * Die Programmroutinen dienen nur der Darstellung und haben keinen Anspruch auf eine * korrekte Funktion, insbesondere mit Blick auf die Sicherheit ! * Prüfen Sie die Sicherheit bevor das Programm in der echten Welt eingesetzt wird. * The program routines just show the function but please be aware of the security part - * check yourself before using in the real world ! */ import java.io.UnsupportedEncodingException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; import java.util.Base64; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; public class B13_AesGcmNoPaddingRandomBase64String { public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { System.out.println( "B13 AES im Betriebsmodus GCM Kein Padding mit Zufalls-GCM Nonce, Base64-Kodierung mit einem String"); // es werden ein paar variablen benötigt: String plaintextString = "Dieses ist der super geheime Text"; byte[] plaintextByte = plaintextString.getBytes("UTF-8"); final int GCMNONCELENGTH = 12; // = 96 bit String decryptedtextString = ""; // enthält später den entschlüsselten text // diese konstanten und variablen benötigen wir zur ver- und entschlüsselung // der schlüssel ist exakt 32 zeichen lang und bestimmt die stärke der // verschlüsselung. mögliche schlüssellängen sind 16 byte (128 bit), // 24 byte (192 bit) und 32 byte (256 bit) final byte[] keyByte = "12345678901234567890123456789012".getBytes("UTF-8"); // 32 byte // GENERATE random nonce (number used once) final byte[] gcmNonceByte = new byte[GCMNONCELENGTH]; SecureRandom secureRandomGcm = new SecureRandom(); secureRandomGcm.nextBytes(gcmNonceByte); // der verschluesselte (encrypted) text kommt in diese variable in form eines // byte arrays byte[] ciphertextByte = null; // die länge steht noch nicht fest, da sie von der größe des plaintextes abhängt // der entschlüsselte (decrypted) text kommt in dieses byte array, welches // später in einen string umkodiert wird byte[] decryptedtextByte = null; // die länge steht noch nicht fest, da sie von der größe des plaintextes // abhängt // ab hier arbeiten wir nun im verschlüsselungsmodus // umwandlung des klartextes in ein byte array plaintextByte = plaintextString.getBytes("UTF-8"); // hier erfolgt nun die verschlüsselung des plaintextes ciphertextByte = AesGcmNoPaddingEncrypt(plaintextByte, keyByte, gcmNonceByte); // byte array aus gcmNonceByte und ciphertextByte erzeugen byte[] gcmNonceCiphertextByte = new byte[(GCMNONCELENGTH + ciphertextByte.length)]; System.arraycopy(gcmNonceByte, 0, gcmNonceCiphertextByte, 0, GCMNONCELENGTH); System.arraycopy(ciphertextByte, 0, gcmNonceCiphertextByte, GCMNONCELENGTH, ciphertextByte.length); // byte array in einen base64-string umwandeln String gcmNonceCiphertextString = Base64.getEncoder().encodeToString(gcmNonceCiphertextByte); // ausgabe der daten System.out.println(""); System.out.println("Klartextdaten verschlüsseln und als Base64-String anzeigen"); System.out.println("plaintextString :" + plaintextString); System.out.println("plaintextByte (hex) :" + DatatypeConverter.printHexBinary(plaintextByte)); System.out.println("gcmNonceByte (hex) :" + DatatypeConverter.printHexBinary(gcmNonceByte)); System.out.println("keyByte (hex) :" + DatatypeConverter.printHexBinary(keyByte)); System.out.println("= = = Verschlüsselung = = ="); System.out.println("ciphertextByte (hex) :" + DatatypeConverter.printHexBinary(ciphertextByte)); System.out.println("= = = gcmNonceByte + ciphertextByte = = ="); System.out.println("gcmNonceCiphertextByte (hex) :" + DatatypeConverter.printHexBinary(gcmNonceCiphertextByte)); System.out.println("gcmNonceCiphertextString(B64):" + gcmNonceCiphertextString); // ab hier arbeiten wir nun im entschlüsselungsmodus // hier simulieren wir die eingabe des keybytes final byte[] keyByteDecrypt = "12345678901234567890123456789012".getBytes("UTF-8"); // 32 byte // hier simulieren wir den empfang der nachricht String receivedMessageString = gcmNonceCiphertextString; // umwandlung des base64-strings in ein byte array byte[] gcmNonceCiphertextByteReceived = Base64.getDecoder().decode(receivedMessageString); // aufteilung gcmNonce + ciphertext byte[] gcmNonceByteReceived = Arrays.copyOfRange(gcmNonceCiphertextByteReceived, 0, GCMNONCELENGTH); byte[] ciphertextByteReceived = Arrays.copyOfRange(gcmNonceCiphertextByteReceived, GCMNONCELENGTH, gcmNonceCiphertextByteReceived.length); // nun wird der ciphertext wieder entschlüsselt decryptedtextByte = AesGcmNoPaddingDecrypt(ciphertextByteReceived, keyByteDecrypt, gcmNonceByteReceived); // zurück-kodierung des byte array in text decryptedtextString = new String(decryptedtextByte, "UTF-8"); // ausgabe der daten System.out.println(""); System.out.println("= = = Erhaltene Daten = = = "); System.out.println("receivedMessageString Base64 :" + receivedMessageString); System.out.println( "gcmNonceCiphertextByteR (hex):" + DatatypeConverter.printHexBinary(gcmNonceCiphertextByteReceived)); System.out.println("gcmNonceByteReceived (hex) :" + DatatypeConverter.printHexBinary(gcmNonceByteReceived)); System.out.println("ciphertextByteReceived (hex) :" + DatatypeConverter.printHexBinary(ciphertextByteReceived)); System.out.println("= = = geheimer Schlüssel = = ="); System.out.println("keyByteDecrypt (hex) :" + DatatypeConverter.printHexBinary(keyByteDecrypt)); System.out.println("= = = Entschlüsselung = = ="); System.out.println("decryptedtextByte (hex) :" + DatatypeConverter.printHexBinary(decryptedtextByte)); System.out.println("decryptedtextString :" + decryptedtextString); } public static byte[] AesGcmNoPaddingEncrypt(byte[] plaintextByte, byte[] keyByte, byte[] gcmNonceByte) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { final int GCM_TAG_LENGTH = 128; byte[] ciphertextByte = null; // der schlüssel wird in die richtige form gebracht SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES"); // statt eines initvectors wird ein gcm parameter benoetigt GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, gcmNonceByte); // die verschlüsselungsroutine wird mit dem gewünschten parameter erstellt Cipher aesCipherEnc = Cipher.getInstance("AES/GCM/NoPadding"); // nun wird die routine mit dem schlüssel initialisiert aesCipherEnc.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec); // hier erfolgt nun die verschlüsselung des plaintextes ciphertextByte = aesCipherEnc.doFinal(plaintextByte); return ciphertextByte; } public static byte[] AesGcmNoPaddingDecrypt(byte[] ciphertextByte, byte[] keyByte, byte[] gcmNonceByte) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { final int GCM_TAG_LENGTH = 128; byte[] decryptedtextByte = null; // der schlüssel wird in die richtige form gebracht SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES"); // statt eines initvectors wird ein gcm parameter benoetigt GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, gcmNonceByte); // die verschlüsselungsroutine wird mit dem gewünschten parameter erstellt Cipher aesCipherDec = Cipher.getInstance("AES/GCM/NoPadding"); // nun wird die routine mit dem schlüssel initialisiert aesCipherDec.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec); // hier erfolgt nun die verschlüsselung des plaintextes decryptedtextByte = aesCipherDec.doFinal(ciphertextByte); return decryptedtextByte; } } |
Das Ergebnis findet Ihr in der Konsole:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
B13 AES im Betriebsmodus GCM Kein Padding mit Zufalls-GCM Nonce, Base64-Kodierung mit einem String Klartextdaten verschlüsseln und als Base64-String anzeigen plaintextString :Dieses ist der super geheime Text plaintextByte (hex) :44696573657320697374206465722073757065722067656865696D652054657874 gcmNonceByte (hex) :14C5DAE643E12A965107F554 keyByte (hex) :3132333435363738393031323334353637383930313233343536373839303132 = = = Verschlüsselung = = = ciphertextByte (hex) :B04D603201645F3657750DB4D372E81E4371909234F281D48BAFD41546CF300F40093765F3D833DF0E8B5497AAD906C14B = = = gcmNonceByte + ciphertextByte = = = gcmNonceCiphertextByte (hex) :14C5DAE643E12A965107F554B04D603201645F3657750DB4D372E81E4371909234F281D48BAFD41546CF300F40093765F3D833DF0E8B5497AAD906C14B gcmNonceCiphertextString(B64):FMXa5kPhKpZRB/VUsE1gMgFkXzZXdQ2003LoHkNxkJI08oHUi6/UFUbPMA9ACTdl89gz3w6LVJeq2QbBSw== = = = Erhaltene Daten = = = receivedMessageString Base64 :FMXa5kPhKpZRB/VUsE1gMgFkXzZXdQ2003LoHkNxkJI08oHUi6/UFUbPMA9ACTdl89gz3w6LVJeq2QbBSw== gcmNonceCiphertextByteR (hex):14C5DAE643E12A965107F554B04D603201645F3657750DB4D372E81E4371909234F281D48BAFD41546CF300F40093765F3D833DF0E8B5497AAD906C14B gcmNonceByteReceived (hex) :14C5DAE643E12A965107F554 ciphertextByteReceived (hex) :B04D603201645F3657750DB4D372E81E4371909234F281D48BAFD41546CF300F40093765F3D833DF0E8B5497AAD906C14B = = = geheimer Schlüssel = = = keyByteDecrypt (hex) :3132333435363738393031323334353637383930313233343536373839303132 = = = Entschlüsselung = = = decryptedtextByte (hex) :44696573657320697374206465722073757065722067656865696D652054657874 decryptedtextString :Dieses ist der super geheime Text |
Die Lizenz zum obigen Beispiel findet Ihr auf der eigenen Lizenz-Seite.
Letzte Aktualisierung: 15.11.2018