2012-11-16 4 views
22

Ich möchte eine RSA-SHA256-Signatur in Java generieren, aber ich bekomme nicht die gleiche Signatur wie mit OpenSSL auf der Konsole.Warum sind die RSA-SHA256-Signaturen, die ich mit OpenSSL und Java erzeuge, anders?

Dies ist, was ich mit OpenSSL hat (nach this tutorial):

Schlüsselpaar generieren:

openssl genrsa -out private.pem 1024 

Extract öffentlichen Schlüssel:

openssl rsa -in private.pem -out public.pem -outform PEM -pubout 

erstellen Hash der Daten:

echo 'data to sign' > data.txt 
openssl dgst -sha256 <data.txt> hash 

Die generierte Hash-Datei beginnt mit (stdin)=, was ich von Hand entfernt habe (zuerst vergessen, es zu erwähnen, danke mata).

Sign hash:

openssl rsautl -sign -inkey private.pem -keyform PEM -in hash > signature 

Um die Ergebnisse in Java zu reproduzieren I umgewandelt zuerst den privaten Schlüssel von PEM DER:

openssl pkcs8 -topk8 -inform PEM -outform DER -in private.pem -nocrypt > private.der 

nun diese Java-Klasse schrieb ich die gleiche Signatur zu generieren:

public class RSATest { 

    public static void main(String[] args) throws IOException, 
      NoSuchAlgorithmException, InvalidKeySpecException, 
      InvalidKeyException, SignatureException { 

     byte[] encodedPrivateKey = readFile("private.der"); 
     byte[] content = readFile("data.txt"); 

     KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey); 
     RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory 
       .generatePrivate(keySpec); 

     Signature signature = Signature.getInstance("SHA256withRSA"); 
     signature.initSign(privateKey); 
     signature.update(content); 
     byte[] signatureBytes = signature.sign(); 

     FileOutputStream fos = new FileOutputStream("signature-java"); 
     fos.write(signatureBytes); 
     fos.close(); 
    } 

    private static byte[] readFile(String filename) throws IOException { 
     File file = new File(filename); 
     BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
       file)); 
     byte[] bytes = new byte[(int) file.length()]; 
     bis.read(bytes); 
     bis.close(); 
     return bytes; 
    } 

} 

Leider sind die Ergebnisse nicht die gleichen, also denke ich, dass ich etwas getan haben muss wron g, aber ich kann nicht herausfinden, was. Kann jemand von mir mir helfen, den Fehler zu finden?

+0

Zufällige Auffüllung und Nachrichtencodierung wird sicherstellen, dass die Signaturen nicht übereinstimmen. Vielleicht sollten Sie ein deterministisches Signaturschema verwenden? – jww

Antwort

36
openssl dgst -sha256 < data.txt 

produziert so etwas wie:

 
(stdin)= b39eaeb437e33087132f01c2abc60c6a16904ee3771cd7b0d622d01061b40729 

Mitteilung der (stdin)= ‚? Sie möchten nicht, dass dies Teil Ihres Hashs ist. Wenn Sie einen Digest erstellen müssen, verwenden Sie die Option -binary.

versuchen diese Daten zu unterschreiben mit:

openssl sha -sha256 -sign private.pem < data.txt 

Dies tut alles, was Sie brauchen.


bearbeiten - ein wenig mehr Erklärungen:

lassen Sie uns eine Zusammenfassung erstellen und zeigen Sie es

