Wir starten mit einem Basismodell, welches alle Bestandteile der RSA-Routinen mitbringt. Aus Darstellungsgründen habe ich als Schlüssellänge 512 Bit gewählt, welche allerdings in der realen Welt niemals verwendet werden darf, da sie als unsicher einzustufen ist.
Ganz wichtig ist es, sich den Einsatz des Public und des Private Keys in Erinnerung zu rufen, da an dieser Stelle immer wieder Fehler gemacht werden. Bei der asymmetrischen Signatur veröffentlicht der Absender seinen Public (öffentlichen) Schlüssel, z.B. auf seiner Webseite. Der Absender der Nachricht benutzt seinen Private Key für die Erzeugung der Signatur und sendet die Nachricht (ciphertext) zusammen mit der Signatur an den Empfänger. Der Empfänger prüft die Signatur mit dem Public Keys des Absenders.
Hier noch einmal die Kurzform: signieren mit dem Private Key des Absenders, prüfen der Signatur (Verifizierung) mit dem Public Key des Absenders.
Signatursteckbrief | |
Name des Verfahrens | RSA |
Langname | RSA Signatur |
Art der Chiffre | Kompletter Plaintext |
Blocklänge (Byte) | – |
Schlüssellänge (Byte/Bit) | 64/512, 128/1024, 256/2048, 512/4096, 1024/8192 |
Padding genutzt | Nein |
Sicherheit | nur ab 2048 Bit Schlüssellänge |
Besonderes | – |
Ich habe den Quellcode gleich mittels Methoden strukturiert, damit die Beispiele der weiteren Signaturverfahren leichter vergleichbar sind.
Bitte die nachfolgende Routine nicht für den Echteinsatz nutzen, da sie aus kryptographischer Sicht sehr 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 |
package net.bplaced.javacrypto.signature; /* * 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): 09.01.2019 * Funktion: signiert und verifiziert einen Text mittels RSA (Asymmetrisch) * Function: signs and verifies a text string using RSA (asymmetric) * * 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.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Signature; import java.security.SignatureException; import javax.xml.bind.DatatypeConverter; public class D01_RsaSignaturString { public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException, SignatureException { System.out.println("D01 RSA Signatur mit einem String"); // KeyPair generieren // Hinweis: RSA-Unterschriften werden ab einer Schlüssellänge von 2.048 Bit als // sicher angesehen. Hier wird die Länge von 512 Bit nur verwendet, um die // Ausgabe der erzeugten Schlüssel "klein" zu halten int rsaKeyLengthInt = 512; // 512, 1024, 2048, 4096, 9192 bit String rsaHashverfahrenString = "SHA256withRSA"; // SHA256withRSA, SHA384withRSA, SHA512withRSA KeyPair keyPair = generateRsaKeyPair(rsaKeyLengthInt); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); // ausgabe der schlüsseldaten System.out.println("\nprivateKey Länge:" + privateKey.getEncoded().length + " Data:\n" + byteArrayPrint(privateKey.getEncoded(), 33)); System.out.println("\npublicKey Länge: " + publicKey.getEncoded().length + " Data:\n" + byteArrayPrint(publicKey.getEncoded(), 33)); System.out.println("\nPublic Key : " + publicKey.toString()); // diese nachricht soll signiert werden String messageString = "Nachricht fuer Signatur"; byte[] messageByte = messageString.getBytes("utf-8"); System.out.println("\nOriginal-Nachricht :" + messageString); System.out.println("Original-Nachricht hex :" + DatatypeConverter.printHexBinary(messageByte)); // die signatur erfolgt mit dem privaten schlüssel byte[] signatureByte = signRsa(privateKey, rsaHashverfahrenString, messageByte); System.out.println( "\nsignatureByte Länge:" + signatureByte.length + " Data:\n" + byteArrayPrint(signatureByte, 33)); // die überprüfung der signatur erfolgt mit dem öffentlichen schlüssel System.out.println("\nÜberprüfung der Signatur"); boolean signatureIsCorrectBoolean = verifyRsa(publicKey, rsaHashverfahrenString, messageByte, signatureByte); System.out.println("Signatur ist korrekt :" + signatureIsCorrectBoolean); // veränderung der nachricht System.out.println("\nVeränderung der Nachricht"); messageByte = "Nachricht fuer Signatur2".getBytes("utf-8"); System.out.println("Veränderte-Nachricht hex :" + DatatypeConverter.printHexBinary(messageByte)); signatureIsCorrectBoolean = verifyRsa(publicKey, rsaHashverfahrenString, messageByte, signatureByte); System.out.println("Signatur ist korrekt :" + signatureIsCorrectBoolean); } public static KeyPair generateRsaKeyPair(int keylengthInt) throws NoSuchAlgorithmException { KeyPairGenerator keypairGenerator = KeyPairGenerator.getInstance("RSA"); keypairGenerator.initialize(keylengthInt, new SecureRandom()); // Achtung: die keylänge von 512 bit ist unsicher return keypairGenerator.generateKeyPair(); } public static byte[] signRsa(PrivateKey privateKey, String rsaInstanceString, byte[] messageByte) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { Signature signature = Signature.getInstance(rsaInstanceString); signature.initSign(privateKey); signature.update(messageByte); return signature.sign(); } public static Boolean verifyRsa(PublicKey publicKey, String rsaInstanceString, byte[] messageByte, byte[] signatureByte) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { Signature publicSignature = Signature.getInstance(rsaInstanceString); publicSignature.initVerify(publicKey); publicSignature.update(messageByte); return publicSignature.verify(signatureByte); } public static String byteArrayPrint(byte[] byteData, int numberPerRow) { String returnString = ""; String rawString = DatatypeConverter.printHexBinary(byteData); int rawLength = rawString.length(); int i = 0; int j = 1; int z = 0; for (i = 0; i < rawLength; i++) { z++; returnString = returnString + rawString.charAt(i); if (j == 2) { returnString = returnString + " "; j = 0; } j++; if (z == (numberPerRow * 2)) { returnString = returnString + "\n"; z = 0; } } return returnString; } } |
Hier die Ergebnisse auf der Konsole:
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 |
D01 RSA Signatur mit einem String privateKey Länge:343 Data: 30 82 01 53 02 01 00 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 04 82 01 3D 30 82 01 39 02 01 00 02 41 00 A2 9A EC 8D 42 63 CF 9D 97 AB AF 9E E3 E3 22 9D B2 8A EF 7F 40 D5 05 F4 E4 85 B8 92 74 5E FA 0C 26 1A 78 B5 C0 E1 02 DD 68 F2 F5 D6 31 8A E4 83 47 F7 5A 77 6D 8F 36 9C 41 6F E2 71 35 59 03 DD 02 03 01 00 01 02 40 79 91 44 0B 74 38 35 0F 48 46 A6 7D 2F 39 30 37 20 35 F9 4A 75 49 0E 34 01 E9 EB 8D 2B 0D 9A F8 E6 BC 45 44 E1 30 6D 11 6F E6 37 7E 7D 0C CD 8A E4 7E E3 27 D4 E0 08 B1 E5 AE 37 6A 37 3F A8 21 02 21 00 F1 ED 50 86 9A 95 67 85 94 5C EB 68 BE 22 BE 1C E9 B2 8E 11 4B 79 8C D2 23 77 F9 8F 8A 6F 43 35 02 21 00 AC 10 60 F2 1B 12 23 45 BF 5D 5E D1 F9 2A 69 19 F4 87 BA E5 B6 5E E2 CE E8 00 30 C5 CB 86 EB 09 02 20 2C 44 98 6F 88 E9 BD BF 9B 9E 45 15 2D 75 7E 04 1C 5F 27 CF D2 57 B3 84 E0 28 9B E9 C0 13 0B E1 02 20 43 18 8F F5 59 01 15 A8 19 1B 7B E2 3D 5B 80 68 92 A6 6B 07 30 BA 87 8F 4F 80 E3 83 FD FD BA A1 02 20 35 A8 0C C5 A0 BE 10 A9 CE F7 AF D8 07 FA 88 27 9B 81 18 32 8C FC 70 15 39 2C 79 8E F7 D7 60 01 publicKey Länge: 94 Data: 30 5C 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 4B 00 30 48 02 41 00 A2 9A EC 8D 42 63 CF 9D 97 AB AF 9E E3 E3 22 9D B2 8A EF 7F 40 D5 05 F4 E4 85 B8 92 74 5E FA 0C 26 1A 78 B5 C0 E1 02 DD 68 F2 F5 D6 31 8A E4 83 47 F7 5A 77 6D 8F 36 9C 41 6F E2 71 35 59 03 DD 02 03 01 00 01 Public Key : Sun RSA public key, 512 bits modulus: 8516323884804341783585853400443214505245896432822056066318199462714641794786381928611949290773028915517902532474656744797521170821497104060718787415573469 public exponent: 65537 Original-Nachricht :Nachricht fuer Signatur Original-Nachricht hex :4E61636872696368742066756572205369676E61747572 signatureByte Länge:64 Data: 31 B5 9E 5F 8E 53 FA 26 47 B4 06 AC BC BF 84 33 F5 22 EC E3 6A D5 51 BA 6A A3 69 CE 9D EB C6 C2 24 26 D3 DF 13 AD 44 A8 76 A3 E6 4C 42 37 1F C5 E8 53 E6 7C 61 B0 E1 5D E9 6B 5D 28 1C 8A AB 1F Überprüfung der Signatur Signatur ist korrekt :true Veränderung der Nachricht Veränderte-Nachricht hex :4E61636872696368742066756572205369676E6174757232 Signatur ist korrekt :false |
Die Lizenz zum obigen Beispiel findet Ihr auf der eigenen Lizenz-Seite.
Letzte Aktualisierung: 14.01.2019