Im nachfolgenden Beispiel zeige ich Euch, das die beste Verschlüsselung überlistet werden kann, wenn Ihr nicht zusätzliche Sicherungsmaßnahmen nutzt.
Ich arbeite in den beiden Programmen G02a und G02b mit exakt denselben Programmroutinen wie im Beispiel B09c AES MODUS CBC PKCS5PADDING ZUFALLS-INITVEKTOR DATEI INFILE-INITVECTOR, allerdings habe ich die Verschlüsselungsroutine in den Programmteil G02a und die Entschlüsselungsroutine in den Programmteil G02b geschoben, um die typische Situation „Der Absender verschlüsselt eine Nachricht“ (= G02a) und „Der Empfänger entschlüsselt diese Nachricht“ (=G02b) abzubilden. Sofern beide Programme hintereinander ausgeführt werden, wird die Demonstrationsdatei g02_test.txt zuerst in die Datei g02_test.enc verschlüsselt und durch das Programm G02b in die Datei g02_test.dec entschlüsselt.
Bis hierhin ist alles in Ordnung – aber was passiert wenn die verschlüsselte Datei g02_test.enc auf ihrem Weg zum Empfänger abgefangen und verändert wird ? In meinem Beispiel kennt der Mann in der Mitte (der böse „man in the middle“) den grundsätzlichen Aufbau der Mailnachricht, weil er vielleicht selber schon eine derartige Auftrags-Nachricht erhalten hat.
Wenn Ihr dieses simuliert und zuerst die verschlüsselte Nachricht erzeugt (G02a), dann die Veränderungsroutine („Tampering“) per G02c aufruft und am Ende dann schaut, welche Nachricht beim Empfänger entschlüsselt wird (G02b) dann ahnt Ihr, was am Ende passiert. Hier die Kurzversion – es entsteht ein Schaden in Höhe von 8.500 Euro:
Original Auftragstext: „Eilauftrag: 1000 EUR an das JavaCrypto-Konto ueberweisen.“
Verfälschter Auftragstext: „Eilauftrag: 9500 EUR an das JavaCrypto-Konto ueberweisen.“
Was ist das Besondere an diesem Angriff ? Wir greifen hier nicht die Verschlüsselung selber an (daher findet Ihr nirgendwo in G02c eine Ver- oder Entschlüsselungsroutine), sondern das CBC-Verfahren und den Initialisierungsvektor. Durch eine geschickte doppelte XOR-Kodierung wird erreicht, das die Entschlüsselung genau das Resultat erzeugt, was der Angreifer haben wollte. Die dafür notwendige Programmzeile findet in der Zeile 82 von G02c. Simpel, nicht wahr ?
Das Fazit aus diesem super einfachen Angriff ? Neben der Verschlüsselung ist es auch sehr wichtig, das die erhaltene Nachricht so auch Absender verschickt worden ist. Einige Lösungen findet Ihr im Kapitel F Nutzung von Hashes oder Ihr nutzt gleich einen Verschlüsselungsmodus, welcher diese Prüfung mit übernimmt. Die Beispiele B12 und höher arbeiten mit dem GCM-Modus und bieten genau diese zusätzliche Sicherheit.
Hier nun die Verschlüsselungsroutine:
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 |
package net.bplaced.javacrypto.unsecure; /* * 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): 18.11.2018 * Funktion: liest eine datei und verschlüsselt sie im aes cbc modus pkcs5 padding * speicherung des initvector in der verschluesselten datei * basiert auf B09c_AesCbcPkcs5PaddingRandomFileWithInitvector * Function: encrypts a file using aes cbc modus with pkcs5 padding * saves the initvector in the encrypted file * is based on B09c_AesCbcPkcs5PaddingRandomFileWithInitvector * * 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.DataOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Paths; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; public class G02a_AesCbcPkcs5PaddingRandomFileWithInitvector { public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, FileNotFoundException, IOException { System.out.println("G02a AES im Betriebsmodus CBC PKCS5Padding mit Zufalls-Initvektor mit einer Datei und Infile-Initvector - nur verschlüsseln"); // es werden ein paar variablen benötigt: String dateinameReadString = "g02_test.txt"; // aus der datei wird das plaintextByte eingelesen String dateinameWriteString = "g02_test.enc"; // in diese datei wird das ciphertextByte geschrieben String plaintextString = ""; // die daten werden aus der datei gelesen byte[] plaintextByte = null; // die daten werden aus der datei gelesen // zuerst testen wir ob die einzulesende datei existiert if (FileExistsCheck(dateinameReadString) == false) { System.out.println("Die Datei " + dateinameReadString + " existiert nicht. Das Programm wird beendet."); System.exit(0); }; // datei in byte array einlesen plaintextByte = readBytesFromFileNio(dateinameReadString); plaintextString = new String(plaintextByte, "UTF-8"); // die umwandlung erfolgt nur zur späteren anzeige // 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 = "1234567890123456".getBytes("UTF-8"); // 16 byte final byte[] keyByte = "12345678901234567890123456789012".getBytes("UTF-8"); // 32 byte // der initialisierungsvektor ist exakt 16 zeichen lang byte[] initvectorByte = new byte[16]; SecureRandom secureRandom = new SecureRandom(); secureRandom.nextBytes(initvectorByte); // 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 // 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 = AesCbcPaddingEncrypt(plaintextByte, keyByte, initvectorByte); // byte array in eine datei schreiben try (DataOutputStream out = new DataOutputStream(new FileOutputStream(dateinameWriteString))) { out.writeInt(initvectorByte.length); out.write(initvectorByte); out.writeInt(ciphertextByte.length); out.write(ciphertextByte); } System.out.println(""); System.out.println("Klartextdaten einlesen und als verschlüsselte Datei speichern"); System.out.println("keyByte (hex) :" + DatatypeConverter.printHexBinary(keyByte)); System.out.println("initvectorByte (hex) :" + DatatypeConverter.printHexBinary(initvectorByte)); System.out.println("Dateiname Lesen :" + dateinameReadString); System.out.println("Dateiname Schreiben :" + dateinameWriteString); System.out.println("plaintextByte (hex) :" + DatatypeConverter.printHexBinary(plaintextByte)); System.out.println("plaintextString :" + plaintextString); System.out.println("= = = Verschlüsselung = = ="); System.out.println("initvectorByte File (hex):" + DatatypeConverter.printHexBinary(initvectorByte)); System.out.println("ciphertextByte (hex) :" + DatatypeConverter.printHexBinary(ciphertextByte)); } public static byte[] AesCbcPaddingEncrypt(byte[] plaintextByte, byte[] keyByte, byte[] initvectorByte) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { byte[] ciphertextByte = null; // der schlüssel wird in die richtige form gebracht SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES"); // der initvector wird in die richtige form gebracht IvParameterSpec ivKeySpec = new IvParameterSpec(initvectorByte); // die verschlüsselungsroutine wird mit dem gewünschten parameter erstellt Cipher aesCipherEnc = Cipher.getInstance("AES/CBC/PKCS5PADDING"); // nun wird die routine mit dem schlüssel initialisiert aesCipherEnc.init(Cipher.ENCRYPT_MODE, keySpec, ivKeySpec); // hier erfolgt nun die verschlüsselung des plaintextes ciphertextByte = aesCipherEnc.doFinal(plaintextByte); return ciphertextByte; } private static boolean FileExistsCheck(String dateinameString) { return Files.exists(Paths.get(dateinameString), new LinkOption[] { LinkOption.NOFOLLOW_LINKS }); } private static byte[] readBytesFromFileNio(String filenameString) { byte[] byteFromFileByte = null; try { byteFromFileByte = Files.readAllBytes(Paths.get(filenameString)); } catch (IOException e) { e.printStackTrace(); } return byteFromFileByte; } } |
mit Ihrer Konsolenausgabe:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
G02a AES im Betriebsmodus CBC PKCS5Padding mit Zufalls-Initvektor mit einer Datei und Infile- Initvector - nur verschlüsseln Klartextdaten einlesen und als verschlüsselte Datei speichern keyByte (hex) :3132333435363738393031323334353637383930313233343536373839303132 initvectorByte (hex) :486E8B6BEDD1609C07CF71676069F440 Dateiname Lesen :g02_test.txt Dateiname Schreiben :g02_test.enc plaintextByte (hex) :45696C617566747261673A20313030302045555220616E20646173204A61766143727970746F2D4B6F6E746F20756562657 277656973656E2E0D0A5669656C6520477275657373650D0A4A6F6E2C2043454F plaintextString :Eilauftrag: 1000 EUR an das JavaCrypto-Konto ueberweisen. Viele Gruesse Jon, CEO = = = Verschlüsselung = = = initvectorByte File (hex):486E8B6BEDD1609C07CF71676069F440 ciphertextByte (hex) :0708535DE8F3574453B4241B6939B8C8C08A5890B036A60C89761E1A91ACED11A964FC968AC14A112E8A35656FC2E47A72D 06FCB67E7E44022B376477C17A6B9B4FAD6F3E7D3E224337FE9BC849453E4190A7A7417EF9CABFBB77C4E33D4B333 |
Das ist die reine Entschlüsselungsroutine:
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 |
package net.bplaced.javacrypto.unsecure; /* * 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): 18.11.2018 * Funktion: liest eine datei und verschlüsselt sie im aes cbc modus pkcs5 padding * speicherung des initvector in der verschluesselten datei * basiert auf B09c_AesCbcPkcs5PaddingRandomFileWithInitvector * Function: encrypts a file using aes cbc modus with pkcs5 padding * saves the initvector in the encrypted file * is based on B09c_AesCbcPkcs5PaddingRandomFileWithInitvector * * 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.DataInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; import java.security.InvalidAlgorithmParameterException; 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.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; public class G02b_AesCbcPkcs5PaddingRandomFileWithInitvector { public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, FileNotFoundException, IOException { System.out.println( "G02b AES im Betriebsmodus CBC PKCS5Padding mit Zufalls-Initvektor mit einer Datei und Infile-Initvector nur Entschlüsseln"); // es werden ein paar variablen benötigt: 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 = "1234567890123456".getBytes("UTF-8"); // 16 byte final byte[] keyByte = "12345678901234567890123456789012".getBytes("UTF-8"); // 32 byte // der initialisierungsvektor ist exakt 16 zeichen lang byte[] initvectorByte = new byte[16]; // 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 entschlüsselungsmodus // wir starten die entschlüsselung mit einem leeren ciphertext ciphertextByte = null; // ebenso ist der initvector leer - wird auch aus der datei gelesen initvectorByte = null; // byte array einlesen String dateinameReadString = "g02_test.enc"; // ciphertextByte lesen String dateinameWriteString = "g02_test.dec"; // decryptedtextByte schreiben // zuerst testen wir ob die einzulesende datei existiert if (FileExistsCheck(dateinameReadString) == false) { System.out.println("Die Datei " + dateinameReadString + " existiert nicht. Das Programm wird beendet."); System.exit(0); }; // das ciphertextByte wird aus der datei gelesen try (DataInputStream dataIn = new DataInputStream(new FileInputStream(dateinameReadString))) { int initvectorSize = dataIn.readInt(); initvectorByte = new byte[initvectorSize]; dataIn.read(initvectorByte, 0, initvectorSize); int ciphertextSize = dataIn.readInt(); ciphertextByte = new byte[ciphertextSize]; dataIn.read(ciphertextByte, 0, ciphertextSize); } // nun wird der ciphertext wieder entschlüsselt decryptedtextByte = AesCbcPaddingDecrypt(ciphertextByte, keyByte, initvectorByte); // wir schreiben die entschlüsselten daten in eine datei writeBytesToFileNio(decryptedtextByte, dateinameWriteString); // 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("Dateiname Lesen :" + dateinameReadString); System.out.println("Dateiname Schreiben :" + dateinameWriteString); System.out.println("= = = Verschlüsselung = = ="); System.out.println("initvectorByte File (hex):" + DatatypeConverter.printHexBinary(initvectorByte)); 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[] AesCbcPaddingEncrypt(byte[] plaintextByte, byte[] keyByte, byte[] initvectorByte) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { byte[] ciphertextByte = null; // der schlüssel wird in die richtige form gebracht SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES"); // der initvector wird in die richtige form gebracht IvParameterSpec ivKeySpec = new IvParameterSpec(initvectorByte); // die verschlüsselungsroutine wird mit dem gewünschten parameter erstellt Cipher aesCipherEnc = Cipher.getInstance("AES/CBC/PKCS5PADDING"); // nun wird die routine mit dem schlüssel initialisiert aesCipherEnc.init(Cipher.ENCRYPT_MODE, keySpec, ivKeySpec); // hier erfolgt nun die verschlüsselung des plaintextes ciphertextByte = aesCipherEnc.doFinal(plaintextByte); return ciphertextByte; } public static byte[] AesCbcPaddingDecrypt(byte[] ciphertextByte, byte[] keyByte, byte[] initvectorByte) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { byte[] decryptedtextByte = null; // der schlüssel wird in die richtige form gebracht SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES"); // der initvector wird in die richtige form gebracht IvParameterSpec ivKeySpec = new IvParameterSpec(initvectorByte); // die verschlüsselungsroutine wird mit dem gewünschten parameter erstellt Cipher aesCipherDec = Cipher.getInstance("AES/CBC/PKCS5PADDING"); // nun wird die routine mit dem schlüssel initialisiert aesCipherDec.init(Cipher.DECRYPT_MODE, keySpec, ivKeySpec); // hier erfolgt nun die verschlüsselung des plaintextes decryptedtextByte = aesCipherDec.doFinal(ciphertextByte); return decryptedtextByte; } private static boolean FileExistsCheck(String dateinameString) { return Files.exists(Paths.get(dateinameString), new LinkOption[] { LinkOption.NOFOLLOW_LINKS }); } private static void writeBytesToFileNio(byte[] byteToFileByte, String filenameString) { try { Path path = Paths.get(filenameString); Files.write(path, byteToFileByte); } catch (IOException e) { e.printStackTrace(); } } } |
Auch hier die Konsolenausgabe:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
G02b AES im Betriebsmodus CBC PKCS5Padding mit Zufalls-Initvektor mit einer Datei und Infile- Initvector nur Entschlüsseln keyByte (hex) :3132333435363738393031323334353637383930313233343536373839303132 Dateiname Lesen :g02_test.enc Dateiname Schreiben :g02_test.dec = = = Verschlüsselung = = = initvectorByte File (hex):72E3930B375C7EC873168AC798895BAC ciphertextByte (hex) :01DC89BEB537974D9991FA8A05AD747FD31D1772478D7BD5CF6D9992C15373957F47954D7A0CEDA4656E7AD7BC189D74922 9E190DEA33D0EE730A6D211B4425B727A794F5A547A71B297FFB13696B255AF64FFAE396582805CE40599F2438E2A = = = Entschlüsselung = = = decryptedtextByte (hex) :45696C617566747261673A20313030302045555220616E20646173204A61766143727970746F2D4B6F6E746F20756562657 277656973656E2E0D0A5669656C6520477275657373650D0A4A6F6E2C2043454F decryptedtextString :Eilauftrag: 1000 EUR an das JavaCrypto-Konto ueberweisen. Viele Gruesse Jon, CEO |
Nun die Veränderungsroutine (Tampering):
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 |
package net.bplaced.javacrypto.unsecure; /* * 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): 18.11.2018 * Funktion: liest eine datei und verschlüsselt sie im aes cbc modus pkcs5 padding * speicherung des initvector in der verschluesselten datei * Function: encrypts a file using aes cbc modus with pkcs5 padding * saves the initvector in the encrypted file * * 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.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Paths; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.xml.bind.DatatypeConverter; public class G02c_AesCbcPkcs5PaddingRandomFileWithInitvector { public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, FileNotFoundException, IOException { System.out.println("G02c Tampering"); // es werden ein paar variablen benötigt: String dateinameReadString = "g02_test.enc"; // aus der datei werden die originalen daten eingelesen String dateinameWriteString = "g02_test.enc"; // in diese datei werden die veränderten daten geschrieben // der initialisierungsvektor ist exakt 16 zeichen lang byte[] initvectorByte = new byte[16]; // 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 String plaintextGuessedString = "Eilauftrag: 1000"; // die geratenen ersten 16 zeichen der mail String tamperingtextString = "Eilauftrag: 9500"; // die geänderten ersten 16 zeichen der mail // zuerst testen wir ob die einzulesende datei existiert if (FileExistsCheck(dateinameReadString) == false) { System.out.println("Die Datei " + dateinameReadString + " existiert nicht. Das Programm wird beendet."); System.exit(0); }; // wir starten mit der einleseroutine der verschlüsselten daten byte[] initvectorOrgByte = new byte[16]; // zur sicherung des originalwertes // der initvectorByte und das ciphertextByte werden aus der datei gelesen try (DataInputStream dataIn = new DataInputStream(new FileInputStream(dateinameReadString))) { int initvectorSize = dataIn.readInt(); initvectorOrgByte = new byte[initvectorSize]; dataIn.read(initvectorOrgByte, 0, initvectorSize); int ciphertextSize = dataIn.readInt(); ciphertextByte = new byte[ciphertextSize]; dataIn.read(ciphertextByte, 0, ciphertextSize); } // hier erfolgt die veränderung im initvectorByte for (int i = 0; i < 16; i++) { initvectorByte[i] = (byte) (initvectorOrgByte[i] ^ tamperingtextString.getBytes("UTF-8")[i] ^ plaintextGuessedString.getBytes("UTF-8")[i]); } // der komplette datensatz wird zurückgeschrieben // byte array in eine datei schreiben try (DataOutputStream out = new DataOutputStream(new FileOutputStream(dateinameWriteString))) { out.writeInt(initvectorByte.length); out.write(initvectorByte); out.writeInt(ciphertextByte.length); out.write(ciphertextByte); } System.out.println(""); System.out.println("Verschlüsselte Datei einlesen und nach Tampering als verschlüsselte Datei speichern"); System.out.println("Dateiname Lesen :" + dateinameReadString); System.out.println("Dateiname Schreiben :" + dateinameWriteString); System.out.println("plaintextGuessedString :" + plaintextGuessedString); System.out.println("tamperingtextString :" + tamperingtextString); System.out.println("initvectorOrgByte (hex) :" + DatatypeConverter.printHexBinary(initvectorOrgByte)); System.out.println("initvectorByte File (hex):" + DatatypeConverter.printHexBinary(initvectorByte)); System.out.println("ciphertextByte (hex) :" + DatatypeConverter.printHexBinary(ciphertextByte)); } private static boolean FileExistsCheck(String dateinameString) { return Files.exists(Paths.get(dateinameString), new LinkOption[] { LinkOption.NOFOLLOW_LINKS }); } } |
Die Konsole zeigt lapidar:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
G02c Tampering Verschlüsselte Datei einlesen und nach Tampering als verschlüsselte Datei speichern Dateiname Lesen :g02_test.enc Dateiname Schreiben :g02_test.enc plaintextGuessedString :Eilauftrag: 1000 tamperingtextString :Eilauftrag: 9500 initvectorOrgByte (hex) :72E3930B375C7EC873168AC798895BAC initvectorByte File (hex):72E3930B375C7EC873168AC7908C5BAC ciphertextByte (hex) :01DC89BEB537974D9991FA8A05AD747FD31D1772478D7BD5CF6D9992C15373957F47954D7A0CEDA4656E7AD7BC189D74922 9E190DEA33D0EE730A6D211B4425B727A794F5A547A71B297FFB13696B255AF64FFAE396582805CE40599F2438E2A |
Nun rufen wir noch einmal das Programm G02b auf und schauen dann in die Konsolenausgabe:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
G02b AES im Betriebsmodus CBC PKCS5Padding mit Zufalls-Initvektor mit einer Datei und Infile- Initvector nur Entschlüsseln keyByte (hex) :3132333435363738393031323334353637383930313233343536373839303132 Dateiname Lesen :g02_test.enc Dateiname Schreiben :g02_test.dec = = = Verschlüsselung = = = initvectorByte File (hex):72E3930B375C7EC873168AC7908C5BAC ciphertextByte (hex) :01DC89BEB537974D9991FA8A05AD747FD31D1772478D7BD5CF6D9992C15373957F47954D7A0CEDA4656E7AD7BC189D74922 9E190DEA33D0EE730A6D211B4425B727A794F5A547A71B297FFB13696B255AF64FFAE396582805CE40599F2438E2A = = = Entschlüsselung = = = decryptedtextByte (hex) :45696C617566747261673A20393530302045555220616E20646173204A61766143727970746F2D4B6F6E746F20756562657 277656973656E2E0D0A5669656C6520477275657373650D0A4A6F6E2C2043454F decryptedtextString :Eilauftrag: 9500 EUR an das JavaCrypto-Konto ueberweisen. Viele Gruesse Jon, CEO |
Alle Quellcodes zu den Unsicherheiten findet Ihr zum Download in meinem Github-Repository, welches Ihr über diesen Link erreicht: https://github.com/java-crypto/G-Unsicherheit. Alle Programme sind sowohl unter Java 8 als auch unter Java 11 lauffähig.
Die Lizenz zum obigen Beispiel findet Ihr auf der eigenen Lizenz-Seite.
Letzte Aktualisierung: 13.01.2019