2012-11-16 39 views
22

Tôi muốn tạo chữ ký RSA-SHA256 trong Java, nhưng tôi không thể tạo chữ ký giống như với OpenSSL trên bảng điều khiển.Tại sao chữ ký RSA-SHA256 tôi tạo ra với OpenSSL và Java khác nhau?

Đây là những gì tôi đã làm với OpenSSL (sau this tutorial):

Tạo cặp khóa:

openssl genrsa -out private.pem 1024 

Extract công chính:

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

Tạo băm của dữ liệu:

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

Tệp băm được tạo bắt đầu bằng (stdin)= những gì tôi đã xóa bằng tay (trước tiên quên đề cập đến nó, nhờ có dữ liệu).

Đăng băm:

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

Để tái tạo các kết quả trong Java đầu tiên tôi chuyển đổi các khóa bí mật từ PEM để Der:

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

Bây giờ tôi đã viết lớp Java này để tạo chữ ký giống nhau:

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

} 

Thật không may là kết quả không giống nhau, vì vậy tôi nghĩ tôi phải làm điều gì đó wron g, nhưng tôi không thể hiểu được điều gì. Ai đó có thể giúp tôi tìm lỗi không?

+0

Đệm ngẫu nhiên và mã hóa thư sẽ đảm bảo chữ ký không khớp. Có lẽ bạn nên sử dụng một chương trình chữ ký xác định? – jww

Trả lời

36
openssl dgst -sha256 < data.txt 

sản xuất cái gì đó như:

 
(stdin)= b39eaeb437e33087132f01c2abc60c6a16904ee3771cd7b0d622d01061b40729 

thông báo các (stdin)= '? bạn không muốn điều đó là một phần của hàm băm, nếu bạn cần tạo thông báo, hãy sử dụng tùy chọn -binary.

thử sử dụng này để ký dữ liệu của bạn:

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

này làm mọi thứ mà bạn cần.


chỉnh sửa - một chút giải thích hơn:

hãy tạo một digest và hiển thị nó

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

bây giờ chúng tôi lấy tiêu hóa này và ký int sử dụng 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.| 

bây giờ, hãy đăng nhập cùng một tệp bằng cách sử dụng dgst trực tiếp:

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

Vậy điều gì khác biệt ở đây? Để thấy điều đó, chúng ta có thể xác minh chữ ký và hiển thị đầu ra thô.Cả hai file nào chứa tiêu hóa, nhưng các siêu dữ liệu và padding là khác nhau:

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

Để thấy điều này rõ ràng hơn, chúng ta có thể cố gắng sử dụng -asn1parse cờ, mà sẽ không làm việc cho chữ ký đầu tiên, nhưng đối với thứ hai nó cho thấy cấu trúc chính xác của chữ ký:

$ 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

Bạn đã đúng, tôi đã nhận thấy nó và xóa '(stdin) =' khỏi tệp băm bằng tay, nhưng quên đề cập đến nó trong câu hỏi của tôi. Tôi sẽ sửa câu hỏi của tôi. Cảm ơn. –

+1

Tuy nhiên, bạn nên tạo chữ ký bằng cách sử dụng lệnh thứ hai tôi đăng, cách bạn đang làm nó, bạn ký chuỗi đại diện của băm thay vì nhị phân, và điều này không thực sự tạo ra một chữ ký hợp lệ. xem câu trả lời của tôi từ [đây] (http://stackoverflow.com/questions/11221898/m2crypto-rsa-sign-vs-openssl-rsautl-sign/11227055#11227055) – mata

+0

Bạn nói đúng, một lần nữa. Sử dụng lệnh của bạn chữ ký giống với chữ ký được tạo bởi Java. Nhưng một vấn đề khác xuất hiện cho tôi. Chữ ký cũ (không chính xác) của tôi đã được xác minh thành công bằng lệnh 'openssl rsautl -verify -inkey.png -keyform PEM -pubin -in signature> verified', những gì không hoạt động nữa. Bạn có thể cho tôi biết lệnh xác minh chính xác là gì không? –

Các vấn đề liên quan