RSA在python中用私钥对字符串进行签名

ary*_*yan 7 python cryptography rsa pycrypto pycryptodome

我正在与我们的客户端服务器通信。对于 api,我需要用我的私钥签署一个字符串。他们必须遵循以下条件

  1. 用户SHA 256算法计算字符串的哈希值
  2. 使用私钥和 RSA (PKCS1_PADDING) 算法对哈希值进行签名。
  3. Base64编码加密的Hash值

我正在做以下事情

from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
import base64


pkey = RSA.importKey(keystring)

message = "Hello world"

h = SHA256.new(message.encode())
signature = PKCS1_v1_5.new(pkey).sign(h)
result = base64.b64encode(signature).decode()
Run Code Online (Sandbox Code Playgroud)

在这里我得到一个字符串作为结果。但在服务器端我的签名不匹配。

我有什么问题吗?谁可以帮我这个事 ?

Jam*_*olk 1

我最近回到这个问题,发现它从未得到解决。我不知道 OP 设置出了什么问题,但以下代码对我有用。

首先,生成签名的Python代码"Hello world"

from Cryptodome.Signature import PKCS1_v1_5
from Cryptodome.Hash import SHA256
from Cryptodome.PublicKey import RSA
import base64


def sign(message: str, private_key_str: str) -> str:
    priv_key = RSA.importKey(private_key_str)
    h = SHA256.new(message.encode('utf-8'))
    signature = PKCS1_v1_5.new(priv_key).sign(h)
    result = base64.b64encode(signature).decode()
    return result
Run Code Online (Sandbox Code Playgroud)

现在验证它的 Java 代码:

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

...
...

    public static boolean verify(String message, String b64Sig, byte[] pubkey_spki) throws GeneralSecurityException {
        var pubKey = (PublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(pubkey_spki));
        var verifier = Signature.getInstance("SHA256withRSA");
        verifier.initVerify(pubKey);
        verifier.update(message.getBytes(StandardCharsets.UTF_8));
        return verifier.verify(Base64.getDecoder().decode(b64Sig));
    }
Run Code Online (Sandbox Code Playgroud)

也许最棘手的部分是在每种语言/库中指定正确的填充方案。这些签名使用PKCS#1 RFC 8017中标识为RSASSA-PKCS1-v1_5的方案。在 python 端,这是通过向 PKCS1_v1_5 签名对象提供 SHA256 哈希对象来完成的。在 Java 中,可能更简单一些,因为您要求使用 SHA256 作为哈希函数实现 RSA 算法的对象,但仍然必须知道这是 RSASSA-PKCS1-v1_5,而不是 RFC 8017 中的其他可能性。Signature

我认为,如果一个人还不是专家,那么理解 Python 和 Java 中的这些神奇选择会产生兼容的代码将会很困难。