2012-11-16 11 views
22

Chcę wygenerować podpis RSA-SHA256 w Javie, ale nie mogę uzyskać tego samego podpisu, co w przypadku OpenSSL na konsoli.Dlaczego generowane przeze mnie podpisy RSA-SHA256 z OpenSSL i Java są inne?

To, co zrobiłem z OpenSSL (po this tutorial):

Generowanie pary kluczy:

openssl genrsa -out private.pem 1024 

Extract klucza publicznego:

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

Utwórz skrót danych:

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

Wygenerowany plik skrótu rozpoczyna się od (stdin)=, który usunąłem ręcznie (najpierw zapomniałem o tym wspomnieć, dzięki mata).

Znak hash:

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

Aby odtworzyć wyniki w Javie I najpierw konwertowane klucza prywatnego z PEM do DER:

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

Teraz Pisałem tę klasę Java, aby wygenerować ten sam podpis:

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; 
    } 

} 

Niestety wyniki nie są takie same, więc myślę, że musiałem zrobić coś wron g, ale nie wiem co. Czy ktoś z was może mi pomóc znaleźć błąd?

+0

Losowe dopełnianie i kodowanie wiadomości sprawiają, że podpisy nie są zgodne. Może powinieneś użyć deterministycznego schematu podpisu? – jww

Odpowiedz

36
openssl dgst -sha256 < data.txt 

produkuje coś takiego:

 
(stdin)= b39eaeb437e33087132f01c2abc60c6a16904ee3771cd7b0d622d01061b40729 

wypowiedzenia (stdin)= „? nie chcesz, aby to było częścią twojego hasha, jeśli potrzebujesz stworzyć skrót, użyj opcji -binary.

Spróbuj użyć tego podpisać swoje dane:

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

to nie wszystko, czego potrzebujesz.


edycja - trochę więcej wyjaśnień:

Stwórzmy trawienia i pokazać to

$ 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..| 

teraz bierzemy tego strawić i podpisać int użyciu rsautl:

$ 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.| 

teraz podpiszmy ten sam plik, używając bezpośrednio: dgst:

$ 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....| 

Co tu jest inaczej? Aby to zobaczyć, możemy zweryfikować podpis i pokazać nieprzetworzone dane wyjściowe.Oba pliki robić zawierać strawienia, ale metadane i wyściółka jest inna:

$ 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..| 

Aby to zobaczyć jaśniej, możemy spróbować użyć flagi -asn1parse, który nie będzie pracować dla pierwszego podpisu, ale dla po drugie pokazuje poprawną strukturę podpisu:

$ 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

Masz rację, już to zauważyłem i usunąłem '(stdin) =' z pliku hasha ręcznie, ale zapomniałem wspomnieć o tym w moim pytaniu. Poprawię moje pytanie. Dzięki. –

+1

mimo to powinieneś utworzyć podpis przy użyciu drugiego polecenia, które napisałem, tak jak robisz to, podpisujesz łańcuchową reprezentację skrótu zamiast pliku binarnego, a to naprawdę nie tworzy prawidłowego podpisu. zobacz moją odpowiedź z [tutaj] (http://stackoverflow.com/questions/11221898/m2crypto-rsa-sign-vs-openssl-rsautl-sign/11227055#11227055) – mata

+0

Masz rację, znowu. Za pomocą twojego polecenia podpis jest taki sam, jak wygenerowany przez Javę. Ale pojawia się inny problem. Mój stary (nieprawidłowy) podpis został pomyślnie zweryfikowany za pomocą komendy 'openssl rsautl -verify -inkey public.pem -keyform PEM -pubin -in signature> verified', co już nie działa. Czy możesz mi powiedzieć, jakie jest prawidłowe polecenie weryfikacji? –

Powiązane problemy