我正在与我们的客户端服务器通信。对于 api,我需要用我的私钥对字符串进行签名。他们有以下条件要遵循
- 用户SHA 256算法计算字符串的哈希
- 使用私钥和 RSA (PKCS1_PADDING( 算法对哈希值进行签名。
- Base64 对加密的哈希值进行编码
我正在做以下工作
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()
在这里,我得到了一个字符串作为结果。但是在服务器端,我的签名不匹配。
我有什么问题吗?谁能帮我这个?
我最近回到这个问题,注意到它从未得到解决。我不知道 OP 设置出了什么问题,但以下代码对我有用。
首先,生成"Hello world"
签名的python代码:
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
现在验证它的 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));
}
也许最棘手的部分是在每种语言/库中指定正确的填充方案。这些签名使用 PKCS#1 RFC 8017 中标识为 RSASSA-PKCS1-v1_5 的方案。在 python 端,这是通过向PKCS1_v1_5签名对象提供 SHA256 哈希对象来实现的。在 Java 中,它可能更简单一些,因为您要求Signature
对象以 SHA256 作为哈希函数实现 RSA 算法,但仍然必须知道这是 RSASSA-PKCS1-v1_5而不是 RFC 8017 中的其他可能性。
我认为,如果一个人还不是专家,那么理解python和Java中的这些神奇选择会产生兼容的代码将是困难的。