如何使用OpenSSL计算RSA-SHA1(sha1WithRSAEncryption)值

时间:2012-06-12 01:46:32

标签: cryptography openssl rsa digital-signature xml-signature

我对RSA-SHA1感到困惑,我认为它是RSA_private_encrypt(SHA1(消息))。 但我无法获得正确的签名值。 有什么不对吗?

2 个答案:

答案 0 :(得分:8)

是的,PKCS#1加密和PKCS#1签名是different。在加密情况下(您尝试过的情况),输入消息在被取幂之前只需填充。

另一方面,PKCS#1 signagtures将首先计算表格的ASN.1 DER结构

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

然后再次填充以形成编码消息EM

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

其中PS是足够长度的0xff的填充字符串。如果您重现此EM并使用RSA_private_encrypt,那么您将获得正确的PKCS#1 v1.5签名编码,与使用RSA_sign或更好,使用通用{{3}获得的编码相同}。

这是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

SHA-256哈希打印如下:

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

dec_signedRSA_sign再次使用公钥解密的结果 - 这使我们准确地返回了RSA函数的输入并删除了填充,结果证明,这正是上面提到的DigestInfo结构:

 #<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/...">]>

如您所见,digest DigestInfo字段的值与我们自己计算的SHA-256哈希值相同。

答案 1 :(得分:3)

我认为你正在使用错误的OpenSSL抽象级别;您应该使用rsa.h - 已声明的函数RSA_sign()RSA_verify(),这些函数旨在用于符合PKCS#1的签名。