5

I am trying to decrypt something, which was encrypted using RijndaelManaged of .NET/C#, using Java to decrypt.

The C# program is not mine; I cannot change it to be more interoperable. But I know how it is encrypting:

byte[] bytes = new UnicodeEncoding().GetBytes(password); // edit: built-in is 8chars
FileStream fileStream = new FileStream(outputFile, FileMode.Create);
RijndaelManaged rijndaelManaged = new RijndaelManaged();
CryptoStream cryptoStream = new CryptoStream((Stream) fileStream,
    rijndaelManaged.CreateEncryptor(bytes, bytes), CryptoStreamMode.Write);

I do not know how to decrypt this on the Java end. The closest thing to useful I have found is this blog post, but it is light on actual details and I could not implement a decrypter.

Edit: I'm an idiot and now have it working.

UnicodeEncoding is UTF-16LE, while I was using UTF-8. Switching to the proper encoding when plugging the password in has fixed the program.

I also needed to get BouncyCastle and do Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");

finaledit: Here's the code to decrypt a default RijndaelManaged stream from .NET in Java, assuming it was created using a raw password as the key:

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
String password = "kallisti"; // only 8, 12, or 16 chars will work as a key
byte[] key = password.getBytes(Charset.forName("UTF-16LE"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"),
    new IvParameterSpec(key));
return cipher; // then use CipherInputStream(InputStream, Cipher)

And remember: if you control the C# end, don't use an underived password as your key!

Aleksei Vasiliev
  • 221
  • 1
  • 3
  • 6
  • 1
    unsolicited advice: Don't use `new UnicodeEncoding().GetBytes(password);` to get the bytes for a password. For why, see http://en.wikipedia.org/wiki/PBKDF2 and http://tools.ietf.org/html/rfc2898 especially section 3. Fortunately, both .NET and Java have RFC2898-compliant (aka PKCS5, aka PBKDF2) key derivation classes. Your apps should use them. – Cheeso May 22 '11 at 18:31
  • 1
    See also, http://stackoverflow.com/questions/2375541/password-verification-with-pbkdf2-in-java for a question on PKBDF2 in Java. – Cheeso May 22 '11 at 18:36
  • @Cheeso: The C# app isn't mine; I know using a raw password as a key is a terrible idea. It's also not encrypting anything that actually needs crypto, just a binary blob the app writer didn't want other apps to be able to read. – Aleksei Vasiliev May 24 '11 at 03:38

1 Answers1

3

It's possible using the standard AES decryption. Rijndel is just a superset of AES which is more lax with particular options. See Rijndael support in Java for more details.

From the answer given in the linked question:

byte[] sessionKey = null; //Where you get this from is beyond the scope of this post
byte[] iv = null ; //Ditto
byte[] plaintext = null; //Whatever you want to encrypt/decrypt
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//You can use ENCRYPT_MODE or DECRYPT_MODE
cipher.calling init(Cipher.DECRYPT_MODE, new SecretKeySpec(sessionKey, "AES"), new IvParameterSpec(iv));
byte[] ciphertext = cipher.doFinal(plaintext);
Community
  • 1
  • 1
Chris Dennett
  • 21,465
  • 8
  • 52
  • 84
  • 3
    You have that bit slightly backwards - AES is a subset of Rijndael, particularly on the block size. AES will strictly use a block size of 128 (Reference FIPS 197), whereas Rijndael will give you some flexibility. – vcsjones May 21 '11 at 22:54
  • Thanks for the advice :) Edited answer. Just got it a bit confused. – Chris Dennett May 21 '11 at 22:59
  • "java.security.InvalidKeyException: Invalid AES key length: 8 bytes" "java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long" I have tried this code, but it does not work. I am using an identical password to what the C# end is doing. The C# end is using a raw plaintext password to plug into the cipher; the above code seems to expect to receive a byte array derived from a password. – Aleksei Vasiliev May 21 '11 at 23:02
  • See if this works any better: http://www.cs.ucdavis.edu/~rogaway/ocb/ocb-java/Rijndael.java. It looks like the AES support needs particular key lengths (128, 192, 256, etc.). So you'd have to craft the key on either end to be compatible with AES. – Chris Dennett May 21 '11 at 23:04
  • I know I have to craft the key to be compatible with AES. But I need to do that in a way that is equivalent to what the C# program is doing. The C# program is simply providing RijndaeManaged with an 8-byte password, which is then apparently automatically derived into a proper key. I don't know how to do this in Java. – Aleksei Vasiliev May 21 '11 at 23:10
  • Update: From using DotPeek to look at the Rijndael/RijndaelManaged/etc classes in C#, I believe that .NET's implementation allows 64-bit keys. "private static KeySizes[] s_legalKeySizes = new KeySizes[1]{new KeySizes(128, 256, 64)};" Java's doesn't, since AES is only 128, 192, and 256. The above Rijndael implementation also limits itself to AES's legal key sizes. – Aleksei Vasiliev May 21 '11 at 23:23
  • My above comment was probably wrong and definitely irrelevant to my case but I'm leaving it up. dwi. – Aleksei Vasiliev May 25 '11 at 22:03