Wir bewegen uns nun weg von der Errechnung von Prüfsummen (Hashes) hin zu Hash-basierten Message Authentication Codes (HMACs) oder auf deutsch: Nachrichtenauthentifizierungscodes mit Prüfsummen. Wenn wir uns die Ausgabe anschauen ist das Ergebnis – wie bei den SHA-Routinen – ein 32- bzw. 64-Byte langer Wert, der wie eine Prüfsumme aussieht. Das Ergebnis ist einmalig für die verwendete Datei und damit auch eine Prüfsumme, aber… wir benötigen zusätzlich einen Schlüssel (im Beispiel hmacKeyByte) für die Errechnung der Prüfsumme.
Wenn dieser Schlüssel nur dem Absender und dem Empfänger der Nachricht bekannt ist, kann damit nicht nur die Integrität der Datei (d.h. die Datei ist unverändert) gewährleistet und überprüft werden. Zusätzlich ist auch sichergestellt, das die Nachricht vom Absender stammt (Authentizität), da nur der Absender und der Empfänger den geheimen Schlüssel kennen. Noch ein wichtiger Hinweis: bitte für den HMAC-Schlüssel nicht den Schlüssel verwenden, der auch für die eigentliche Verschlüsselung genutzt wird.
Hier nun der Programmcode:
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 |
package net.bplaced.javacrypto.hashandmac; /* * 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): 21.01.2019 * Funktion: errechnet den HMAC256 und HMAC512-Wert einer Datei * Function: calculates the HMAC256 and HMAC512 value of a 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.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; public class F05_HmacFile { public static void main(String[] args) throws Exception { System.out.println("F05 HMAC 256 & 512 mit einer Datei"); String filenameString = "a11_test_1mb.dat"; byte[] hmacKeyByte = "1234567890".getBytes("utf-8"); byte[] hmacByte = generateHmac256(filenameString, hmacKeyByte); System.out.println("\nHMAC256-Wert der Datei:" + filenameString); System.out.println( "hmacByte Länge:" + hmacByte.length + " Data:" + printHexBinary(hmacByte)); hmacByte = generateHmac512(filenameString, hmacKeyByte); System.out.println("\nHMAC512-Wert der Datei:" + filenameString); System.out.println( "hmacByte Länge:" + hmacByte.length + " Data:" + printHexBinary(hmacByte)); System.out.println("\nF05 HMAC 256 & 512 mit einer Datei beendet"); } public static byte[] generateHmac256(String filenameString, byte[] keyByte) throws IOException, NoSuchAlgorithmException, InvalidKeyException { byte[] resultMacByte = null; File file = new File(filenameString); BufferedInputStream is = new BufferedInputStream(new FileInputStream(file)); Mac mac = Mac.getInstance("HmacSHA256"); // HmacSHA512 SecretKeySpec keySpec = new SecretKeySpec(keyByte, "HmacSHA256"); // HmacSHA512 mac.init(keySpec); byte[] content = new byte[1024]; int readSize; while ((readSize = is.read(content)) != -1) { mac.update(content, 0, readSize); } resultMacByte = mac.doFinal(); is.close(); return resultMacByte; } public static byte[] generateHmac512(String filenameString, byte[] keyByte) throws IOException, NoSuchAlgorithmException, InvalidKeyException { byte[] resultMacByte = null; File file = new File(filenameString); BufferedInputStream is = new BufferedInputStream(new FileInputStream(file)); Mac mac = Mac.getInstance("HmacSHA512"); // HmacSHA256 SecretKeySpec keySpec = new SecretKeySpec(keyByte, "HmacSHA512"); // HmacSHA256 mac.init(keySpec); byte[] content = new byte[1024]; int readSize; while ((readSize = is.read(content)) != -1) { mac.update(content, 0, readSize); } resultMacByte = mac.doFinal(); is.close(); return resultMacByte; } 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); } } |
Hier das Ergebnis auf der Konsole:
1 2 3 4 5 6 7 8 9 |
F05 HMAC 256 & 512 mit einer Datei HMAC256-Wert der Datei:a11_test_1mb.dat hmacByte Länge:32 Data:5C453797E48978DDDC9F140C10D228989F0E8AFDEB2CA8DCAA2527106EB296EB HMAC512-Wert der Datei:a11_test_1mb.dat hmacByte Länge:64 Data:2D6E0F3A8332908A802CCF46EFD738B29B9A6F7335EC32FD85730537146F8AE22C7FD063DB4D6583E487A6CF5FE7B578E855BDBCC4823A7CF575AAECAB12E4FD F05 HMAC 256 & 512 mit einer Datei beendet |
Alle Quellcodes zu Hashes und MACs findet Ihr zum Download in meinem Github-Repository, welches Ihr über diesen Link erreicht: https://github.com/java-crypto/F-Hashes-und-MACs. 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: 21.01.2019