1

I am trying to decrypt an AES encrypted string from Java, in C#. When I decrypt, it returns gibberish and does not match the original plain text, which was encrypted via Java code. Pls guide me on what is going wrong here.

Attached the Java code for encryption and the C# code for decryption. Pls let me know if you need more details.

I tried AesCryptoServiceProvider as well and it did not work either. You can see the code tried in the commented code in C#.

Pls note that I can make changes on my C# code only to match the Java code and can not make any edits to Java side.

Java code for Encryption:

/** encrypt cipher */
private static final Cipher ENCRYPT_CIPHER = generateCipher(Cipher.ENCRYPT_MODE);

private static String ENCRYPT_KEY = "key";

/**
 * @param val
 * @return encrypted value
 * @throws Exception
 */
public String encrypt(final String val) throws Exception {
    return new String(Base64.encodeBase64(ENCRYPT_CIPHER.doFinal(val.getBytes()), true)).toString();
}

/**
 * @param encrypt
 * @return cipher
 */
protected static Cipher generateCipher(final int encrypt) {
    try {
        final Cipher cipher = Cipher.getInstance("AES");
        cipher.init(encrypt, SecretKeyFactory.getInstance("AES").generateSecret(new IBMAESKeySpec(Base64.decodeBase64(ENCRYPT_KEY.getBytes()))));
        return cipher;
    } catch (final Exception e) {
        return null;
    }
}

C# code for decryption:

private static String ENCRYPT_KEY = "key";
public String decodeString (String encodedStr)
{

/*using (var aesCryptoProvider = new AesCryptoServiceProvider())
    {
    aesCryptoProvider.BlockSize = 128;
    aesCryptoProvider.KeySize = 256;
    aesCryptoProvider.Key = Convert.FromBase64String(ENCRYPT_KEY.ToString());
    aesCryptoProvider.Padding = PaddingMode.Zeros;
    aesCryptoProvider.Mode = CipherMode.ECB;

    using (var decryptor = aesCryptoProvider.CreateDecryptor())
    using (var memoryStream = new MemoryStream(Convert.FromBase64String(encodedStr)))
    using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
    using (var streamReader = new StreamReader(cryptoStream, Encoding.UTF8))
    {
        decodedStr = streamReader.ReadToEnd();
    }
    } 
 */
    using (AesManaged aesAlg = new AesManaged())
        {
        aesAlg.Key = Convert.FromBase64String(ENCRYPT_KEY.ToString()); ;
        aesAlg.BlockSize = 128;
        aesAlg.KeySize = 256;
        aesAlg.Mode = CipherMode.ECB;
        aesAlg.Padding = PaddingMode.Zeros;
        // Create a decrytor to perform the stream transform.
        ICryptoTransform decryptor = aesAlg.CreateDecryptor();

        // Create the streams used for decryption.
        using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(encodedStr)))
        {
            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
            using (StreamReader srDecrypt = new StreamReader(csDecrypt))
            {

                // Read the decrypted bytes from the decrypting stream
                // and place them in a string.
                decodedStr = srDecrypt.ReadToEnd();
            }
            }
        }

     }
}
csharpnewbie
  • 789
  • 2
  • 12
  • 33
  • You don't set the IV (https://en.wikipedia.org/wiki/Initialization_vector). This should usually be attached together with the encrypted text (it is not a secret!) and should be set in the `aesAlg.IV` property (https://msdn.microsoft.com/en-us/library/system.security.cryptography.aesmanaged.iv%28v=vs.110%29.aspx). I don't know where it can be read from in your Java cipher though. – Jens Jan 07 '16 at 19:42
  • 1
    This can be an encoding problem since most of the values are encoded to/from base64. For example, in Java, after the `String` is encrypted it is encoded to base64 but in C# after decryption, the `String` is not decoded. – Titus Jan 07 '16 at 19:43
  • @Jens - Since in the Java code shared, I did not see any IV set, I did not set a one in C# as well. I dont know the default IV for this library in Java. – csharpnewbie Jan 07 '16 at 19:45
  • I would guess that it will be randomly generated in the init step, but this is really just a hunch since I don't know anything about the java implementation. It would explain the problem though ;-) – Jens Jan 07 '16 at 19:47
  • Three questions: a) Is the IBM provider your default JCE provider? b) How long is `ENCRYPT_KEY`? c) *"Didn't work"* is not an accurate description of what went wrong. Are there any exceptions? --- **Always** use a fully qualified Cipher string such as `Cipher.getInstance("AES/CBC/PKCS5Padding")`. At least the padding is not matching between those two implementations. **Never** use ECB mode, because it is deterministic and therefore not semantically secure. – Artjom B. Jan 07 '16 at 20:23
  • 1
    @ArtjomB. - Hi - My encrypt key is 24 bytes long. As I mentioned the Java process is an existing one and used by many other systems. It uses AES already and I cant make any edits to it. I tried other modes than ECB and they all give the error ' Length of the data to decrypt is invalid'. As mentioned, after decrypting with ECB, it returns some gibberish and it does not match the original plain text. – csharpnewbie Jan 07 '16 at 20:32
  • OK. a) So which provider is it then? What JVM do you use and which version does it have? b) 24 Base64 encoded characters would mean that you have a 16 byte key which would mean that you need to set `aesAlg.KeySize = 128;`. If you actually mean 24 decoded bytes then it should be `aesAlg.KeySize = 192;`. c) What's the gibberish? Can you provide example inputs, example outputs and expected outputs? --- Please provide [an MCVE](/help/mcve) so that we can test something instead of guessing. – Artjom B. Jan 07 '16 at 21:09
  • Do you also have an example key? – Artjom B. Jan 07 '16 at 23:23
  • @ArtjomB. - Sorry unfortunately I don't have that. – csharpnewbie Jan 08 '16 at 00:00
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/100096/discussion-between-csharpnewbie-and-artjom-b). – csharpnewbie Jan 08 '16 at 00:41

1 Answers1

0

This is just a quick answer. Haven't done a ton of research into it, but have you checked to see if the endian-ness matches? It looks like C# (.NET) is little-endian, but the JVM is big-endian. I'm not sure if it swaps it for network transmission, however (then it would just match the hardware). Just an idea. If I find anything additional, I'll update my answer.

Jon Nos
  • 93
  • 2
  • 10
  • 1
    Hi Jon - am not sure on endian-ness. Let me research on it and see. Thanks for your quick response. – csharpnewbie Jan 07 '16 at 19:44
  • I saw you said that the Java side is already in use. Is it only Java code that is doing the decryption already or C++? Another option other than rewriting it in C# is to use already existing code and add a wrapper. ps: I belive the aesAlg.KeySize should be: your Key.Length * 8 = 24*8= 192 instead of 256 – Jon Nos Jan 07 '16 at 20:51
  • Hi Jon - I tried with 192 as well earlier and it still returns some garbage as decrypted value. We have a Java webservice, which returns the data in the encrypted format, which am trying to decrypt from my .Net application. – csharpnewbie Jan 07 '16 at 20:57