4

for a bank transaction implementation, I have a private key and some data and I need to sign that data with the private key.

The example code the bank has given is in C# .NET and I can't find any equivalent to it in python.

The key is in the following format :

<RSAKeyValue>
  <Modulus>...</Modulus>
  <Exponent>...</Exponent>
  <P>...</P>
  <Q>...</Q>
  <DP>...</DP>
  <DQ>...</DQ>
  <InverseQ>...</InverseQ>
  <D>...</D>
</RSAKeyValue>

And the example code is this :

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(“ <RSAKeyValue><Modulus>oQRshGhLf2Fh... ”);
string data = "#" + merchantCode + "#" + terminalCode + "#"
+invoiceNumber + "#" + invoiceDate + "#" + amount + "#" +redirectAddress
+ "#" + action + "#" + timeStamp + "#";
byte[] signMain = rsa.SignData(Encoding.UTF8.GetBytes(data), new
SHA1CryptoServiceProvider());
sign = Convert.ToBase64String(signMain);

Now I have not found any good equivalent for this in python and I need to do the exact thing in order to not raise any exceptions. I once asked this question in another literature and it got put on hold. I don't know why they did that but I have been struggling this for weeks and I have not yet found any solutions. so please help me in any way you can. thanks in advance.

Ashkan Kazemi
  • 1,077
  • 8
  • 26

3 Answers3

6

Notice that example code use SHA1 ,not SHA256.

Also you can use an online RSA Key Converter tool to convert RSA xml format to .pem format if you want to do it once.

You can use this method:

   import json
   from Crypto.PublicKey import RSA
   from Crypto.Signature import PKCS1_v1_5
   from Crypto.Hash import SHA1
   import base64 import       

   def get_sign(data, private_key):
        rsa_key = RSA.importKey(base64.b64decode(private_key.encode("utf-8")))
        signer = PKCS1_v1_5.new(rsa_key)
        digest = SHA1.new()
        digest.update(data)
        sign = signer.sign(digest)
        return base64.b64encode(sign).decode('utf-8')

   # usage example 
   pem_private_key= """
       izfrNTmQLnfsLzi2Wb9xPz2Qj9fQYGgeug3N2MkDuVHwpPcgkhHkJgCQuuvT+qZI
       ...
       eM1tfdFZ6wMTLkxRhBkBK4JiMiUMvpERyPib6a2L6iXTfH+3RUDS6A==
       """
   payload_json = json.dumps({"is_example":True})
   sign = get_sign(pem_private_key, payload_json.encode('utf-8'))
Mojtaba Arvin
  • 679
  • 1
  • 10
  • 21
3

You will need to convert your .NET XML format key to a .PEM in order for it to be handled by any Python modules. (See this question)

Once you have that, you could use the RSA or PyCrypto modules.

Check out this example code for signing data using PyCrypto:

def sign_data(private_key_loc, data):
    '''
    param: private_key_loc Path to your private key
    param: package Data to be signed
    return: base64 encoded signature
    '''
    from Crypto.PublicKey import RSA 
    from Crypto.Signature import PKCS1_v1_5 
    from Crypto.Hash import SHA256 
    from base64 import b64encode, b64decode 
    key = open(private_key_loc, "r").read() 
    rsakey = RSA.importKey(key) 
    signer = PKCS1_v1_5.new(rsakey) 
    digest = SHA256.new() 
    # It's being assumed the data is base64 encoded, so it's decoded before updating the digest 
    digest.update(b64decode(data)) 
    sign = signer.sign(digest) 
    return b64encode(sign)

Obviously, it will need to be adapted to your needs (Use import SHA instead of import SHA256 if you need SHA-1, for example), but it should give you a good head-start.

Community
  • 1
  • 1
Anthony Hilyard
  • 1,220
  • 12
  • 27
  • thanks a bunch, nobody said python doesn't support that format. but how can I convert it? – Ashkan Kazemi Jul 28 '15 at 16:33
  • In [the question I linked above](http://stackoverflow.com/questions/3094222/how-do-i-convert-an-xml-rsa-key-to-a-pem-file), there are a few methods listed for the conversion. – Anthony Hilyard Jul 28 '15 at 16:36
1

https://pypi.python.org/pypi/rsa is an RSA implementation. I don't know what the heck is happening in that rsa.FromXmlString (https://msdn.microsoft.com/en-us/library/vstudio/system.security.cryptography.rsa.fromxmlstring(v=vs.90) ), so that will take some investigation on your part.

http://stuvel.eu/files/python-rsa-doc/reference.html#rsa.sign shows you how to sign a message in RSA, you'll want the SHA-1 hash method. Then base64 encode the results https://docs.python.org/2/library/base64.html

djcrabhat
  • 464
  • 5
  • 10