Auf dieser Seite zeige ich Euch (hoffentlich) sehr eindrucksvoll, was es mit einer „Kollision“ bei der unsicheren Hashroutine MD5 auf sich hat. Im Ergebnis dürft Ihr Euch bei der Nutzung von fremden Ressourcen (z.B. einem heruntergeladenen Programm oder einer PDF-Datei) niemals auf den MD5-Hashwert verlassen, denn er kann so geschickt manipuliert sein das Ihr eine andere (vielleicht bösartige) Datei untergeschoben bekommt.
In unserem ersten Beispiel ladet Ihr Euch die beiden Dateien g07a_hello.exe und g07a_erase.exe herunter. Beide Dateien sind harmlos, geben aber ganz andere Informationen aus:
g07a_hello.exe:
g07a_erase.exe:
Nun starten wir unsere MD5-Berechnung und als Vergleich dazu die Berechnung des SHA-256-Hashwertes. Es handelt sich um die zusammengeführten Programme F01 MD5 Hash von einer Datei und F03 SHA-256 und SHA-512 Hash von einer Datei und im Ergebnis zeigen sie eindrucksvoll, das die MD5-Hashwerte für beide Dateien identisch sind (Zeile 8), aber die SHA-256-Hashwerte nicht gleich sind (Zeile 16). Ich zeige hier zuerst das erschreckende Konsolenergebnis und dann später dann den Quellcode:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
G07a MD5 Kollision = Unsicherheit Hinweis: nutzen Sie die MD5-Funktion niemals in Echtprogrammen da sie unsicher ist ! MD5-Hashwert der Datei: g07a_hello.exe hash1Byte Länge:16 Data:CDC47D670159EEF60916CA03A9D4A007 MD5-Hashwert der Datei: g07a_erase.exe hash2Byte Länge:16 Data:CDC47D670159EEF60916CA03A9D4A007 Die beiden MD5-Hashwerte sind gleich:true Alternative Berechnung eines SHA-256-Hashwertes SHA256-Hashwert der Datei:g07a_hello.exe hash1Byte Länge:32 Data:60D13913155644883F130B85EB24D778314014C9479AEDB5F6323BF38AD3A451 SHA256-Hashwert der Datei:g07a_erase.exe hash2Byte Länge:32 Data:1316543942A8C6CD754855500CD37068EDBBD8B31C4979D2825A4E799FED6102 Die beiden SHA256-Hashwerte sind gleich:false G07a MD5 Kollision = Unsicherheit beendet |
Beide Demoprogramme wurden nicht von mir erstellt, sondern von Peter Selinger, der auf seiner Webseite http://cryptography.hyperlink.cz/2004/collisions.htm weitere Erläuterungen und auch ein Programm bereithält, mit dem eine solche Kollision mutwillig erzeugt werden kann.
Das zweite Beispiel zeigt Euch anhand von 2 unterschiedlichen Bildern, das auch dort durch geschickte Manipulation der gleiche MD5-Hashwert erzeugt wird. Ladet Euch die beiden Bilder
g07b_plane.jpg und g07b_ship.jpg herunter und lasst Sie durch das MD5-Haspprogramm laufen.
Die hier gezeigten Bilder sind verkleinerte Versionen und damit funktioniert das Beispiel nicht.
g07b_plane.jpg:
g07b_ship.jpg:
Auch hier ist die Konsolenausgabe eindeutig: gleicher MD5-Hashwert, unterschiedlicher SHA-256-Hashwert:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
G07b MD5 Kollision = Unsicherheit Hinweis: nutzen Sie die MD5-Funktion niemals in Echtprogrammen da sie unsicher ist ! MD5-Hashwert der Datei: g07b_plane.jpg hash1Byte Länge:16 Data:253DD04E87492E4FC3471DE5E776BC3D MD5-Hashwert der Datei: g07b_ship.jpg hash2Byte Länge:16 Data:253DD04E87492E4FC3471DE5E776BC3D Die beiden MD5-Hashwerte sind gleich:true Alternative Berechnung eines SHA-256-Hashwertes SHA256-Hashwert der Datei:g07b_plane.jpg hash1Byte Länge:32 Data:91E34644AF1E6C36166E1A69D915D8ED5DBB43FFD62435E70059BC76A742DAA6 SHA256-Hashwert der Datei:g07b_ship.jpg hash2Byte Länge:32 Data:CAF110E4AEBE1FE7ACEF6DA946A2BAC9D51EDCD47A987E311599C7C1C92E3ABD Die beiden SHA256-Hashwerte sind gleich:false G07b MD5 Kollision = Unsicherheit beendet |
Die beiden Bilder habe nicht ich sondern Nat McHugh erstellt; Einzelheiten findet ihr auf seiner Webseite https://natmchugh.blogspot.com/2015/02/create-your-own-md5-collisions.html.
Den Quellcode für beide Beispiele (unterscheiden sich nur durch die Dateinamen der einzulesenden Dateien) findet Ihr im Github-Archiv, hier nur der Quellcode des ersten Beispiels:
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.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 * getestet mit/tested with: Java Runtime Environment 11.0.1 x64 * Datum/Date (dd.mm.jjjj): 08.12.2019 * Funktion: errechnet die MD5-Hashwerte zweier Dateien * Function: calculates the MD5-hashes of two files * * 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.File; import java.io.FileInputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; public class G07a_Md5Kollision { public static void main(String[] args) throws Exception { System.out.println("G07a MD5 Kollision = Unsicherheit"); System.out.println("Hinweis: nutzen Sie die MD5-Funktion niemals in Echtprogrammen da sie unsicher ist !"); String filename1String = "g07a_hello.exe"; byte[] hash1Byte = generateMd5DoNotUse(filename1String); System.out.println("\nMD5-Hashwert der Datei: " + filename1String); System.out.println( "hash1Byte Länge:" + hash1Byte.length + " Data:" + printHexBinary(hash1Byte)); String filename2String = "g07a_erase.exe"; byte[] hash2Byte = generateMd5DoNotUse(filename2String); System.out.println("MD5-Hashwert der Datei: " + filename2String); System.out.println( "hash2Byte Länge:" + hash2Byte.length + " Data:" + printHexBinary(hash2Byte)); System.out.println("Die beiden MD5-Hashwerte sind gleich:" + Arrays.equals(hash1Byte, hash2Byte)); System.out.println("\nAlternative Berechnung eines SHA-256-Hashwertes"); hash1Byte = generateSha256(filename1String); System.out.println("\nSHA256-Hashwert der Datei:" + filename1String); System.out.println( "hash1Byte Länge:" + hash1Byte.length + " Data:" + printHexBinary(hash1Byte)); hash2Byte = generateSha256(filename2String); System.out.println("SHA256-Hashwert der Datei:" + filename2String); System.out.println( "hash2Byte Länge:" + hash2Byte.length + " Data:" + printHexBinary(hash2Byte)); System.out.println("Die beiden SHA256-Hashwerte sind gleich:" + Arrays.equals(hash1Byte, hash2Byte)); System.out.println("\nG07a MD5 Kollision = Unsicherheit beendet"); } public static byte[] generateMd5DoNotUse(String filenameString) throws IOException, NoSuchAlgorithmException { // bitte diese hashfunktion niemals in echtprogrammen nutzen // die hashfunktion ist unsicher // do not use this hashroutine in production // the hashroutine is unsecure File file = new File(filenameString); byte[] bufferByte = new byte[(int) file.length()]; FileInputStream fis = new FileInputStream(file); fis.read(bufferByte); fis.close(); MessageDigest md = MessageDigest.getInstance("MD5"); md.update(bufferByte); return md.digest(); } public static byte[] generateSha256(String filenameString) throws IOException, NoSuchAlgorithmException { File file = new File(filenameString); byte[] bufferByte = new byte[(int) file.length()]; FileInputStream fis = new FileInputStream(file); fis.read(bufferByte); fis.close(); MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(bufferByte); return md.digest(); } public static String printHexBinary(byte[] bytes) { final char[] hexArray = "0123456789ABCDEF".toCharArray(); char[] hexChars = new char[bytes.length * 2]; for (int j = 0; j < bytes.length; j++) { int v = bytes[j] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } return new String(hexChars); } } |
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: 08.12.2019