使用 openssl 进行数字签名

use*_*115 2 security linux encryption openssl

我正在尝试使用 RSA 密钥对签署和验证签名。

这是我生成密钥对的方法(适用于加密/解密):

ssh-keygen -t rsa -f mykey -N '' -b 2048
mv mykey mykey-priv.pem
ssh-keygen -f mykey.pub -e -m pem > mykey-pub.pem ; rm -f mykey.pub
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试加密散列(使用私钥)然后验证它(使用公钥)时,它失败了:

openssl dgst -sha256 /etc/hosts > /tmp/hash 
openssl rsautl -sign -inkey mykey-priv.pem -in /tmp/hash -out /tmp/signature
openssl rsautl -verify -pubin -inkey mykey-pub.pem -in /tmp/signature
Run Code Online (Sandbox Code Playgroud)

最后一行让我无法加载公钥

我缺少什么?

如果相关,我正在使用 CentOS 3.9(旧的和遗留的,但我在这里别无选择)。

最后,这是一个示例密钥对:

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA8nVhTRuinf4bGAda1ufF+VGG6f8kIFGt8/oCK74n9E6lXgpu
7KqeRzadaiONDh8GgQXn5bX9O2vOL+sL0xYa3W13eCoT7+4U51C/+8HqBxujRAVm
i4r/Ju+52kober+GSuIfoNF2nMA24EDy9tid0JgHcBJ0NTyhv6sPvNfcFR1Flbpo
LixTGCcn5S9A9NzJXiOkZ6abnxmyEmZsEaboowMay027GLWAw186GODbrGBByhjq
W6W6jcijb7EFdIYCEqtC6RsZmAiuPBK0LfW5078GE05oIZrG8GtQR8f7k8HDpEDF
+ZI53CZiLhrcXq6+tS4U57FqQs8ytUf6Gno7JwIDAQABAoIBAQCn7zd64gZLqmJ3
zThVG+obGyX4U3lhTVHQaD0ysR4ZcJPHxDA6ip7gsmprxr3/puupWD7b86a3jp8c
v4/MIEZxUk3qlDKFAAHIijy/kvuW+sSl65uwUZETFf5DvQq1hYzttxuzFwIx5kzc
HQBsi3MbtQGJ1a5Z5WofSMu4wEa289tAjHQiaXs8WEbgOctwS11lhFbDLwLagBFz
FL+J0C0oGjgNYaLJUihZKsMHCPZ0/LVFDcCus0ep7mQmvAEQ3FhSNNVakUL07XmM
MC6PTUxUvQa8vGDlRnXwGlIWVFNevvudvZjs02J7KWc3hUH9DqXiEm7cClJfoISB
HIq4WFvpAoGBAP0UHfCRyv4/2nZmizX05NG/qMNuz97G6Rir2ltw9wmrpvqK/n4r
d1JX19ECCx2nQM04C4Q7jQMmyqpF21Wf903PrGXPBa8j5XIDJy+YPC2RrifGsaHm
wN1EmYVfYZCphwmTIO2D05n/4Zkgze/KmhMnqpWn27De+LLfgcxsbET7AoGBAPVB
4RvpQCfKdP+ieKRopDE0v+UkdQCogdUz0rhwAdwzhXmUZIJ/Xb4a15DIN+zxKz2h
aiIJFkifKw5bQQQQjiIuRN73YpjQ6D9jWTdEs3E1zaWYFNPNAYqSi/1g/udgLL0N
RAOw5aNCDyOV4OZRESa9rhUUngfK4VrbqWIm1pLFAoGBAOBGWZn9uaTDNXjDuw6f
7b+rV4WJyBEmuR8x/JoYa/RX9+wEDTAGmQGR8yG3693lgFndFueiVn66e9OVgKBK
2MBOD/tRETp6VzVIcguNn5bKiUmanYRamAP+bQZy1mV6tr7XcdDKiFTrHCO1nIqq
QwxClLt3PAtsLX1m8QIV+4TNAoGBAMA161hWi2Mj9mHKUUZ4hAXUU3ggBFqJtYcD
4GeP0MVk03yfYc4sR6mPm9XqNHpL4BmjAWy/Nmmf5LyRo/itiNcc7/jWZL1jLEFR
eUApZYCaLBtVfy0nA8g4ZeIkPGHVK/rWBLHn13EFepvnAKVAb3KvQVlgGSH+THNK
qAs2aQAJAoGAabSXLpXsZTdy1lMUtZlvUhH4tLVgHFJGILMQ3bh2TTMnkaVbPFyy
KDeK+QJGaqjTx1SIXYgANR5cYI1xNge6aVA6T2aY2Dlq3qpAOK3sJWhEZYDxJKeq
Oy97h96/n14jdfh1U4TValcZfgVXqAfBMjxx0fPtSQjIn2RVjZRBpFs=
-----END RSA PRIVATE KEY-----


