I want to encrypt data using AES in java, and I want to intialize the cipher with Initialisation Vector. Can I use 256-bits IV ? Or I must use only 128-bits IV ?
4 Answers
The IV depends on the mode of operation. For most modes (e.g. CBC), the IV must have the same length as the block. AES uses 128-bit blocks, so a 128-bit IV. Note that AES-256 uses a 256-bit key (hence the name), but still with 128-bit blocks.
AES was chosen as a subset of the family of block ciphers known as Rijndael. That family includes no less than 15 variants, for three possible block sizes (128, 192 and 256 bits) and five possible key sizes (128, 160, 192, 224 and 256 bits). AES, as standardized by NIST, includes only three variants, all with 128-bit blocks, and with keys of 128, 192 or 256 bits.
To further confuse things, some software frameworks got it wrong; e.g. PHP uses "MCRYPT_RIJNDAEL_128" to designate Rijndael with 128-bit keys and 128-bit blocks (i.e. the same thing as AES-128), and "MCRYPT_RIJNDAEL_256" for Rijndael with 256-bit keys and 256-bit blocks (i.e. not one of the AES variants, and in particular not at all AES-256).
-
Does the choice of
MCRYPT_RIJNDAEL_128
vsMCRYPT_RIJNDAEL_256
really affect the key size as well? AFAIR it only affects the block size and the key size is determined by the key you pass to the encrypt/decrypt functions. Jun 4, 2015 at 14:18 -
IIRC,
MCRYPT_RIJNDAEL_128
is actually Rijndael-128/256, i.e. AES-256. (I don't really have a good way to re-check this right now, though, so I could be mistaken.) Jun 4, 2015 at 17:41 -
2@IlmariKaronen That choice is made when the key is supplied. I think they now require precise key sizes 128, 192 and 256. Before they zero (right) padded keys up to 128 bit, 192 bit and 256 and removed bits from keys above 256 bit. The
mcrypt
PHP extension was clearly not made by professionals andmcrypt
as C library has been abandoned a very long time ago (some people are trying to resurrect it). It doesn't have any padding modes for block cipher modes of encryption either. Jun 5, 2015 at 8:22 -
2PHP did arguably not get it wrong. The block size is in the description of the cipher, the key size is configured using the key. The problem is that most people equate Rijndael with AES. In hindsight there are so many users doing that (including the ones that wrote the PHP mcrypt sample code initially!) that the API should be amended to include AES constants (i.e. map a new constant
MCRYPT_AES
toMCRYPT_RIJNDAEL_128
). Jun 5, 2015 at 9:50
The IV handling in Java is dependent on the cryptographic provider that is used. The SUN provider that comes with the OpenJDK / Oracle runtimes is rather strict; it requires the IV to be the same size as the block size for most modes of operation. This is true even for CTR mode where you might have expected that supplying a nonce - the first / leftmost bytes of the counter - should be sufficient. ECB mode of course does not require an IV, so it will throw an exception if you try and supply one.
The block size of AES is always 128 bits, so a 256 bit IV is not possible for most modes of operation. As already noted in a few answers, Rijndael can be configured with a block size of 256 bit, but Rijndael is not included in the standard runtime. You would need an additional provider or library such as Bouncy Castle to use Rijndael. The block cipher AES doesn't use an IV as input, which is also why supplying an IV for ECB mode fails. Some other languages/runtimes simply ignore the IV for ECB
Now there is one cipher that does allow you to specify a 256 bit IV (or actually: nonce) and that is GCM. GCM works best with a nonce of 12 bytes though. GCM converts data - includes the nonce - to a 128 bit counter for CTR mode internally.
Note that increasing the IV size does not auto-magically make the algorithm more secure. If you have 256 bit input for an IV then you could use SHA-256 bit on the input and take the 128 leftmost bits instead.
As we were talking Java, here's some code, you can fiddle with the IV size and try some algorithms such as "AES/CFB/NoPadding"
yourself. Note that the static IV's used in the code are for demonstration purposes only. CTR requires a unique IV, CBC requires a fully unpredictable IV (which is commonly fulfilled by randomizing all 16 bytes for AES).
SecretKey aesKey = new SecretKeySpec(new byte[256 / Byte.SIZE], "AES");
byte[] pt = "owlstead".getBytes(StandardCharsets.US_ASCII);
{
// === CBC mode requires an IV of the same size as the block size
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
// changing the IV size will result in an exception
byte[] ivBytes = new byte[c.getBlockSize()];
IvParameterSpec iv = new IvParameterSpec(ivBytes);
c.init(Cipher.ENCRYPT_MODE, aesKey, iv);
byte[] ct = c.doFinal(pt);
System.out.println(Hex.toHexString(ct));
}
{
// === CTR mode actually requires a complete IV in Java
// Java (or actually, the SUN provider) requires a 128 bit IV instead of just a nonce
Cipher c = Cipher.getInstance("AES/CTR/NoPadding");
// changing the IV size will result in an exception
byte[] ivBytes = new byte[c.getBlockSize()];
IvParameterSpec iv = new IvParameterSpec(ivBytes);
c.init(Cipher.ENCRYPT_MODE, aesKey, iv);
byte[] ct = c.doFinal(pt);
System.out.println(Hex.toHexString(ct));
}
{
// === GCM mode can do it!
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
byte[] ivBytes = new byte[256 / Byte.SIZE];
GCMParameterSpec gcmSpecWithIV = new GCMParameterSpec(128, ivBytes);
c.init(Cipher.ENCRYPT_MODE, aesKey, gcmSpecWithIV);
byte[] ct = c.doFinal(pt);
System.out.println(Hex.toHexString(ct));
}
{
// === java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
byte[] ivBytes = new byte[c.getBlockSize()];
IvParameterSpec iv = new IvParameterSpec(ivBytes);
c.init(Cipher.ENCRYPT_MODE, aesKey, iv);
byte[] ct = c.doFinal(pt);
System.out.println(Hex.toHexString(ct));
}
-
Thank you @MaartenBodewes for the code. I use SunJCE provider and I have to implement a crypto-plugin with AES in CTR mode, so I am satisfied with this provider.– HakimJun 5, 2015 at 9:41
-
You're welcome. In that case you can only use 128 bits IV, as indicated. Note that the static IV is for demonstration purposes only, of course. Amended answer to make sure nobody uses copy and paste. Jun 5, 2015 at 9:43
You must use a 128 bit IV. For CBC mode IV must match the block size, which is always 128 bits for AES.
Rijndael, the winning AES candidate, is defined for 128 and 256 bit blocks, but only 128 bit blocks were standardized as AES. Some libraries support Rijndael with 256 bit blocks, but then you're no longer using AES.
If you need a longer IV for some reason, you can use a KDF or hash to turn the original key and the IV into the key you actually use for AES.
-
2This isn't true for all modes. For instance, GCM recommends a 96-bit IV.– cpastJun 4, 2015 at 15:26
The purpose of the IV is to "mix it up" a bit.
Without it, messages with the same first block of plaintext would all share the same first block of ciphertext. That scenario isn't that uncommon, consider files that start off with standard declarations about their filetype or the way SMTP use things like RCPT TO:, MAIL FROM: etc as common elements. 128bits (the block size of AES) is small, so this kind of thing would happen.
There are different modes of operation, but using CBC as the simplest (and maybe still most common?) the ciphertext from one block is used to feed into the next, i.e. the encrypted output (ciphertext) made from the first block of plaintext is used to XOR the plaintext of block 2 (before that is then encrypted). The ciphertext of each block is used to XOR (exlusive OR) the plaintext of the next block, and so the name Cipher block CHAINING. The issue is the first block has no block to precede it (well in CBC anyway...)
This is where the problem first described is an issue -- messages with the same first block of plaintext would all share the same first block of ciphertext if the same key was used to encrypt them.
To avoid that problem an IV (initialization vector) is used. This is a block of material can be used to XOR (exclusive OR) the very first block to start the chain. The IV is sent with the message, otherwise it would be impossible to start decryption.
Even re-encrypting the same message over and over again with the same key, the first encrypted block would be different each time, and so by chaining, the whole encrypted message would different each time.
If you consider what is being done with the IV, in my CBC example, it makes no sense at all to discuss an IV of any size greater or less than the 128bit block size, because that is the size of the first block you need to "mix up" and from then onwards you use the previous ciphertext to chain it. (OK this isn't true for all modes, some IVs might need to be smaller than the first block, but let's just consider CBC for now). So for CBC the IV must be the same as the blocksize, which in AES is always 128bit (regardless of the keysize).
The benefit for security isn't as much considering the IV length, don't think that a longer IV must mean better security, the IV is not the key!
The issue with IVs is more what/how you generate your IVs. They must be good quality (i.e. uniform pseudo-random material statistically unrelated to any previously used IVs), if you have either a poor IV generation scheme or a poor key schedule you can undermine the security, potentially opening it up to cryptanalysis based on statistical techniques.
What I really would like to state is that Cryptography is a bit complicated :) and even making a best intentioned mistake has led to some catastrophic consequences. Some otherwise good schemes have been completely ruined by small implementation mistakes. Remember WEP for wireless anyone?
If you don't fully and deeply understand all the factors involved, please stick to the standards, and use well used (well peer-reviewed) libraries and established practices.
Trying to do something clever, even with the very best intentions, is extremely dangerous unless you understand all the consequences. What I am trying to very politely say is that if you need to ask a question like: what is the IV size to use, you shouldn't be trying to experiment with how to implement, just stick to the standard values.
Best wishes with your coding, enjoy...