13

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

4

2 回答 2

9

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

另一方面,PKCS#1 签名将首先计算表单的 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 签名编码,与使用通用EVP_PKEY_signRSA_sign获得的相同甚至更好。

下面是 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 哈希值相同。

于 2012-06-12T14:43:50.133 回答
3

我认为您在错误的 OpenSSL 抽象级别上工作;您可能应该使用rsa.h-declared 函数RSA_sign()and RSA_verify(),它旨在用于PKCS#1兼容签名。

于 2012-06-12T02:03:42.253 回答