Der ECDH Schlüsselaustausch basiert auf dem Diffie-Hellmann Schlüsselaustausch und wurde um die elliptische Kurven-Kryptographie erweitert. Auch dieser Algorithmus ist mit wenigen Zeilen Programmcode nutzbar und ist ein vollwertiger Schlüsselaustausch-Code. Auch hier gilt wieder: „glaubst Du den Machern der Kurve“? Falls nicht biete ich Euch im Beispiel E04 EC Kurve25519 Schlüsselaustausch Signatur eine alternative Kurve zur Nutzung an.
Hier noch einmal in Kurzform die Vorgehensweise: beide Partner erzeugen ihre Schlüsselpaare (KeyPairs) und tauschen dann ihre öffentlichen Schlüssel (public keys) aus. Im Programm geschieht das einfach durch „Vertauschen“ in der Ansicht, in der Praxis werden die öffentlichen Schlüssel z.B. auf einer persönlichen Webseite veröffentlicht. Dann erzeugen beide Partner den gemeinsamen geheimen Schlüssel (shared secret key), der dann z.B. für eine symmetrische Verschlüsselung genutzt werden kann. In diesem Beispiel ist der gemeinsame geheime Schlüssel zwar 32 Byte lang und damit „OK“ für AES-Verschlüsselungen, aber bei der Nutzung einer „längeren“ Kurve entstehen wieder „zu lange“ Schlüssel – diese werden mittels SHA-256-Hashfunktion auf die Länge von 32 Byte gebracht; alternativ wäre auch die Nutzung von HKDF (Kryptografische Erzeugung von abgeleiteten Schlüsseln) denkbar.
Schlüsselaustauschsteckbrief | |
Name des Verfahrens | ECDH |
Langname | Elliptische Kurven mit Diffie-Hellmann Schlüsselaustausch |
Basis | Elliptische Kurven kombiniert mit dem diskreten Logarithmus |
Blocklänge (Byte) | – |
Schlüssellänge (Byte/Bit) | 256/2048, 384/3072, 521/4168 |
Padding genutzt | Nein |
Sicherheit | ab 2048 Bit Schlüssellänge |
Besonderes | – |
Der nachfolgende Quellcode ist durch die Ausgaberoutinen deutlich länger als der „eigentliche“ Programmcode.
Bitte die nachfolgende Routine nicht für den Echteinsatz nutzen, da sie aus kryptographischer Sicht 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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
package net.bplaced.javacrypto.keyexchange; /* * 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): 14.01.2019 * Funktion: elektronischer Schlüsselaustausch mittels ECDH * Function: digital key exchange using ECDH * * 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.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.ECGenParameterSpec; import javax.crypto.KeyAgreement; public class E02_EcdhKeyexchange { public static void main(String[] args) throws Exception { System.out.println("E02 ECDH Schlüsselaustausch"); String ecdhCurvenameString = "secp256r1"; // standard kurvennamen // secp256r1 [NIST P-256, X9.62 prime256v1] // secp384r1 [NIST P-384] // secp521r1 [NIST P-521] // jeder der beiden benutzer erzeugt ein eigenes schluessel-paar // variablen fuer den benutzer a KeyPair aKeyPair = generateEcdhKeyPair(ecdhCurvenameString); PrivateKey aPrivateKey = aKeyPair.getPrivate(); // der private schluessel von benutzer a PublicKey aPublicKey = aKeyPair.getPublic(); // der public schluessel von benutzer a byte[] aSharedSecretByte = null; // variablen fuer den benutzer b KeyPair bKeyPair = generateEcdhKeyPair(ecdhCurvenameString); PrivateKey bPrivateKey = bKeyPair.getPrivate(); // der private schluessel von benutzer b PublicKey bPublicKey = bKeyPair.getPublic(); // der public schluessel von benutzer b byte[] bSharedSecretByte = null; // ausgabe der schluessel fuer jeden benutzer System.out.println("\n= = = Erzeugung der Schlüssel von Benutzer A = = ="); System.out.println("Benutzer A PrivateKey (Hex):" + printHexBinary(aPrivateKey.getEncoded())); System.out.println("Benutzer A PublicKey (Hex) :" + printHexBinary(aPublicKey.getEncoded())); System.out.println("Benutzer A PublicKey :" + aPublicKey.toString()); System.out.println("\n= = = Erzeugung der Schlüssel von Benutzer B = = ="); System.out.println("Benutzer B PrivateKey (Hex):" + printHexBinary(bPrivateKey.getEncoded())); System.out.println("Benutzer B PublicKey (Hex) :" + printHexBinary(bPublicKey.getEncoded())); System.out.println("Benutzer B PublicKey :" + bPublicKey.toString()); // nun werden die public keys untereinander getauscht // in der realen welt wird der public key zB per mail oder einer webseite // verteilt // hier werden die beiden public keys "nur" beim jeweils anderen benutzer // angezeigt System.out.println("\n= = = Schlüssel bei Benutzer A = = ="); System.out.println("Benutzer A PrivateKey (Hex):" + printHexBinary(aPrivateKey.getEncoded())); System.out.println("Benutzer B PublicKey (Hex) :" + printHexBinary(bPublicKey.getEncoded())); System.out.println("\n= = = Schlüssel bei Benutzer B = = ="); System.out.println("Benutzer B PrivateKey (Hex):" + printHexBinary(bPrivateKey.getEncoded())); System.out.println("Benutzer A PublicKey (Hex) :" + printHexBinary(aPublicKey.getEncoded())); // erzeugung des shared secret keys bei jedem benutzer // benutzer a aSharedSecretByte = createEcdhSharedSecret(aPrivateKey, bPublicKey); // benutzer b bSharedSecretByte = createEcdhSharedSecret(bPrivateKey, aPublicKey); // ausgabe der shared keys fuer jeden benutzer System.out.println("\n= = = Gemeinsame Schlüssel (SharedSecred) bei den Benutzern = = ="); System.out.println("Benutzer A SharedSecret (Hex):" + printHexBinary(aSharedSecretByte)); System.out.println("Benutzer B SharedSecret (Hex):" + printHexBinary(bSharedSecretByte)); // die laenge des schluessels duerfte zu gross fuer viele aes-verfahren sein, // daher kuerzen wir den schluessel mittels eines hashes System.out.println("\nSchlüssel-Länge des SharedSecretByte :" + aSharedSecretByte.length + " Byte/" + (aSharedSecretByte.length * 8) + " Bit"); // hashing der ausgabe um einen 32 byte = 256 bit schluessel zu erhalten MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] sharedSecret32Byte = digest.digest(aSharedSecretByte); System.out.println("= = = Der gemeinsame Schlüssel wird per SHA-256 Hash auf eine Länge von 32 Byte gebracht = = ="); System.out.println("SharedSecretByte nach SHA-256Hash (Hex) :" + printHexBinary(sharedSecret32Byte)); System.out.println("Schlüssel-Länge des SharedSecret32Byte :" + sharedSecret32Byte.length + " Byte/" + (sharedSecret32Byte.length * 8) + " Bit"); // ab hier folgt zb die verschluesselung einer datei mittels aes mit nutzung des // sharedSecret32Byte als key } public static KeyPair generateEcdhKeyPair(String curvenameString) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "SunEC"); ECGenParameterSpec ecParameterSpec = new ECGenParameterSpec(curvenameString); keyPairGenerator.initialize(ecParameterSpec); return keyPairGenerator.genKeyPair(); } public static byte[] createEcdhSharedSecret(PrivateKey privateKey, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException { KeyAgreement keyAgree = KeyAgreement.getInstance("ECDH"); keyAgree.init(privateKey); keyAgree.doPhase(publicKey, true); return keyAgree.generateSecret(); } 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); } } |
Die Ausgabe auf der Konsole sieht ähnlich zu Beispiel E01 aus:
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 |
E02 ECDH Schlüsselaustausch = = = Erzeugung der Schlüssel von Benutzer A = = = Benutzer A PrivateKey (Hex):3041020100301306072A8648CE3D020106082A8648CE3D0301070427302502010104203F047007C7F468E852FE8A4FA1B20BA8AB4AD42FE0B356B650896478E43CCBBF Benutzer A PublicKey (Hex) :3059301306072A8648CE3D020106082A8648CE3D030107034200049501AFAB5839AA775E75D4985651CDC656B234629DF1A76EEFC21F0FB7367C022C758E0709178BB2B8FC575E354F30C6DEFF50A5384FB6ABB65EC659D3ED4252 Benutzer A PublicKey :Sun EC public key, 256 bits public x coord: 67397593711024242718910738499416239167549291429001008960048168246136693750786 public y coord: 20109466681901159747569512032785611803125529644634866987033491175327853789778 parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7) = = = Erzeugung der Schlüssel von Benutzer B = = = Benutzer B PrivateKey (Hex):3041020100301306072A8648CE3D020106082A8648CE3D030107042730250201010420FB3B30A2A994434D28C9F2B93A6121F02F97904911A2733F5B3D3B9C5DCC92FE Benutzer B PublicKey (Hex) :3059301306072A8648CE3D020106082A8648CE3D030107034200047E5DD30A21AF8E6657A7664F3F7A5588C1A6E50809FA621DBD970BC960144C70B682D0CBC8EABF3BFBF7F5A2B310A0584E51CA6E3B8EB9F850810BBBEB0AFA9A Benutzer B PublicKey :Sun EC public key, 256 bits public x coord: 57157192240142119435216756736770784976264193742072870255787719521178557369456 public y coord: 82552069617844006167646926219538285581926420536823113346115590292234580982426 parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7) = = = Schlüssel bei Benutzer A = = = Benutzer A PrivateKey (Hex):3041020100301306072A8648CE3D020106082A8648CE3D0301070427302502010104203F047007C7F468E852FE8A4FA1B20BA8AB4AD42FE0B356B650896478E43CCBBF Benutzer B PublicKey (Hex) :3059301306072A8648CE3D020106082A8648CE3D030107034200047E5DD30A21AF8E6657A7664F3F7A5588C1A6E50809FA621DBD970BC960144C70B682D0CBC8EABF3BFBF7F5A2B310A0584E51CA6E3B8EB9F850810BBBEB0AFA9A = = = Schlüssel bei Benutzer B = = = Benutzer B PrivateKey (Hex):3041020100301306072A8648CE3D020106082A8648CE3D030107042730250201010420FB3B30A2A994434D28C9F2B93A6121F02F97904911A2733F5B3D3B9C5DCC92FE Benutzer A PublicKey (Hex) :3059301306072A8648CE3D020106082A8648CE3D030107034200049501AFAB5839AA775E75D4985651CDC656B234629DF1A76EEFC21F0FB7367C022C758E0709178BB2B8FC575E354F30C6DEFF50A5384FB6ABB65EC659D3ED4252 = = = Gemeinsame Schlüssel (SharedSecred) bei den Benutzern = = = Benutzer A SharedSecret (Hex):2E741215E07256B8863A6F3B4F75FE6F48B5B8F4F09C9B7A5A55480B5D3C9DF2 Benutzer B SharedSecret (Hex):2E741215E07256B8863A6F3B4F75FE6F48B5B8F4F09C9B7A5A55480B5D3C9DF2 Schlüssel-Länge des SharedSecretByte :32 Byte/256 Bit = = = Der gemeinsame Schlüssel wird per SHA-256 Hash auf eine Länge von 32 Byte gebracht = = = SharedSecretByte nach SHA-256Hash (Hex) :5834FB2DE4CD9C9955659BD3A73C8D29F574F62ED869E863CC58E132B437D576 Schlüssel-Länge des SharedSecret32Byte :32 Byte/256 Bit |
Die Lizenz zum obigen Beispiel findet Ihr auf der eigenen Lizenz-Seite.