1

When I make a post request with the payload and its signature generated by Java, the server accepts the request.

When I use the same payload and generate signature using same algorithm but now using python, I keep getting Bad Padding exception.

I compared the sha generated by both programs and they seem to be the same, so something's wrong with encryption.

I tried a few things like :-

    i). Encoded the sha with "utf-8", just like its being done in the Java code.  
        The resulting string was the same as the original sha and still got the  
        bad padding.

I have feeling I have to convert the sha in some specific format encrypt and then change the encrypted message to some specific format. To mimic these lines of Java code :-

byte[] encrypted = cipher.doFinal(sha.getBytes("UTF-8"));
byte[] encoded = Hex.encode(encrypted);
strEncrypted = new String(encoded);

But so far I have not succeeded. Please Help.

Here is my Java code (Note it has some missing parts so won't compile. Only makeDigest and encrypt methods are of interest to us) :-

import javax.crypto.Cipher;

String payload = "something";
public static void main(String[] args) throws Exception {
    String dig = makeDigest(payload, "SHA-1");
    Key k = getKey();
    String signature = encrypt(dig, "RSA/ECB/PKCS1Padding", k);
    System.out.print(signature);
}

public static String makeDigest(String payload, String digestAlgo) {
    String strDigest = "";
    try {
        MessageDigest md = MessageDigest.getInstance(digestAlgo);
        byte[] p_b = payload.getBytes("UTF-8");
        md.update(p_b);
        byte[] digest = md.digest();
        byte[] encoded = Hex.encode(digest);
        strDigest = new String(encoded);
    }
    catch (Exception ex) {
        ex.printStackTrace();
    }
    return strDigest;
}

public static String encrypt(String sha, String encryptAlgo, Key k) {
    String strEncrypted = "";
    try {
        Cipher cipher = Cipher.getInstance(encryptAlgo);
        cipher.init(Cipher.ENCRYPT_MODE, k);
        byte[] encrypted = cipher.doFinal(sha.getBytes("UTF-8"));
        byte[] encoded = Hex.encode(encrypted);
        strEncrypted = new String(encoded);
    }
    catch (Exception ex) {
        ex.printStackTrace();
    }
    return strEncrypted;
}

I tried to convert this code to python using Crypto modules.
My Python Code:-

from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5

def get_payload_sha(payload):
    sha = SHA.new(payload).hexdigest()
    return sha

def get_sha_signature(sha):
   key = RSA.importKey(open(some_private_key, "r").read())
   cipher = PKCS1_v1_5.new(key)
   cipher_text = cipher.encrypt(sha)
   signature = cipher_text.encode("hex")
   return signature

payload = "something"
sha = get_payload_sha(payload)
signature = get_sha_signature(sha)
print signature

ERROR

ERROR   96  25-08-2015  10:46:08 Exception decrypting signature [signature=dfg23fghdf2349a3e87e3] : javax.crypto.BadPaddingException: unknown block type
javax.crypto.BadPaddingException: unknown block type
    at org.bouncycastle.jce.provider.JCERSACipher.engineDoFinal(Unknown Source)
    at javax.crypto.Cipher.doFinal(DashoA13*..)
1
  • I am trying to encrypt using private key. Why should I call that method "publickey"? Commented Aug 25, 2015 at 11:21

2 Answers 2

1

You're trying to encrypt a hex-encoded hash with the private key. This operation is called a signature and is internally done with the use of the private exponent d.

If you simply encrypt something with an RSA key (public or private) in pycrypto, then you're always using the public exponent e for this (ref).

You would need to use the signature generation for this:

from Crypto.Signature import PKCS1_v1_5

cipher = PKCS1_v1_5.new(key)
signature = cipher.sign(sha)

But this may not work, because the padding that is used for encrypting and signing is different. So even if the Java code did work, the signature is not likely to be correct.

You can try to exchange e and d as a quick fix:

from Crypto.Cipher import PKCS1_v1_5

temp = key.d
key.d = key.e
key.e = temp

cipher = PKCS1_v1_5.new(key)
signature = cipher.encrypt(sha)
Sign up to request clarification or add additional context in comments.

1 Comment

I seem to have made progress. These were the changes made 1. I returned the sha instead of hexdigest of sha from get_sha.. function to fix 'oid' issue. 2. I used your 1st block of code. Result:- I got this error message "Calculated SHA1 (some numbers and alphabets) digest does not match decrpyted value (weird characters)!" Can you suggest how to fix this??
1

Nothing else worked for me but this:-
I chucked PyCrypto and used M2Crypto instead.

import M2Crypto
import hashlib
payload = something
digest = hashlib.sha1(payload).hexdigest()

# Read private key.
private_key = M2Crypto.RSA.load_key('path_to_somekey')

# Encrypt digest using private key and encode in Hex (Base16)
signature = private_key.private_encrypt(digest, M2Crypto.RSA.pkcs1_padding).encode("hex")
print signature

And you are done!!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.