jlars62
jlars62

Reputation: 7383

Converting C# cryptography to Java

I have been tasked with converting a C# cryptography method to Java and am stuck. I know the C# codes works, but I am having trouble getting my Java code to work.

Here is the C# code:

private const int Nb = 4; // Legal values:  4 = 128-bit blocks

public static void Decrypt(byte[] input, Stream output)
    { 
        var s1 = new MemoryStream(input);
        const int BufferSize = 1024;
        byte[] buffer = new byte[BufferSize];

        input.Read(buffer, 0, 4);
        int pad = buffer[3];

        RijndaelManaged rijndael = new RijndaelManaged();
        rijndael.BlockSize = Nb * 32;
        rijndael.KeySize = buffer[1] * 32;

        rijndael.Mode = CipherMode.ECB;
        rijndael.Padding = PaddingMode.None;

        byte[] key = GetKey(buffer[1]);
        ICryptoTransform decryptor = rijndael.CreateDecryptor(key, GetIV());

        int bytes;
        while ((bytes = input.Read(buffer, 0, BufferSize)) > 0)
        {
            for (int i = 0; i < bytes; i += rijndael.BlockSize)
            {
                decryptor.TransformBlock(buffer, i, rijndael.BlockSize, buffer, i);
            }
            output.Write(buffer, 0, bytes);
        }
        output.SetLength(output.Length - pad - 4);
    }

And here is my attempt in Java so far:

public static String decrypt(byte[] input) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
    byte[] key = getKey(input[1]);
    SecretKey secretKey = new SecretKeySpec(key, 0, key.length, "AES/ECB/NoPadding");
    cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(getIV()));
    // remove first 4 since C# code reads past those
    byte[] finalDecoded = Arrays.copyOfRange(input, 4, input.length);
    byte[] decryptedVal = cipher.doFinal(finalDecoded);
    return new String(decryptedVal);
}

Some More Information

Where am I going wrong in the Java code?

Upvotes: 4

Views: 423

Answers (1)

Sabre
Sabre

Reputation: 359

You are getting the error ECB mode cannot use IV because ECB doesn't perform chaining, so IV is meaningless. The difference is Java throws an error whereas C# just ignores the IV.

When I remove this code : new IvParameterSpec(getIV()) I get this error: Wrong algorithm:AES or Rijndaelrequired

If I change the algorithm to only AES or only Rijndael I get this error: Input length must be multiple of 16 when decrypting with padded cipher.

You had the right idea, but you went too far. This error is only to do with the SecretKeySpec, which doesn't care about the mode, but just the algorithm. Cipher is where you specify mode. Also, Rijndael and AES aren't quite the same thing.

So start by changing the first few lines to this:

Cipher cipher = Cipher.getInstance("Rijndael/ECB/NoPadding");
byte[] key = getKey(input[1]);
SecretKey secretKey = new SecretKeySpec(key, 0, key.length, "Rijndael");
cipher.init(Cipher.DECRYPT_MODE, secretKey);

Note that since you're using the entire key you don't need the offset and length arguments, so you can just do

SecretKey secretKey = new SecretKeySpec(key, "Rijndael");

The original C# code has some not-so-obvious behavior:

while ((bytes = input.Read(buffer, 0, BufferSize)) > 0)
{
    for (int i = 0; i < bytes; i += rijndael.BlockSize)
    {
        decryptor.TransformBlock(buffer, i, rijndael.BlockSize, buffer, i);
    }
    output.Write(buffer, 0, bytes);
}

When the loop gets to the end of the input, it will copy however much is left of it into buffer. Unless the last Read was exactly 1024 bytes, there will be residue from the previous loop (or from initialization if it gets the whole input with one Read operation) after the end of the input.

The inner loop decrypts one 16-byte block at a time. In the case of your 420-byte example, the last block will consist of the remaining 4 bytes of input and 12 more bytes of garbage. But it's okay because the output.Write only writes bytes number of bytes to truncate the garbage. You will have to replicate this behavior in your Java code.


Side note: do you absolutely have to use ECB? It's not very secure...

Upvotes: 6

Related Questions