2

I'm using javax.crypto to do some cryptographic operations in my application. I use AES for encryption/decryption like this:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] cipherText = cipher.doFinal(plaintext);
byte[] iv = cipher.getIV();   //The problematic IV

The generated IV is prepended to the ciphertext after the enncryption.

The Java specification clearly says that the IV must be generated automatically if its is not provided to cipher.init():

If this cipher requires any algorithm parameters that cannot be derived from the given key, the underlying cipher implementation is supposed to generate the required parameters itself (using provider-specific default or random values)

But sometimes I end up with ciphertexts that don't seem very random, such as this one (in base64):

    AAAAAAAAAAAAAAAAAAAAAOmI9Qh1fMiG6HV3tKZK3q5sCruaPdYqYnoUOM00rs6YZY3EvecYfR6vTHzZqk7ugknR9ZMipedYWJB1YOLmSYg=

The bunch of A characters at the front is the IV. The IV is actually 16 zero-bytes.

Most of the time, the library generates proper, random IVs, but sometimes, it just pops out zeros. Why is this happening?

nidzo732
  • 721
  • 1
  • 8
  • 10
  • I have been looking into this issue, it seems like the old (4.3) `AndroidOpenSSL` implementations did this, but this seems to have been fixed in newer versions (7.0 is fine). I notice you don't specify a provider. Would be interested to know more about the nature of _"sometimes"_ in your post. – Dori Sep 28 '17 at 13:22
  • Have spoken about this issue a little here https://doridori.github.io/Android-Security-Beware-of-the-default-IV/ – Dori Sep 28 '17 at 13:45

2 Answers2

4

Some (most?) providers simply use a zero-byte filled IV as their default. My emphasis of your quote:

If this cipher requires any algorithm parameters that cannot be derived from the given key, the underlying cipher implementation is supposed to generate the required parameters itself (using provider-specific default or random values)

When you look to the front of your ciphertext, you see that it starts with a bunch of "A" characters. It's Base 64 for 0x00 bytes.

If you want to make sure that you have a random IV, you have to generate it yourself:

SecureRandom r = new SecureRandom();
byte[] ivBytes = new byte[16];
r.nextBytes(ivBytes);

cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(ivBytes));
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • I'm aware that I can generate an IV myself, that's what I'm going to do from now on, as I can't trust the library to do it for me anymore. I'm just curious that this only happens on some devices, most of the time I get ciphertexts with proper random IVs like this one: `7TUKMTxQTicdblLvBw0+33MCNoeONwCx5bnNKMen6hrecT4SsOpPZUpvGzdfVf3d5KUZnlXUvU/PLt3ngv5hK9pUx98Oi3WblWnY2yN+tX0=`. As you can see, the first 16 bytes are random. But some devices generate bad non-random IVs. Is this the fault of that particular manufacturer's ROM, or the problem with an old Android version? – nidzo732 Jun 25 '15 at 10:56
  • 1
    I'm not familiar with JCE providers on Android, but I would think that manufacturers have a say in what providers they include in the ROM and which one is the default provider. It's not the first time that a manufacturer has proved a bad sense of security. – Artjom B. Jun 25 '15 at 11:16
  • 2
    Note that you will get `Caller-provided IV not permitted when encrypting.` unless you disable [RandomizedEncryptionRequired](https://developer.android.com/reference/android/security/keystore/KeyGenParameterSpec.Builder.html#setRandomizedEncryptionRequired(boolean)) on your Cipher - interesting documentation at that link. – Tom K Jan 25 '17 at 04:53
-2

The IV is not secure. It is prepended to the cyphertext, so any attacker only has to read the cyphertext and look at the first 16 bytes to see what it is.

It is not a good idea to always use the same IV -- it effectively turns the first block of your actual cyphertext into ECB mode, which is insecure.

I recommend generating your own random IV. You do not need to use a cryptographically secure RNG, since an attacker can see it anyway. You just need to avoid using the same IV for different messages. Even something simple like 8 bytes of random with an 8 byte (64 bit) counter will be enough to avoid the ECB effect. Change the key before the counter rolls over, and reset the counter to 0 when you change the key.

rossum
  • 15,344
  • 1
  • 24
  • 38
  • 1
    You *do* need to use a cryptographically strong RNG, even though the IV is publicly visible. Cf. http://stackoverflow.com/questions/3008139/why-is-using-a-non-random-iv-with-cbc-mode-a-vulnerability, for example. You want good, strong, random IVs. Don't use weak IV generation. – Jim Flood Jun 24 '15 at 22:48
  • You are right, thanks for the correction. The IV needs to be both unique *and* unpredictable. – rossum Jun 26 '15 at 09:58