RSA-SHA1について混乱しています。RSA_private_encrypt(SHA1(メッセージ))だと思いました。しかし、正しい署名値を取得できません。何か間違っていることでも?
2 に答える
はい、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_signed
公開鍵で再度復号化した結果です。RSA_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 ハッシュと同じです。
間違った OpenSSL 抽象化レベルで作業していると思います。おそらく、 PKCS#1準拠の署名で使用することを意図したrsa.h
-declared 関数RSA_sign()
とを使用する必要があります。RSA_verify()