-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA8nVhTRuinf4bGAda1ufF+VGG6f8kIFGt8/oCK74n9E6lXgpu7Kqe
RzadaiONDh8GgQXn5bX9O2vOL+sL0xYa3W13eCoT7+4U51C/+8HqBxujRAVmi4r/
Ju+52kober+GSuIfoNF2nMA24EDy9tid0JgHcBJ0NTyhv6sPvNfcFR1FlbpoLixT
GCcn5S9A9NzJXiOkZ6abnxmyEmZsEaboowMay027GLWAw186GODbrGBByhjqW6W6
jcijb7EFdIYCEqtC6RsZmAiuPBK0LfW5078GE05oIZrG8GtQR8f7k8HDpEDF+ZI5
3CZiLhrcXq6+tS4U57FqQs8ytUf6Gno7JwIDAQAB
-----END RSA PUBLIC KEY-----
Run Code Online (Sandbox Code Playgroud)

dav*_*085 5

旁白:ssh-keygen -m仅在相当新的 OpenSSH 版本中,比我在 CentOS 3.9 上预期的要新得多。您是否使用了一些侧面存储库或自己构建它或其他什么?反正...

OpenSSH 所谓的“PEM”不是 OpenSSL 在这里使用的那种 PEM。

背景:OpenSSL长期以来一直支持 PEM 和 DER 格式的两种公钥结构:

  • 特定于每个受支持算法的“传统”结构,具有
    -----BEGIN RSA PUBLIC KEY-----
    -----BEGIN DSA PUBLIC KEY-----
    -----BEGIN EC PUBLIC KEY-----
    由例程实现的PEM 标头PEM_{write,read}{RSA,DSA,EC}PublicKey

  • 一种由 X.509 定义的通用结构,以SubjectPublicKeyInfoPEM 标头命名
    -----BEGIN PUBLIC KEY-----!!注意没有
    由例程实现的算法名称PEM_{write,read}{,RSA,DSA,EC}PUBKEY

但是,OpenSSL命令行几乎只使用后者,包括 for rsautl -pubin. 你可以看到你有前者。为什么?

OpenSSH,当它最近添加了-mssh-keygen -e导出的格式选项时,莫名其妙地将 OpenSSL 遗留结构命名为 OpenSSL PEMX.509 通用结构PKCS8——尽管它根本不是 PKCS#8,它是私钥的标准和通用格式。

所以你的选择是:

  • 使用看起来错误但实际上正确的格式选项 ssh-keygen -e -m pkcs8

  • 转换您使用的唯一操作的文件处理遗留结构:
    openssl rsa -in sshpub_called_pem -RSAPublicKey_in -out goodpub -pubout
    但只有在OpenSSL的1.0.0及以上。

  • 鉴于您的 OpenSSH 私钥文件采用 OpenSSL 兼容格式(这-----BEGIN RSA PRIVATE KEY-----不是-----BEGIN OPENSSH PRIVATE KEY-----OpenSSH 的最新添加),您可以使用 OpenSSL代替 ssh-keygen -e
    openssl rsa -in sshprivate -pubout -out pubforopenssl
    或在 1.0.0 及更高版本中,闪亮的新替代方案 openssl pkey -in sshprivate -pubout -out pubforopenssl

还请注意:(rsautl -sign|-verify默认情况下)使用 PKCS#1-v1.5(又名 01 型)填充,但不遵守要求您还将哈希编码为 ASN.1 的标准SEQUENCE。您以这种方式创建的签名不会在其他符合标准的软件中进行验证,并且在其他软件中创建的签名会给出不同的(尽管部分匹配)结果。考虑改为使用

 openssl {dgst -hashname | hashname} {-sign privatekey | -verify publickey}
Run Code Online (Sandbox Code Playgroud)

它完成了完整的操作:对数据进行散列、ASN.1 编码、填充和 RSA 签名,或者反过来进行 RSA 验证、取消填充、解码和匹配;或者

 openssl pkeyutl -sign|-verify -inkey key [-pubin] -pkeyopt digest:hashname
Run Code Online (Sandbox Code Playgroud)

其中密钥是 RSA 密钥,它执行散列数据之外的所有 PKCS#1-v1.5 。例如:
https : //stackoverflow.com/questions/9380856/openssl-signature-difference-when-using-c-routines-and-openssl-dgst-rsautl-
/sf/ask/939344101/ are-the-rsa-sha256-signatures-i-generate-with-openssl-and-java-different
/sf/ask/696609161/
https:// crypto.stackexchange.com/questions/27079/what-is-the-difference-between-openssl-pkeyutl-sign-and-openssl-rsautl-sign
https://crypto.stackexchange.com/questions/27892/verify-a -rsa-signature-using-only-rsa-encryption