Wenn Ihr beim vorherigen Beispiel mit dem plaintext gespielt und beispielsweise einen plaintext mit 15 Zeichen Länge genutzt habt, erhieltet Ihr eine heftige Fehlermeldung („Exception in thread „main“ javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes“). Das bedeutet im Klartext, das der plaintext immer ein Vielfaches von 16 Zeichen (das ist die Blocklänge) lang sein muß, was nur selten der Fall ist.
Um diese Vorgabe zu erfüllen könntet Ihr beispielsweise den plaintext am Ende mit Leerzeichen auffüllen, um einen plaintext mit einem Vielfachen von 16 zu erzeugen. Das könnte bei der Entschlüsselung aber zu Problemen führen, wenn auch die Leerzeichen am Ende der Nachricht eine Bedeutung haben.
Für diese Fälle wurde ein Padding-Verfahren („auffüllen“) in den Algorithmus eingebaut, der automatisch den plaintext auffüllt und bei der Entschlüsselung das Padding auch wieder entfernt. Ein Erläuterung dazu ist in der Wikipedia zu finden.
Hier der Steckbrief:
Verschlüsselungssteckbrief | |
Name des Verfahrens | AES/ECB/PKCS5PADDING |
Langname | ECB Electronic Code Book |
Art der Chiffre | Blockchiffre |
Blocklänge (Byte) | 16 |
Schlüssellänge (Byte/Bit) | 16/128, 24/192, 32/256 |
Padding genutzt | Ja |
Sicherheit | nur bei kleinen Datenmengen |
Besonderes | Nein |
Das nachfolgende Programm ist nahezu identisch mit dem Programm B03_AesEcbNopaddingString.java, allerdings wurde inZeile 44 der Name der Variablen inklusive des Textes angepaßt und der plaintext in Zeile 38 ist 15 Zeichen lang.
Auch hier gilt die nachfolgende Sicherheitswarnung und die Erläuterung ist identisch zum Beispiel B03.
Bitte die nachfolgende Routine nicht für den Echteinsatz nutzen, da sie aus kryptographischer Sicht sehr angreifbar ist ! Eine optische Erläuterung für meine Einschätzung findet Ihr in der Rubrik Unsicherheit unter G01 ECB Pinguin.
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 |
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): 01.11.2018 * Funktion: verschlüsselt einen string im aes ecb modus pkcs5 padding * Function: encrypts a string using aes ecb modus with pkcs5 padding * * 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.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; public class B04_AesEcbPkcs5PaddingString { public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { System.out.println("B04 AES im Betriebsmodus ECB PKCS5Padding mit einem String"); // es werden ein paar variablen benötigt: String plaintextString = "HalloWelt012345"; // hier 15 zeichen 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 // hier ist der schlüssel 32 byte = 256 bit lang // mögliche schlüssellängen sind 16 byte (128 bit), 24 byte (192 bit) und 32 // byte (256 bit) // final byte[] keyByte = "1234567890123456".getBytes("UTF-8"); // 16 byte final byte[] keyByte = "12345678901234567890123456789012".getBytes("UTF-8"); // 32 byte byte[] plaintextByte = null; // 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"); // der schlüssel wird in die richtige form gebracht SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES"); // die verschlüsselungsroutine wird mit dem gewünschten parameter erstellt Cipher aesCipherEnc = Cipher.getInstance("AES/ECB/PKCS5PADDING"); // nun wird die routine mit dem schlüssel initialisiert aesCipherEnc.init(Cipher.ENCRYPT_MODE, keySpec); // hier erfolgt nun die verschlüsselung des plaintextes ciphertextByte = aesCipherEnc.doFinal(plaintextByte); // ab hier arbeiten wir nun im entschlüsselungsmodus // die verschlüsselungsroutine wird mit dem gewünschten parameter erstellt Cipher aesCipherDec = Cipher.getInstance("AES/ECB/PKCS5PADDING"); // zum einsatz kommt derselbe schlüssel, daher symmetrische verschlüsselung // achtung: hier wird der DECRYPT_MODE = entschlüsselung genutzt aesCipherDec.init(Cipher.DECRYPT_MODE, keySpec); // nun wird der ciphertext wieder entschlüsselt decryptedtextByte = aesCipherDec.doFinal(ciphertextByte); // zurück-kodierung des byte array in text decryptedtextString = new String(decryptedtextByte, "UTF-8"); // ausgabe der variablen System.out.println(""); System.out.println("keyByte (hex) :" + DatatypeConverter.printHexBinary(keyByte)); System.out.println("plaintextString :" + plaintextString); System.out.println("plaintextByte (hex) :" + DatatypeConverter.printHexBinary(plaintextByte)); System.out.println("= = = Verschlüsselung = = ="); System.out.println("ciphertextByte (hex) :" + DatatypeConverter.printHexBinary(ciphertextByte)); System.out.println("= = = Entschlüsselung = = ="); System.out.println("decryptedtextByte (hex):" + DatatypeConverter.printHexBinary(decryptedtextByte)); System.out.println("decryptedtextString :" + decryptedtextString); } } |
Auf der Konsole ist dieses Ergebnis zu sehen – „trotz“ einem 15 Zeichen langen plaintext ver- und entschlüsselt das Programm einwandfrei:
1 2 3 4 5 6 7 8 9 10 |
B04 AES im Betriebsmodus ECB PKCS5Padding mit einem String keyByte (hex) :3132333435363738393031323334353637383930313233343536373839303132 plaintextString :HalloWelt012345 plaintextByte (hex) :48616C6C6F57656C74303132333435 = = = Verschlüsselung = = = ciphertextByte (hex) :9118C368A3DC8ADFC5C23569E5B14672 = = = Entschlüsselung = = = decryptedtextByte (hex):48616C6C6F57656C74303132333435 decryptedtextString :HalloWelt012345 |
Damit Ihr die Verschlüsselungs- bzw. Entschlüsselungsroutinen in Euren eigenen Programmen einfach nutzen könnt habe ich den Verschlüsselungs-/Entschlüsselungs-Programmteil in eigene Methoden ausgelagert – die eigentliche Programmfunktionalität bleibt unverändert.
Bitte die nachfolgende Routine nicht für den Echteinsatz nutzen, da sie aus kryptographischer Sicht sehr angreifbar ist !
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 |
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): 01.11.2018 * Funktion: verschlüsselt einen string im aes ecb modus pkcs5 padding * Function: encrypts a string using aes ecb modus with pkcs5 padding * * 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.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; public class B04b_AesEcbPkcs5PaddingString { public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { System.out.println("B04b AES im Betriebsmodus ECB PKCS5Padding mit einem String"); // es werden ein paar variablen benötigt: String plaintextString = "HalloWelt012345"; // hier 15 zeichen 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 // hier ist der schlüssel 32 byte = 256 bit lang // mögliche schlüssellängen sind 16 byte (128 bit), 24 byte (192 bit) und 32 // byte (256 bit) // final byte[] keyByte = "1234567890123456".getBytes("UTF-8"); // 16 byte final byte[] keyByte = "12345678901234567890123456789012".getBytes("UTF-8"); // 32 byte byte[] plaintextByte = null; // 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"); ciphertextByte = AesEcbPaddingEncrypt(plaintextByte, keyByte); // ab hier arbeiten wir nun im entschlüsselungsmodus decryptedtextByte = AesEcbPaddingDecrypt(ciphertextByte, keyByte); // zurück-kodierung des byte array in text decryptedtextString = new String(decryptedtextByte, "UTF-8"); // ausgabe der variablen System.out.println(""); System.out.println("keyByte (hex) :" + DatatypeConverter.printHexBinary(keyByte)); System.out.println("plaintextString :" + plaintextString); System.out.println("plaintextByte (hex) :" + DatatypeConverter.printHexBinary(plaintextByte)); System.out.println("= = = Verschlüsselung = = ="); System.out.println("ciphertextByte (hex) :" + DatatypeConverter.printHexBinary(ciphertextByte)); System.out.println("= = = Entschlüsselung = = ="); System.out.println("decryptedtextByte (hex):" + DatatypeConverter.printHexBinary(decryptedtextByte)); System.out.println("decryptedtextString :" + decryptedtextString); } public static byte[] AesEcbPaddingEncrypt(byte[] plaintextByte, byte[] keyByte) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { byte[] ciphertextByte = null; // der schlüssel wird in die richtige form gebracht SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES"); // die verschlüsselungsroutine wird mit dem gewünschten parameter erstellt Cipher aesCipherEnc = Cipher.getInstance("AES/ECB/PKCS5PADDING"); // nun wird die routine mit dem schlüssel initialisiert aesCipherEnc.init(Cipher.ENCRYPT_MODE, keySpec); // hier erfolgt nun die verschlüsselung des plaintextes ciphertextByte = aesCipherEnc.doFinal(plaintextByte); return ciphertextByte; } public static byte[] AesEcbPaddingDecrypt(byte[] ciphertextByte, byte[] keyByte) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { byte[] decryptedtextByte = null; // der schlüssel wird in die richtige form gebracht SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES"); // die verschlüsselungsroutine wird mit dem gewünschten parameter erstellt Cipher aesCipherDec = Cipher.getInstance("AES/ECB/PKCS5PADDING"); // nun wird die routine mit dem schlüssel initialisiert aesCipherDec.init(Cipher.DECRYPT_MODE, keySpec); // hier erfolgt nun die verschlüsselung des plaintextes decryptedtextByte = aesCipherDec.doFinal(ciphertextByte); return decryptedtextByte; } } |
Die Lizenz zum obigen Beispiel findet Ihr auf der eigenen Lizenz-Seite.
Letzte Aktualisierung: 18.11.2018