是什么导致此 InvalidSignature 异常? (public密钥和签名由PHP创建,验证在Python完成)

What's causing this InvalidSignature exception? (public key and signature are created by PHP and the verification is done in Python)

我基本上是在尝试使用 "openssl" (PHP) 创建签名并使用 "criptografy" (PYTHON) 进行验证。而且我总是收到错误 "InvalidSignature",这意味着我做错了什么。我知道它们是不同的语言和库,但是一旦我对两者使用相同的算法,我就希望获得有效的签名。感谢您的帮助。

PHP:创建 public 密钥和签名没有问题

$config = array(
    "digest_alg" => "sha256",
    "private_key_bits" => 4096,
    "private_key_type" => OPENSSL_KEYTYPE_RSA,
);
$res = openssl_pkey_new($config);
openssl_pkey_export($res, $privKey);
$pubKey = openssl_pkey_get_details($res);
$pubKey = $pubKey["key"];
error_log($pubKey);

-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtXyDj9vqTGkR/ITYZ6+e xXATzalUOdBcqee+qcb5NJ6Z5DgNdYi9lWz/4YfitYKp0EFwPzbem1zBzKbuQSko y7zRjpmyGbw8Q6wexO4SyA44jxs75JNXMA2x22dkNKajRE5kXngBIF1ixpzCxvvc kfyewM8C8y2iAy5j02YZYw9ysrQWJegamq6sidnMCJBtokOnPQaNJwbDQTqwrSRS 8IDy7BtBHB7F/bBwLArwxG7aLFjJ9vf2F7HpmZ3VvJa69OhY0pZMSqePQpJBIQ+2 ztIywpKkOukJz22Brqoe0ygMQzVrcYoj2MZ8CSiKUCJL6Wm9ErFXvBh/XqPWjX1t nWdnF6qSD/2itIw18+PzCWYaoeu6w064dcbRrUQ4UOYxp69IFtrv5OHAsuWPJ27q 2IUCZ9DWWphlwhz+lI4rAb6whd2R8Sb7vEhvSz4Kd5kIjel9Dt8mJ+jGyhTjqIhP 7amgcOQLKZJfmeltYI+F0U8oJcOPhxtlxfFB1MIxPDHvCcdR93LJGgU6NboTwcpx hnoI86xKblJmnxMxuQbUfPRU8vAuiizKVrpQS8z2k58mlxa9+hykjMcqpAvQ6STM vLswdj0j9aqyv6I94z2Q2Lgcuoh7xSJcLhKN9QGaarUqjAY/zoZPiDnCxXlnVrav BMyQZ9PqbsaHsd7pVVpuW8MCAwEAAQ== -----END PUBLIC KEY-----

$data = 'oi';
$pkeyid = openssl_pkey_get_private($privKey);
openssl_sign($data, $signature, $pkeyid);
error_log(base64_encode($signature));

MoUZzfaHCwME2mmxJnMBQWgo+lTLK2QfpfD+5IEnSwi0wmRtgZgFl7IGsWYlTO+zTQCcB/aKg91CMClmb5P2jEtOkY3ie2pNflEIsc3aGqfWoVpHJUMoft+4hytzgMszqwgbJdo6eac7zIxlrzmeb4jb58APtc4aaLLQru2Gga9oPRyCqbXrD0TXnQ6GzjDNGwi6wP30NU9KaHWaGfeq1WSqsAIaIbi2oG4MeWJYX6SOB/CX1Jg8SJYzWQahpJeybE4Z8fR6ncuvfbjp9aet1aKsPB/DFPQ5VFaAS4oItVb0Ha4wkQ8YgJu5fEUK7X9KzuOwidja5RLZtwDPa0bBSveCw9D8FUsguilaoIu7ueDPTRueK4bQkYstOc2OvVlzInukyOzFXVgZsiV23FTHrQ5FqHd9nCUbfuhgrMqHRYQmRFUgDaeyY+B5ve3bQ4lT3qm282ngKi8AZ+clB0VeaFiQxpF8SCCRMu0bX3dsQMaXRUeSVDipf3ZMABl9xXbzEjqXoJzuvC6tCnEv8K3HzKbjz2S1876eGy7opIixaUMwDu9QOiPoSiFUY/xCsX8D1Im8Mv4eyzWNV3FL1U/GS3LZzkq/NuJdB7wjCib3ieHaYX/bvTpmAp/oO0+vbI2pzq9w71cpqQpsNsOZSGkgY2q1sO6u0I5jCFScdJVbJl0=

