简体   繁体   中英

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. They have the following condition to follow

  1. User SHA 256 algorithm to calculate the hash of the string
  2. Use the private key and RSA (PKCS1_PADDING) algorithm to sign the Hash Value.
  3. Base64 encode the encrypted Hash Value

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.

First, the python code that generates the signature of "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

And now the Java code that verifies it:

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 . 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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