使用 openssl 实用程序签名,使用 python 脚本验证

Sign with openssl utility, verify with python script

我想从 python.

中验证已使用命令行实用程序签名的文件的签名

我的命令行。

openssl pkeyutl -sign -in data.sha256 -inkey device.key -out data-pss.sign -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:32 -pkeyopt rsa_mgf1_md:sha256

我的 python 脚本。

from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization 

# client cert -> get public key
with open('device.pem', 'rb') as fc:
    cert = x509.load_pem_x509_certificate(fc.read(), default_backend())
    public_key = cert.public_key()

# private key
with open('device.key','rb') as fk:
    private_key = serialization.load_pem_private_key(fk.read(), password=None, backend=default_backend())

# data sha256 that has been signed
with open('data.sha256', 'rb') as fd:
    data_sha256 = fd.read()

# data signature done by command line
with open('data-pss.sign', 'rb') as fds:
    data_sig = fds.read()

public_key.verify(data_sig,
                  data_sha256, 
                  padding.PSS(
                    mgf=padding.MGF1(hashes.SHA256()),
                    salt_length=32
                  ),
                  hashes.SHA256())

我得到 cryptography.exceptions.InvalidSignature

如果我通过 python 签名 - 没问题 - 验证成功。

data_sig_py = private_key.sign(data_sha256,
                               padding.PSS(
                                 mgf=padding.MGF1(hashes.SHA256()),
                                 salt_length=32
                               ),
                               hashes.SHA256()
                              )

public_key.verify(data_sig_py,
                  data_sha256, 
                  padding.PSS(
                    mgf=padding.MGF1(hashes.SHA256()),
                    salt_length=32
                  ),
                  hashes.SHA256())

在Python代码中,已经散列的数据在RSAPublicKey#verify(). In this case a Prehashed instance must be passed in the fourth parameter of RSAPublicKey#verify(), i.e. specifically utils.Prehashed(hashes.SHA256()), see also this example的第二个参数中传递。

目前 HashAlgorithm 个实例作为第四个参数传递,即具体 hashes.SHA256()。这也是可能的,但前提是在第二个参数中传递原始数据(即 非散列数据 )而不是已经散列的数据。在这种情况下,RSAPublicKey#verify() 隐式地 散列

即在当前的 Python 代码中,数据在验证时被 double 散列。然而,在 OpenSSL 语句中,只有 single 散列数据被签名。因此,使用 Python 代码的验证失败。
如果签名是使用 Python 代码创建的(如上一个示例),数据也会被散列 两次,从而验证成功。