Mehdi Pourfar
Mehdi Pourfar

Reputation: 508

decrypt aes encrypted bytes with mode ctr in java

Let me explain shortly. I have this encryptor in python:

It uses PyCrypto library.

from Crypto import Random
from Crypto.Cipher import AES
from Crypto.Util import Counter

iv = Random.new().read(8)
encryptor = AES.new(
    CRYPTOGRAPHY_KEY,    // 32 bytes
    AES.MODE_CTR,
    counter=Counter.new(64, prefix=iv),
)

and I want to have a decryptor for it in java.

I wrote this code but it raises java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long.

SecretKeySpec key = new SecretKeySpec(KEY, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);

P.S. I should mention that I'm not an experienced Java developer.


Update. The problem was with initialization vector. Special thanks to @Andy for his time.

Solution:

byte[] nonceAndCounter = new byte[16];
System.arraycopy(iv, 0, nonceAndCounter, 0, 8);
nonceAndCounter[15] = (byte) 1; // PyCrypto's default initial value is 1
IvParameterSpec ivSpec = new IvParameterSpec(nonceAndCounter);

Upvotes: 4

Views: 2996

Answers (2)

Andy
Andy

Reputation: 14184

I believe you are encountering an issue where Java expects the IV to be fully-formed (16 bytes) when using AES/CTR/NoPadding while Python accepts an 8 byte prefix and generates its own counter in the other 64 bits (8 bytes).

I have example code for cross-platform compatibility in this answer. The relevant section is:

    byte[] cipher_key = org.bouncycastle.util.encoders.Hex.decode("0123456789ABCDEFFEDCBA9876543210");
    final int HALF_BLOCK = 64;
    byte[] salt = org.bouncycastle.util.encoders.Hex.decode("0123456789ABCDEF");
    byte[] nonceAndCounter = new byte[16];
    System.arraycopy(salt, 0, nonceAndCounter, 0, ((int) (HALF_BLOCK / 8)));
    IvParameterSpec iv = new IvParameterSpec(nonceAndCounter);
    Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC");
    SecretKeySpec key = new SecretKeySpec(cipher_key, "AES");
    cipher.init(Cipher.ENCRYPT_MODE, key, iv);

Upvotes: 1

ram
ram

Reputation: 1169

If you are trying to use AES-256 (you are using 32 bytes key), then you need to have Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files installed. And this has to be installed wherever this application needs to run. If you plan to distribute this application and thus you don't have control over possible java runtimes, then you have to use other libraries (like Bouncy Castle) through their own API, not through JCE API. (i.e. using Bouncy Castle as a provider like "BC" in JCE would result in the same problem.)

EDIT: First you said you are getting invalid key size exception, now changed the question. For the java.security.InvalidAlgorithmParameterException case, the problem is AES-256 has block size of 16, not 32. 256 represents the key size, not block size. AES (128, 192, 256) always has block size of 128. Thus, the iv must be 16 bytes.

EDIT 2: Not the cause of this exception but another possible problem with your code is, where do you get the iv in Java? Do you generate it random as you do in Python? That would be a big mistake since you have to use the same IV during decryption to make it work. Keep this in mind.

Upvotes: 3

Related Questions