5
votes

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

4
Where is the padding specified in the C# code? How do you know OAEP (which is PKCS #1 ver. 2) isn't being used during encryption?erickson
First thing isolate the encryption and encoding into separate probelms. Ie. validate that the decoded Java byte[] is identical with the original C# byte[]. then you can ask wether is an RSA issue or a Base64 issue. As erickson said, likely is the difference in the default PKCS between C# and Java libs.Remus Rusanu
@erickson - the .NET Encrypt() method's second parameter selects the padding - true specifies OAEP and false (used in the example) specifies PKCS #1 ver 1.5.Michael Burr
Where do you set the key for the encryption?Accipitridae
@Remus - The Base64 encoding yields different results each time but RSA is still able to decrypt it. @Accipitridae - The key store is set in the CspParameters in the .NET and ten imported in Java. The encryption and decryption works when the value is encrypted and decrypted in .NET or when it is encrypted and decrypted in Java. However not when the value is passed between.Matt Shaver

4 Answers

3
votes

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.

2
votes

Check that you have correctly exchanged the key.

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

2
votes

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

0
votes

I had the same problem when using Bouncy Castle 1.48 but it wasn't key-related. Instead, I found that I had to set the following system property:

-Dorg.bouncycastle.pkcs1.strict=false