简体   繁体   English

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

[英]RSA sign a string with private key in python

I am communicating with our clients server.我正在与我们的客户服务器通信。 For an api I need to sign a string with my private key.对于 api,我需要用我的私钥签署一个字符串。 They have the following condition to follow他们有以下条件可以遵循

  1. User SHA 256 algorithm to calculate the hash of the string使用SHA 256算法计算字符串的hash
  2. Use the private key and RSA (PKCS1_PADDING) algorithm to sign the Hash Value.使用私钥和 RSA (PKCS1_PADDING) 算法对 Hash Value 进行签名。
  3. Base64 encode the encrypted Hash Value Base64对加密后的Hash值进行编码

and I am doing following我正在做以下

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()

Here I am getting a string as result.结果我得到了一个字符串。 But on the server side my signature is not matching.但是在服务器端我的签名不匹配。

Is there anything I am going wrong with??我有什么问题吗? Can anyone help me on this?谁可以帮我这个事?

I came back to this question recently and noticed it was never resolved.我最近回到这个问题并注意到它从未得到解决。 I don't know what was going wrong with the OPs setup but the following code worked for me.我不知道 OP 设置出了什么问题,但以下代码对我有用。

First, the python code that generates the signature of "Hello world" :首先,生成"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

And now the Java code that verifies it:现在验证它的 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));
    }

Perhaps the trickiest part of this is specifying the correct padding scheme in each language/library.也许其中最棘手的部分是在每种语言/库中指定正确的填充方案。 These signatures use the scheme identified as RSASSA-PKCS1-v1_5 in the PKCS#1 RFC 8017 .这些签名使用PKCS#1 RFC 8017中标识为RSASSA-PKCS1-v1_5的方案。 On the python side this is accomplished by providing the SHA256 hash object to the PKCS1_v1_5 signature object. In Java it is perhaps a little more straightforward in that you ask for Signature object that implements the RSA algorithm with SHA256 as the hash function, but still have to know that this is RSASSA-PKCS1-v1_5 and not some other possibility in RFC 8017. On the python side this is accomplished by providing the SHA256 hash object to the PKCS1_v1_5 signature object. In Java it is perhaps a little more straightforward in that you ask for Signature object that implements the RSA algorithm with SHA256 as the hash function, but still have知道这是 RSASSA-PKCS1-v1_5 而不是 RFC 8017 中的其他可能性。

I think if one is not already something of an expert then understanding that these magic choices in python and Java produce compatible code is going to be difficult.我认为,如果一个人还不是专家,那么理解 python 和 Java 中的这些神奇选择会产生兼容代码将会很困难。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM