2012-06-12 23 views

Trả lời

8

Có, mã hóa PKCS # 1 và chữ ký PKCS # 1 là different. Trong trường hợp mã hóa (trường hợp bạn đã thử), thông báo đầu vào chỉ đơn giản là đệm trước khi nó được lũy thừa.

PKCS # 1 signagtures mặt khác đầu tiên sẽ tính toán một cấu trúc ASN.1 DER dạng

DigestInfo ::= SEQUENCE { 
    digestAlgorithm AlgorithmIdentifier, 
    digest OCTET STRING 
} 

này sau đó được đệm một lần nữa để tạo thành thông điệp được mã hóa EM

EM = 0x00 || 0x01 || PS || 0x00 || T 

nơi PS là một chuỗi đệm có chiều dài là 0xff. Nếu bạn sao chép EM này và sử dụng RSA_private_encrypt, thì bạn sẽ nhận được mã hóa chữ ký PKCS # 1 v1.5 chính xác, giống như bạn sẽ nhận được với RSA_sign hoặc thậm chí tốt hơn, sử dụng chung EVP_PKEY_sign.

Dưới đây là một cuộc biểu tình nhỏ ở Ruby:

require 'openssl' 
require 'pp' 

data = "test" 
digest = OpenSSL::Digest::SHA256.new 
hash = digest.digest("test") 
key = OpenSSL::PKey::RSA.generate 512 

signed = key.sign(digest, data) 
dec_signed = key.public_decrypt(signed) 

p hash 
pp OpenSSL::ASN1.decode dec_signed 

Các băm SHA-256 in ra như sau:

"\x9F\x86\xD0\x81\x88L}e\x9A/..." 

dec_signed là kết quả của RSA_sign giải mã một lần nữa với khóa công khai - điều này mang lại chúng tôi quay lại chính xác đầu vào cho hàm RSA với phần đệm đã được xóa và khi nó quay ra, đây chính là cấu trúc DigestInfo được đề cập ở trên:

#<OpenSSL::ASN1::Sequence:0x007f60dc36b250 
@infinite_length=false, 
@tag=16, 
@tag_class=:UNIVERSAL, 
@tagging=nil, 
@value= 
    [#<OpenSSL::ASN1::Sequence:0x007f60dc36b318 
    @infinite_length=false, 
    @tag=16, 
    @tag_class=:UNIVERSAL, 
    @tagging=nil, 
    @value= 
    [#<OpenSSL::ASN1::ObjectId:0x007f60dc36b390 
     @infinite_length=false, 
     @tag=6, 
     @tag_class=:UNIVERSAL, 
     @tagging=nil, 
     @value="SHA256">, 
     #<OpenSSL::ASN1::Null:0x007f60dc36b340 
     @infinite_length=false, 
     @tag=5, 
     @tag_class=:UNIVERSAL, 
     @tagging=nil, 
     @value=nil>]>, 
    #<OpenSSL::ASN1::OctetString:0x007f60dc36b2a0 
    @infinite_length=false, 
    @tag=4, 
    @tag_class=:UNIVERSAL, 
    @tagging=nil, 
    @value="\x9F\x86\xD0\x81\x88L}e\x9A/...">]> 

Như bạn có thể thấy, giá trị của trường digestDigestInfo giống với hàm băm SHA-256 mà chúng tôi đã tính.

+0

Cảm ơn bạn đã trả lời chi tiết. Tôi đã có chữ ký chính xác bằng cách sử dụng RSA_sign với NID_sha1 (NID_sha1WithRSA là sai), và tôi nghĩ rằng tôi có thể nhận được giá trị được mã hóa là đầu vào của RSA_private_encrypt bằng cách sửa đổi hàm RSA_sign của OpenSSL. Một lần nữa, cảm ơn bạn rất nhiều! –

+0

Xin lỗi, một câu hỏi khác, làm thế nào tôi có thể nhận được EM với OpenSSL?Tôi đã theo dõi RSA_sign() và tìm thấy i = RSA_private_encrypt (i, s, sigret, rsa, RSA_PKCS1_PADDING); kết thúc bằng cách dẫn đến hàm rsa_priv_enc mà tôi không thể tìm thấy ở nơi nào khác. Cảm ơn bạn –

+1

Và, RSA_PKCS1_PADDING làm gì ở đây? –

3

Tôi nghĩ bạn đang làm việc ở cấp trừu tượng OpenSSL sai; có thể bạn đang sử dụng chức năng rsa.h -declared RSA_sign()RSA_verify(), được dự định sẽ được sử dụng trên PKCS#1 chữ ký tương thích.

+0

Cảm ơn bạn đã trả lời. Tôi vẫn không hiểu rằng những gì khác RSA_sign() mong đợi các chức năng mã hóa băm và RSA? Hai người này có đủ không? –

+0

Nó cũng xử lý vùng đệm PKCS # 1 và mã hóa ASN.1; nếu bạn chỉ đang ký nội dung mà không có đệm, nó có thể dẫn đến những điểm yếu trong RSA và mã hóa là tương thích với các chương trình khác một cách đáng tin cậy. – sarnold

+0

Tôi đã sử dụng RSA_sign (NID_SHA1, ...), nhưng kết quả không giống với tôi nhận được với xmlsec (API chữ ký xml). Tôi đang tự hỏi nếu RSA_sign (NID_SHA1, ...) đang làm RSASSA-PKCS1-v1_5? –