Das nachfolgend gezeigte Programm erfüllt schon sehr viele Anforderungen an eine sichere Verschlüsselung. Ich nutze den AES Betriebsmodus GCM, erzeuge einen Zufalls GCM Nonce, die Verwendung von ergänzenden Daten („AAD“) ist möglich und das verwendete Passwort wird durch den PBKDF2-Algorithmus mehrere tausend Male der Hash-Routine unterworfen. Zur Weitergabe der verschlüsselten Daten (z.B. per Mail) werden die AAD-Daten und der komplette Verschlüsselungs-Datensatz per Base64-Kodierung in einen String verwandelt.
Solltet Ihr eine Variante mit kompletter Dateiverschlüsselung wünschen, schaut Euch das Programm B16… Datei an, dort wird eine Klartextdatei verschlüsselt und später wieder entschlüsselt.
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. Zusätzlich können ergänzende Daten (AAD) genutzt werden. |
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 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
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): 08.12.2018 * Funktion: verschlüsselt einen Text im AESs GCM Modus kein Padding * die Ausgabe erfolgt als Base64-kodierter String * zusätzlich werden ergänzende Daten (aad) genutzt * Function: encrypts a text string using AES GCM modus with no padding * the output is decode as a Base64-string * additionally it uses Additional Associated Data (aad) * * 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.nio.ByteBuffer; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; 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.SecretKeyFactory; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; public class B15_AesGcmNoPaddingRandomAadPbkdf2Base64String { public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException { System.out.println( "B15 AES im Betriebsmodus GCM Kein Padding mit Zufalls-GCM Nonce, AAD, PBKDF2 und 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"); // der gcm modus bietet an, ergänzende daten ohne verschlüsselung mit zu // speichern // diese daten werden ebenfalls mit dem hashwert gesichert String aadtextString = "Hier stehen die AAD-Daten"; byte[] aadtextByte = aadtextString.getBytes("utf-8"); // das passwort wird z.b. von einem jPassword-Feld übergeben char[] passwordChar = "12345678901234567890123456789012".toCharArray(); // erzeugung des password-keys mittels PBKDF2 // variablen für pbkdf2 final int PBKDF2_ITERATIONS = 10000; // anzahl der iterationen, höher = besser = langsamer final int SALT_SIZE_BYTE = 256; // grösse des salts, sollte so groß wie der hash sein final int HASH_SIZE_BYTE = 256; // größe das hashes bzw. gehashten passwortes, 256 byte byte[] passwordHashByte = new byte[HASH_SIZE_BYTE]; // das array nimmt das gehashte passwort auf // wir erzeugen einen zufalls salt mit securerandom, nicht mit random SecureRandom secureRandom = new SecureRandom(); byte passwordSaltByte[] = new byte[SALT_SIZE_BYTE]; secureRandom.nextBytes(passwordSaltByte); // erstellung des gehashten passwortes PBEKeySpec spec = new PBEKeySpec(passwordChar, passwordSaltByte, PBKDF2_ITERATIONS, HASH_SIZE_BYTE); SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512"); passwordHashByte = skf.generateSecret(spec).getEncoded(); // ab hier "normale" gcm-routinen 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 // 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 = AesGcmNoPaddingAadEncrypt(plaintextByte, aadtextByte, passwordHashByte, gcmNonceByte); // aus sicherheitsgründen löschen wir die wichtigen byte arrays Arrays.fill(plaintextByte, (byte) 0); // überschreibt das byte array mit nullen Arrays.fill(passwordHashByte, (byte) 0); // überschreibt das byte array mit nullen Arrays.fill(passwordChar, (char) 0); // überschreibt das char array mit nullen // byte array aus PBKDF2_ITERATIONS, passwordSaltByte, gcmNonceByte und // ciphertextByte erzeugen // integer wert pbkdf2_iterations in byte array umwandeln // pbkdf2_iterationsByte ist 4 byte lang byte[] pbkdf2_iterationsByte = ByteBuffer.allocate(4).putInt(PBKDF2_ITERATIONS).array(); // gcmCompleteCiphertextByte enthält später den kompletten datensatz byte[] gcmCompleteCiphertextByte = new byte[(pbkdf2_iterationsByte.length + SALT_SIZE_BYTE + GCMNONCELENGTH + ciphertextByte.length)]; System.arraycopy(pbkdf2_iterationsByte, 0, gcmCompleteCiphertextByte, 0, 4); System.arraycopy(passwordSaltByte, 0, gcmCompleteCiphertextByte, 4, SALT_SIZE_BYTE); System.arraycopy(gcmNonceByte, 0, gcmCompleteCiphertextByte, (4 + SALT_SIZE_BYTE), GCMNONCELENGTH); System.arraycopy(ciphertextByte, 0, gcmCompleteCiphertextByte, (4 + SALT_SIZE_BYTE + GCMNONCELENGTH), ciphertextByte.length); // byte array in einen base64-string umwandeln String gcmCompleteCiphertextString = Base64.getEncoder().encodeToString(gcmCompleteCiphertextByte); // aad-daten ebenfalls in einen base64-string umwandeln String aadtextB64String = Base64.getEncoder().encodeToString(aadtextByte); // ausgabe der daten System.out.println("Klartextdaten verschlüsseln und als Base64-String anzeigen"); System.out.println("plaintextString :" + plaintextString); System.out.println("plaintextByte (hex) :" + " * * * Das Byte Array wurde gelöscht * * *"); System.out.println("passwordChar (hex) :" + " * * * Das Char Array wurde gelöscht * * *"); System.out.println("gcmNonceByte (hex) :" + DatatypeConverter.printHexBinary(gcmNonceByte)); System.out.println("passwordSaltByte (hex) :" + DatatypeConverter.printHexBinary(passwordSaltByte)); System.out.println("passwordHashByte (hex) :" + " * * * Das Byte Array wurde gelöscht * * *"); System.out.println("aadtextString :" + aadtextString); System.out.println("aadtextByte (hex) :" + DatatypeConverter.printHexBinary(aadtextByte)); System.out.println("aadtextString (B64) :" + aadtextB64String); System.out.println("= = = Verschlüsselung = = ="); System.out.println("ciphertextByte (hex) :" + DatatypeConverter.printHexBinary(ciphertextByte)); System.out.println("= = = gcmNonceByte + ciphertextByte = = ="); System.out.println( "gcmCompleteCiphertextByte (hex) :" + DatatypeConverter.printHexBinary(gcmCompleteCiphertextByte)); System.out.println("gcmCompleteCiphertextString(B64):" + gcmCompleteCiphertextString); // ab hier arbeiten wir nun im entschlüsselungsmodus // simulation der eingabe des passwortes // das passwort wird z.b. von einem jPassword-Feld übergeben char[] passwordCharDecrypt = "12345678901234567890123456789012".toCharArray(); // simulation des empfangs der nachricht // zuerst die aad-daten dekodieren String receivedAadtextB64String = aadtextB64String; byte[] aadtextByteReceived = Base64.getDecoder().decode(receivedAadtextB64String); String aadtextStringReceived = new String(aadtextByteReceived, "UTF-8"); // ganz wichtig: wir benötigen zur entschlüsselung auch die aad-daten // simulation von falsch erhaltenen aad-daten - einfach die zeile ohne // kommentarvermerk ausführen // aadtextByteReceived = "Hier stehen die AAD-Daten1".getBytes("utf-8"); byte[] passwordHashByteDecrypt = null; // jetzt die verschlüsselten daten erhalten String receivedMessageString = gcmCompleteCiphertextString; // umwandlung des base64-strings in ein byte array byte[] gcmCompleteCiphertextByteReceived = Base64.getDecoder().decode(receivedMessageString); // aufteilung PBKDF2_ITERATIONS, passwordSaltByte, gcmNonceByte und // ciphertextByte int PBKDF2_ITERATIONS_RECEIVED = 0; byte[] pbkdf2_iterationsByteReceived = Arrays.copyOfRange(gcmCompleteCiphertextByteReceived, 0, 4); PBKDF2_ITERATIONS_RECEIVED = ByteBuffer.wrap(pbkdf2_iterationsByteReceived).getInt(); byte[] passwordSaltByteReceived = Arrays.copyOfRange(gcmCompleteCiphertextByteReceived, 4, 4 + SALT_SIZE_BYTE); byte[] gcmNonceByteReceived = Arrays.copyOfRange(gcmCompleteCiphertextByteReceived, (4 + SALT_SIZE_BYTE), (4 + SALT_SIZE_BYTE) + GCMNONCELENGTH); byte[] ciphertextByteReceived = Arrays.copyOfRange(gcmCompleteCiphertextByteReceived, (4 + SALT_SIZE_BYTE + GCMNONCELENGTH), gcmCompleteCiphertextByteReceived.length); // aus dem eingegebenen passwort und den übergebenen iterationen und de salt // wird der passwordHashByteDecrypt errechnet PBEKeySpec specDec = new PBEKeySpec(passwordCharDecrypt, passwordSaltByteReceived, PBKDF2_ITERATIONS_RECEIVED, HASH_SIZE_BYTE); SecretKeyFactory skfDecrypt = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512"); passwordHashByteDecrypt = skfDecrypt.generateSecret(specDec).getEncoded(); // nun wird der ciphertext wieder entschlüsselt decryptedtextByte = AesGcmNoPaddingAadDecrypt(ciphertextByteReceived, aadtextByteReceived, passwordHashByteDecrypt, gcmNonceByteReceived); // aus sicherheitsgründen löschen wir die wichtigen byte arrays Arrays.fill(passwordHashByteDecrypt, (byte) 0); // überschreibt das byte array mit nullen Arrays.fill(passwordChar, (char) 0); // überschreibt das char array mit nullen // 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("gcmCompleteCiphertextByteReceived:" + DatatypeConverter.printHexBinary(gcmCompleteCiphertextByteReceived)); System.out .println("aadtextByte (hex) :" + DatatypeConverter.printHexBinary(aadtextByteReceived)); System.out.println("aadtextStringReceived :" + aadtextStringReceived); System.out.println("receivedMessageString Base64 :" + receivedMessageString); System.out.println("gcmCompleteCiphertextByteR (hex) :" + DatatypeConverter.printHexBinary(gcmCompleteCiphertextByteReceived)); System.out.println( "passwordSaltByte Received :" + DatatypeConverter.printHexBinary(passwordSaltByteReceived)); System.out.println("passwordHashByteDecrypt :" + " * * * Das Byte Array wurde gelöscht * * *"); System.out .println("gcmNonceByteReceived (hex) :" + DatatypeConverter.printHexBinary(gcmNonceByteReceived)); System.out.println( "ciphertextByteReceived (hex) :" + DatatypeConverter.printHexBinary(ciphertextByteReceived)); System.out.println("= = = Entschlüsselung = = ="); System.out.println("decryptedtextByte (hex) :" + DatatypeConverter.printHexBinary(decryptedtextByte)); System.out.println("decryptedtextString :" + decryptedtextString); } public static byte[] AesGcmNoPaddingAadEncrypt(byte[] plaintextByte, byte[] aadtextByte, 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); // einbindung der aad-daten aesCipherEnc.updateAAD(aadtextByte); // hier erfolgt nun die verschlüsselung des plaintextes ciphertextByte = aesCipherEnc.doFinal(plaintextByte); return ciphertextByte; } public static byte[] AesGcmNoPaddingAadDecrypt(byte[] ciphertextByte, byte[] aadtextByte, 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); // einbindung der aad-daten aesCipherDec.updateAAD(aadtextByte); // hier erfolgt nun die verschlüsselung des plaintextes decryptedtextByte = aesCipherDec.doFinal(ciphertextByte); return decryptedtextByte; } } |
Die Konsole zeigt die folgende Ausgabe. Bitte beachtet, das innerhalb des Programms die sensiblen Arrays gelöscht werden:
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 |
B15 AES im Betriebsmodus GCM Kein Padding mit Zufalls-GCM Nonce, AAD, PBKDF2 und Base64-Kodierung mit einem String Klartextdaten verschlüsseln und als Base64-String anzeigen plaintextString :Dieses ist der super geheime Text plaintextByte (hex) : * * * Das Byte Array wurde gelöscht * * * passwordChar (hex) : * * * Das Char Array wurde gelöscht * * * gcmNonceByte (hex) :78B0CDDCD3CD0BD5383CF12D passwordSaltByte (hex) :9BD88905A0FE7B43E7A6FAEBC10D8CD983352FE3BCC5657401C4FBDAA11A2D06980FFDD5DAA414B8B291F077B1D6CFD55942452368AB10C5457AC11A5A9D0DCA0C867E1501E135D4457BA97766C4D25788B08D78F6F53ABEF1E7D71589E385F78FFC69315D3E090A077688F49A92FD5FDC4E80F2987434DED0DDEC8131F7A1DBC82AB426285FAB2B4EE1BC2EC68559D86517650BCB76D1A899CAFBC51E6450AA027AFAC6BCA47B86995D0A1B30644D0CCED7D24C8000EB9D567F7ECECE9A9C24E8DA43A4129813760E3ADC6A6C4A502D6B7C9493B4518ECCBCEF888A28DCCC0944F0B71D754287D8A89BC89D80E855E9C92A6CAC3EFE3DCB89ED32684012D56E passwordHashByte (hex) : * * * Das Byte Array wurde gelöscht * * * aadtextString :Hier stehen die AAD-Daten aadtextByte (hex) :486965722073746568656E20646965204141442D446174656E aadtextString (B64) :SGllciBzdGVoZW4gZGllIEFBRC1EYXRlbg== = = = Verschlüsselung = = = ciphertextByte (hex) :74222DB8BFE70B5CAA18CF71C663A93B063529C0BCABF418EDF05279CF6E7D87D221E8B80B0C98BE360F83C950FC722B03 = = = gcmNonceByte + ciphertextByte = = = gcmCompleteCiphertextByte (hex) :000027109BD88905A0FE7B43E7A6FAEBC10D8CD983352FE3BCC5657401C4FBDAA11A2D06980FFDD5DAA414B8B291F077B1D6CFD55942452368AB10C5457AC11A5A9D0DCA0C867E1501E135D4457BA97766C4D25788B08D78F6F53ABEF1E7D71589E385F78FFC69315D3E090A077688F49A92FD5FDC4E80F2987434DED0DDEC8131F7A1DBC82AB426285FAB2B4EE1BC2EC68559D86517650BCB76D1A899CAFBC51E6450AA027AFAC6BCA47B86995D0A1B30644D0CCED7D24C8000EB9D567F7ECECE9A9C24E8DA43A4129813760E3ADC6A6C4A502D6B7C9493B4518ECCBCEF888A28DCCC0944F0B71D754287D8A89BC89D80E855E9C92A6CAC3EFE3DCB89ED32684012D56E78B0CDDCD3CD0BD5383CF12D74222DB8BFE70B5CAA18CF71C663A93B063529C0BCABF418EDF05279CF6E7D87D221E8B80B0C98BE360F83C950FC722B03 gcmCompleteCiphertextString(B64):AAAnEJvYiQWg/ntD56b668ENjNmDNS/jvMVldAHE+9qhGi0GmA/91dqkFLiykfB3sdbP1VlCRSNoqxDFRXrBGlqdDcoMhn4VAeE11EV7qXdmxNJXiLCNePb1Or7x59cVieOF94/8aTFdPgkKB3aI9JqS/V/cToDymHQ03tDd7IEx96HbyCq0JihfqytO4bwuxoVZ2GUXZQvLdtGomcr7xR5kUKoCevrGvKR7hpldChswZE0MztfSTIAA651Wf37OzpqcJOjaQ6QSmBN2DjrcamxKUC1rfJSTtFGOzLzviIoo3MwJRPC3HXVCh9iom8idgOhV6ckqbKw+/j3Lie0yaEAS1W54sM3c080L1Tg88S10Ii24v+cLXKoYz3HGY6k7BjUpwLyr9Bjt8FJ5z259h9Ih6LgLDJi+Ng+DyVD8cisD = = = Erhaltene Daten = = = gcmCompleteCiphertextByteReceived:000027109BD88905A0FE7B43E7A6FAEBC10D8CD983352FE3BCC5657401C4FBDAA11A2D06980FFDD5DAA414B8B291F077B1D6CFD55942452368AB10C5457AC11A5A9D0DCA0C867E1501E135D4457BA97766C4D25788B08D78F6F53ABEF1E7D71589E385F78FFC69315D3E090A077688F49A92FD5FDC4E80F2987434DED0DDEC8131F7A1DBC82AB426285FAB2B4EE1BC2EC68559D86517650BCB76D1A899CAFBC51E6450AA027AFAC6BCA47B86995D0A1B30644D0CCED7D24C8000EB9D567F7ECECE9A9C24E8DA43A4129813760E3ADC6A6C4A502D6B7C9493B4518ECCBCEF888A28DCCC0944F0B71D754287D8A89BC89D80E855E9C92A6CAC3EFE3DCB89ED32684012D56E78B0CDDCD3CD0BD5383CF12D74222DB8BFE70B5CAA18CF71C663A93B063529C0BCABF418EDF05279CF6E7D87D221E8B80B0C98BE360F83C950FC722B03 aadtextByte (hex) :486965722073746568656E20646965204141442D446174656E aadtextStringReceived :Hier stehen die AAD-Daten receivedMessageString Base64 :AAAnEJvYiQWg/ntD56b668ENjNmDNS/jvMVldAHE+9qhGi0GmA/91dqkFLiykfB3sdbP1VlCRSNoqxDFRXrBGlqdDcoMhn4VAeE11EV7qXdmxNJXiLCNePb1Or7x59cVieOF94/8aTFdPgkKB3aI9JqS/V/cToDymHQ03tDd7IEx96HbyCq0JihfqytO4bwuxoVZ2GUXZQvLdtGomcr7xR5kUKoCevrGvKR7hpldChswZE0MztfSTIAA651Wf37OzpqcJOjaQ6QSmBN2DjrcamxKUC1rfJSTtFGOzLzviIoo3MwJRPC3HXVCh9iom8idgOhV6ckqbKw+/j3Lie0yaEAS1W54sM3c080L1Tg88S10Ii24v+cLXKoYz3HGY6k7BjUpwLyr9Bjt8FJ5z259h9Ih6LgLDJi+Ng+DyVD8cisD gcmCompleteCiphertextByteR (hex) :000027109BD88905A0FE7B43E7A6FAEBC10D8CD983352FE3BCC5657401C4FBDAA11A2D06980FFDD5DAA414B8B291F077B1D6CFD55942452368AB10C5457AC11A5A9D0DCA0C867E1501E135D4457BA97766C4D25788B08D78F6F53ABEF1E7D71589E385F78FFC69315D3E090A077688F49A92FD5FDC4E80F2987434DED0DDEC8131F7A1DBC82AB426285FAB2B4EE1BC2EC68559D86517650BCB76D1A899CAFBC51E6450AA027AFAC6BCA47B86995D0A1B30644D0CCED7D24C8000EB9D567F7ECECE9A9C24E8DA43A4129813760E3ADC6A6C4A502D6B7C9493B4518ECCBCEF888A28DCCC0944F0B71D754287D8A89BC89D80E855E9C92A6CAC3EFE3DCB89ED32684012D56E78B0CDDCD3CD0BD5383CF12D74222DB8BFE70B5CAA18CF71C663A93B063529C0BCABF418EDF05279CF6E7D87D221E8B80B0C98BE360F83C950FC722B03 passwordSaltByte Received :9BD88905A0FE7B43E7A6FAEBC10D8CD983352FE3BCC5657401C4FBDAA11A2D06980FFDD5DAA414B8B291F077B1D6CFD55942452368AB10C5457AC11A5A9D0DCA0C867E1501E135D4457BA97766C4D25788B08D78F6F53ABEF1E7D71589E385F78FFC69315D3E090A077688F49A92FD5FDC4E80F2987434DED0DDEC8131F7A1DBC82AB426285FAB2B4EE1BC2EC68559D86517650BCB76D1A899CAFBC51E6450AA027AFAC6BCA47B86995D0A1B30644D0CCED7D24C8000EB9D567F7ECECE9A9C24E8DA43A4129813760E3ADC6A6C4A502D6B7C9493B4518ECCBCEF888A28DCCC0944F0B71D754287D8A89BC89D80E855E9C92A6CAC3EFE3DCB89ED32684012D56E passwordHashByteDecrypt : * * * Das Byte Array wurde gelöscht * * * gcmNonceByteReceived (hex) :78B0CDDCD3CD0BD5383CF12D ciphertextByteReceived (hex) :74222DB8BFE70B5CAA18CF71C663A93B063529C0BCABF418EDF05279CF6E7D87D221E8B80B0C98BE360F83C950FC722B03 = = = Entschlüsselung = = = decryptedtextByte (hex) :44696573657320697374206465722073757065722067656865696D652054657874 decryptedtextString :Dieses ist der super geheime Text |
Die AAD-Daten werden ebenfalls der GCM-internen Hash-Prüfroutine unterworfen. Wenn Ihr testweise die AAD-Daten auf dem Weg zum Empfänger ändert (z.B. in Zeile 162 den Kommentarvermerk entfernt) erhaltet Ihr diese Fehlermeldung:
1 2 3 4 5 6 7 8 9 10 |
gcmCompleteCiphertextString(B64):AAAnEKY8H4EY4AJhOp7d4r42l7AHV3lm/pSxLjDRiN5Gaij4BB7dxFDuMjB0yRBqYU9+KKv2z+vboGAfHQtkxffXQnuh/Fyhiy9kaXhAYYQfCyh/iWxd5IVn02YzsZgcJLxotrepY+c/W9g4JMMlPY6SCyjHhNXGGC1Mt+iPgZsSzUyTIBK952qzOLDDt62WU9Qfd8iguwpyKidrlCU6MTBQ7DWw+A92u/XRN9dNH8NGpyuEcANZzcI6CeyrQH4tjLe976kdibzTuaMWUbjj4KcY8KT5xqGQhUHF98894KljFE3bwOA+UlVcl/5p8wvcZUboLpaxU3eXULsPS1EaYJsQ+lLc3jMygM+Qk4Hhx2L4jfXGCsDYUAaCTeseRwP59OIvFnMW4jFv7effpO2H+epXwPFcGGKXF+VPM3ldLo7Z Exception in thread "main" javax.crypto.AEADBadTagException: Tag mismatch! at com.sun.crypto.provider.GaloisCounterMode.decryptFinal(GaloisCounterMode.java:578) at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1049) at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:985) at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847) at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446) at javax.crypto.Cipher.doFinal(Cipher.java:2164) at net.bplaced.javacrypto.symmetricencryption.B15_AesGcmNoPaddingRandomAadPbkdf2Base64String.AesGcmNoPaddingAadDecrypt(B15_AesGcmNoPaddingRandomAadPbkdf2Base64String.java:256) at net.bplaced.javacrypto.symmetricencryption.B15_AesGcmNoPaddingRandomAadPbkdf2Base64String.main(B15_AesGcmNoPaddingRandomAadPbkdf2Base64String.java:189) |
Alle Quellcodes zur symmetrischen Verschlüsselung findet Ihr zum Download in meinem Github-Repository, welches Ihr über diesen Link erreicht:
https://github.com/java-crypto/B-Symmetrische-Verschluesselung.
Die Lizenz zum obigen Beispiel findet Ihr auf der eigenen Lizenz-Seite.
Letzte Aktualisierung: 08.12.2018