Dieses Beispiel bringt Euch einen Sonderfall im Bereich der Kryptographie näher, nämlich die „Hash-based Key Deriving Function“ oder auf Deutsch: die Hash-basierte Ableitung von Schlüsseln, abgekürzt mit „HKDF“.
Die HKDF hat 2 Einsatzgebiete: zum einen kann ich aus einem vorhandenen Schlüssel mehrere Schlüssel ableiten, z.B. einen für die Verschlüsselung und einen anderen für die Nutzung eines HMACs.
Das zweite Einsatzgebiet besteht in der Erhöhung der Entropie bei „schlechten Passwörtern“. Die Entropie ist für mich schwer zu beschreiben, ich versuche es daher mit einem Beispiel: kann ich ein 8-stelliges Passwort nur über eine 10-Ziffern-Tastatur eingeben, „verschenke“ ich eine Menge Sicherheit, da jedes meiner 8 Zeichen nur 10 Zustände einnehmen kann (oder mathematisch gesehen 8 hoch 10 = 1.073.741.824 möglicher Passwörter) – eine geringe oder schlechte Entropie. Durch die HKDF-Funktion leite ich ein aus einem Passwort mit schlechter Entropie ein Passwort mit hoher Entropie ab – maximal möglich wären 8 hoch 256 möglicher Passwörter (= 1.552518e+231 Zustände).
Das nachfolgende Beispiel zeigt Euch die sehr einfache Implementierung einer HKDF-Methode, nur hat Java 8 leider keine HKDF-Funktion eingebaut. Im Netz existiert eine sehr gute Java-Bibliothek, welche die HKDF-Funktion bereitstellt. Das komplette Java-Archiv ist in diesem Github-Depot vorhanden: https://github.com/patrickfav/hkdf, ich empfehle Euch zur einfachen Nutzung den Download der fertigen JAR-Datei aus dem zentralen Maven-Verzeichnis: https://mvnrepository.com/artifact/at.favre.lib/hkdf [dort klickt Ihr die neueste Version und auf der Folgeseite findet Ihr in der Mitte den anklickbaren Link zur (recht kleinen) jar-Datei (http://central.maven.org/maven2/at/favre/lib/hkdf/1.0.1/hkdf-1.0.1.jar)].
Files | jar (11 KB) |
---|
Bindet diese Datei analog zu BouncyCastle (siehe A06 Einbindung und Nutzung von Bouncy Castle) in Eclipse ein und das Beispiel funktioniert. Bitte beachtet, dass die Nutzung der Bibliothek unter der Apache 2-Lizenz möglich ist.
Die HKDF-Routine benötigt ein „Salt Byte“, das auch statisch gewählt werden kann. Ich habe mich in diesem Beispiel für ein 32 Byte Array komplett mit Hex00 gefüllt entschieden.
Hier nun der Quellcode:
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 |
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: leitet 2 Passwörter mittels HKDF256 ab * Function: derives 2 passwords using HKDF256 * * 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 ! * * Das Programm benötigt die nachfolgende Bibliothek: * The programm uses this external library: * source code: https://github.com/patrickfav/hkdf * jar-Datei: https://mvnrepository.com/artifact/at.favre.lib/hkdf * */ import java.nio.charset.StandardCharsets; import at.favre.lib.crypto.HKDF; public class F06_Hkdf256ByteArray { public static void main(String[] args) throws Exception { System.out.println("F06 HKDF-256 mit einem Byte Array"); String passwordString = "wenig Entropie"; byte[] passwordByte = passwordString.getBytes("utf-8"); System.out.println("\npasswordByte Länge:" + passwordByte.length + " Data:" + printHexBinary(passwordByte)); byte[] saltByte = new byte[32]; String usageString = "aes-cbc"; byte[] hkdfByte = generateHkdf256(passwordByte, usageString, saltByte, 16); System.out.println("\nHKDF-256-Wert für die Anwendung:" + usageString); System.out.println("HKDFByte Länge:" + hkdfByte.length + " Data:" + printHexBinary(hkdfByte)); usageString = "hmac"; hkdfByte = generateHkdf256(passwordByte, usageString, saltByte, 16); System.out.println("\nHKDF-256-Wert für die Anwendung:" + usageString); System.out.println("HKDFByte Länge:" + hkdfByte.length + " Data:" + printHexBinary(hkdfByte)); System.out.println("\nF06 HKDF-256 mit einem Byte Array beendet"); } public static byte[] generateHkdf256(byte[] rawPasswordByte, String usageString, byte[] staticSaltByte, int outputLengthInt) { HKDF hkdf = HKDF.fromHmacSha256(); // .fromHmacSha256 oder .fromHmacSha512 // extract the "raw" data to create output with concentrated entropy byte[] pseudoRandomKey = hkdf.extract(staticSaltByte, rawPasswordByte); // create expanded bytes for e.g. AES secret key and IV return hkdf.expand(pseudoRandomKey, usageString.getBytes(StandardCharsets.UTF_8), outputLengthInt); } 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); } } |
Das findet Ihr anschließend in der Konsole:
1 2 3 4 5 6 7 8 9 10 11 |
F06 HKDF-256 mit einem Byte Array passwordByte Länge:14 Data:77656E696720456E74726F706965 HKDF-256-Wert für die Anwendung:aes-cbc HKDFByte Länge:16 Data:0F1FCE524EF07A143018CCDD9E13102A HKDF-256-Wert für die Anwendung:hmac HKDFByte Länge:16 Data:B6EA351AAB923EEB4185DFA15C8315DB F06 HKDF-256 mit einem Byte Array 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