views:

1794

answers:

5

Currently I am receiving the following error when using Java to decrypt a Base64 encoded RSA encrypted string that was made in C#:

javax.crypto.BadPaddingException: Not PKCS#1 block type 2 or Zero padding

The setup process between the exchange from .NET and Java is done by creating a private key in the .NET key store then from the PEM file extracted, created use keytool to create a JKS version with the private key. Java loads the already created JKS and decodes the Base64 string into a byte array and then uses the private key to decrypt.

Here is the code that I have in C# that creates the encrypted string:

public string Encrypt(string value) {
    byte[] baIn = null;
    byte[] baRet = null;
    string keyContainerName = "test";

    CspParameters cp = new CspParameters();
    cp.Flags = CspProviderFlags.UseMachineKeyStore;
    cp.KeyContainerName = keyContainerName;
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);

    // Convert the input string to a byte array 
    baIn = UnicodeEncoding.Unicode.GetBytes(value);

    // Encrypt
    baRet = rsa.Encrypt(baIn, false);

    // Convert the encrypted byte array to a base64 string
    return Convert.ToBase64String(baRet);
}

Here is the code that I have in Java that decrypts the inputted string:

public void decrypt(String base64String) {
    String keyStorePath = "C:\Key.keystore";
    String storepass = "1234";
    String keypass = "abcd";
    byte[] data = Base64.decode(base64String);
    byte[] cipherData = null;

    keystore = KeyStore.getInstance("JKS");
    keystore.load(new FileInputStream(keyStorePath), storepass.toCharArray());

    RSAPrivateKey privateRSAKey = (RSAPrivateKey) keystore.getKey(alias, keypass.toCharArray());

    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.DECRYPT_MODE, privateRSAKey);
    cipherData = cipher.doFinal(data);

    System.out.println(new String(cipherData));
}

Does anyone see a step missing or where the padding or item needs to be changed? I have done hours of reading on this site and others but haven't really found a concrete solution.

You're help is vastly appreciated.

Thanks. -Matt

A: 

Check that you have correctly exchanged the key.

Trying to decrypt with an incorrect key is indistinguishable from decrypting badly padded data.

Rasmus Faber
A: 

Hey Matt,

I've the same problem.

have you already found a solution for your problem?

If yes, would you post it.?

Thanks Eugen

Eugen, it turned out to be the incorrect key.
Matt Shaver
A: 

My guess is that the C# version is emitting the bytes in little endian format, and the Java version is importing the bytes expecting them to be in big endian format. Try swapping the bytes in baRet from end to end before you convert them to base 64, and see if your Java program can decrypt them then.

Just a guess.

John Deters
+1  A: 

I'm working through a similar problem operating between .Net and iPhone stuff in Objective - C, and I think the answer lies in this little gem from the RSACryptoServiceProvider documentation:

Unlike the RSA implementation in unmanaged CAPI, the RSACryptoServiceProvider class reverses the order of an encrypted array of bytes after encryption and before decryption. By default, data encrypted by the RSACryptoServiceProvider class cannot be decrypted by the CAPI CryptDecrypt function and data encrypted by the CAPI CryptEncrypt method cannot be decrypted by the RSACryptoServiceProvider class.

See here for more details: http://msdn.microsoft.com/en-us/library/s575f7e2(v=VS.90).aspx

DJBHiney
A: 

I had exactely the same problem and I finally find the solution!

I was stubborn using PKCS1Padding but I didn't manage to make it work.

The best result I got using "rsa.Encrypt(baIn, false)" on the C# side and "RSA/NONE/NoPadding" on the Java side was this kind of string : "☻?o+_>??5?l0Q*???*?R▲???♀7..." followed by my decrypted string. So in a way it got decrypted but since there is no padding specified, the data is shifted. So I tried all the paddings available in bouncycastle but I would alway get errors such as "block incorrect size" or "data hash wrong".

So I decided to start trying OAEP paddings and I finally managed to get it working by using "rsa.Encrypt(baIn, true)" on the C# side and "RSA/NONE/OAEPWithSHA1AndMGF1Padding" on the java side!

It worked for me, I hope it will work for you too! If it doesn't work make sure you're using the right key, very often the problem comes from the key.