PYTHON: InvalidSignature 错误

from cryptography.hazmat.backends import default_backend  
from cryptography.hazmat.primitives.asymmetric import padding  
from cryptography.hazmat.primitives import hashes  
from cryptography.hazmat.primitives.serialization import load_pem_private_key  
from cryptography.hazmat.primitives.serialization import load_pem_public_key
signature= 'MoUZzfaHCwME2mmxJnMBQWgo+lTLK2QfpfD+5IEnSwi0wmRtgZgFl7IGsWYlTO+zTQCcB/aKg91CMClmb5P2jEtOkY3ie2pNflEIsc3aGqfWoVpHJUMoft+4hytzgMszqwgbJdo6eac7zIxlrzmeb4jb58APtc4aaLLQru2Gga9oPRyCqbXrD0TXnQ6GzjDNGwi6wP30NU9KaHWaGfeq1WSqsAIaIbi2oG4MeWJYX6SOB/CX1Jg8SJYzWQahpJeybE4Z8fR6ncuvfbjp9aet1aKsPB/DFPQ5VFaAS4oItVb0Ha4wkQ8YgJu5fEUK7X9KzuOwidja5RLZtwDPa0bBSveCw9D8FUsguilaoIu7ueDPTRueK4bQkYstOc2OvVlzInukyOzFXVgZsiV23FTHrQ5FqHd9nCUbfuhgrMqHRYQmRFUgDaeyY+B5ve3bQ4lT3qm282ngKi8AZ+clB0VeaFiQxpF8SCCRMu0bX3dsQMaXRUeSVDipf3ZMABl9xXbzEjqXoJzuvC6tCnEv8K3HzKbjz2S1876eGy7opIixaUMwDu9QOiPoSiFUY/xCsX8D1Im8Mv4eyzWNV3FL1U/GS3LZzkq/NuJdB7wjCib3ieHaYX/bvTpmAp/oO0+vbI2pzq9w71cpqQpsNsOZSGkgY2q1sO6u0I5jCFScdJVbJl0='

decoded = base64.b64decode(signature)

plaintextMessage="oi"

# /tmp/public contains the public key
alicePubKey = load_pem_public_key(open('/tmp/public', 'rb').read(),default_backend())  

ciphertext = alicePubKey.verify(  
    decoded,  
    plaintextMessage,  
    padding.PSS(  
            mgf=padding.MGF1(algorithm=hashes.SHA256()),  
            salt_length=padding.PSS.MAX_LENGTH,  
    ),  
    hashes.SHA256()  
)

很明显,您的 PHP 代码:

  1. 使用带有 SHA1 的 RSA 签名,不是 SHA256
  2. 使用 PKCS#1 版本 1.5 填充, PSS

您似乎只是从 cryptography package documentation.

复制并粘贴了您的代码

因此,下面的 python 片段应该验证:

ciphertext = alicePubKey.verify(  
    decoded,  
    b'oi',  
    padding.PKCS1v15(),  
    hashes.SHA1()  
)

PSS 和 SHA-256 是更好的选择,因此您应该调查修改 PHP 代码以使用它们而不是修改 python 代码。

正如James所说,函数openssl_sign默认使用SHA1,可以用参数OPENSSL_ALGO_SHA256解决什么问题。

所以我做了这些改变:

PHP

openssl_sign($data, $signature, $pkeyid, OPENSSL_ALGO_SHA256);

Python

ciphertext = alicePubKey.verify(  
    decoded,  
    plaintextMessage,  
    padding.PKCS1v15(),
    hashes.SHA256()  
 )