$ openssl dgst -sha256 -binary <data.txt> digest 
$ hd digest 
00000000 26 3b 0a a1 2e b9 32 db b8 dc d3 6f 37 94 0b 05 |&;....2....o7...| 
00000010 71 9c ba 79 46 34 28 9f 5c 5b 98 9a 64 61 c9 ec |q..yF4(.\[..da..| 

jetzt nehmen wir diese verdauen und melden rsautl int mit:

$ openssl rsautl -sign -inkey private.pem <digest> sign1 
$ hd sign1 
00000000 1b 7a cf a4 8d 41 8e 04 ed 3a bb ba 86 f1 f8 e0 |.z...A...:......| 
00000010 df f7 47 3e d7 a7 f4 90 7a 05 f8 7f 45 e5 29 e7 |..G>....z...E.).| 
00000020 9f f4 2c 91 97 2f e7 26 69 9f 6a 07 a3 48 1b 85 |..,../.&i.j..H..| 
00000030 2e f8 ee 44 4d 25 9f ae 05 95 81 c9 e3 07 68 ad |...DM%........h.| 

Jetzt signieren wir dieselbe Datei unter Verwendung von dgst direkt:

$ openssl dgst -sha256 -sign private.pem <data.txt> sign2 
$ hd sign2 
00000000 15 c2 94 87 eb e6 cb 45 c8 63 0c 97 60 d3 07 f3 |.......E.c..`...| 
00000010 dc 65 32 ad 44 1c c2 2a 7f a3 e1 fc dd 84 27 8c |.e2.D..*......'.| 
00000020 77 a6 97 2b 33 6b c6 d7 7d e1 1d 39 5c 48 b6 48 |w..+3k..}..9\H.H| 
00000030 cb 18 be bf 6a 66 90 d3 88 89 52 6c dd d1 b9 99 |....jf....Rl....| 

Also was ist hier anders? Um das zu sehen, können wir die Signatur verifizieren und die rohe Ausgabe anzeigen.Beide Dateien machen den Digest enthalten, die Metadaten und Polsterung ist anders:

$ openssl rsautl -raw -verify -inkey private.pem < sign1 | hd 
00000000 00 01 ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| 
00000010 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 |................| 
00000020 26 3b 0a a1 2e b9 32 db b8 dc d3 6f 37 94 0b 05 |&;....2....o7...| 
00000030 71 9c ba 79 46 34 28 9f 5c 5b 98 9a 64 61 c9 ec |q..yF4(.\[..da..| 

$ openssl rsautl -raw -verify -inkey private.pem < sign2 | hd 
00000000 00 01 ff ff ff ff ff ff ff ff ff ff 00 30 31 30 |.............010| 
00000010 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 |...`.H.e....... | 
00000020 26 3b 0a a1 2e b9 32 db b8 dc d3 6f 37 94 0b 05 |&;....2....o7...| 
00000030 71 9c ba 79 46 34 28 9f 5c 5b 98 9a 64 61 c9 ec |q..yF4(.\[..da..| 

dies deutlich zu sehen, können wir versuchen, die -asn1parse Flagge zu verwenden, die nicht für die erste Signatur arbeiten, aber für die Zweitens zeigt es die korrekte Struktur der Signatur:

$ openssl rsautl -verify -inkey private.pem -asn1parse < sign1 
Error in encoding 
139931349546656:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:asn1_lib.c:142: 

$ openssl rsautl -verify -inkey private.pem -asn1parse < sign2 
    0:d=0 hl=2 l= 49 cons: SEQUENCE   
    2:d=1 hl=2 l= 13 cons: SEQUENCE   
    4:d=2 hl=2 l= 9 prim: OBJECT   :sha256 
    15:d=2 hl=2 l= 0 prim: NULL    
    17:d=1 hl=2 l= 32 prim: OCTET STRING  
     0000 - 26 3b 0a a1 2e b9 32 db-b8 dc d3 6f 37 94 0b 05 &;....2....o7... 
     0010 - 71 9c ba 79 46 34 28 9f-5c 5b 98 9a 64 61 c9 ec q..yF4(.\[..da.. 
+0

Sie haben recht, ich habe es schon bemerkt und '(stdin) =' aus der Hash-Datei von Hand entfernt, aber vergessen, es in meiner Frage zu erwähnen. Ich werde meine Frage korrigieren. Vielen Dank. –

+1

Nichtsdestoweniger sollten Sie die Signatur mit dem zweiten Befehl, den ich gepostet habe, erstellen. Wie Sie es tun, signieren Sie die Zeichenfolgendarstellung des Hash anstelle der Binärdatei, und das erzeugt keine gültige Signatur. siehe meine Antwort von [hier] (http://stackoverflow.com/questions/11221898/m2crypto-rsa-sign-vs-openssl-rsautl-sign/11227055#11227055) – mata

+0

Sie haben wieder Recht. Mit Ihrem Befehl ist die Signatur identisch mit der von Java generierten. Aber ein anderes Problem erscheint für mich. Meine alte (falsche) Signatur wurde erfolgreich verifiziert mit dem Befehl 'openssl rsautl -verify -inkey public.pem -keyform PEM -pubin -in signature> verified', was nicht mehr funktioniert. Können Sie mir sagen, was der richtige Befehl für die Verifizierung ist? –

Verwandte Themen