Need solution for wrong IV length in AES
Asked Answered
C

6

10

I'm trying to implement AES in Java and this is the code I use:

 byte[] sessionKey = {00000000000000000000000000000000};
 byte[] iv = {00000000000000000000000000000000};
 byte[] plaintext = "6a84867cd77e12ad07ea1be895c53fa3".getBytes();
 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

 cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sessionKey, "AES"), new IvParameterSpec(iv));
 byte[] ciphertext = cipher.doFinal(plaintext);

 cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sessionKey, "AES"), new IvParameterSpec(iv));
 byte[] deciphertext = cipher.doFinal(ciphertext);

I need this fixed key and IV for test purpose but I get the following exception:

Exception in thread "main"
java.security.InvalidAlgorithmParameterException: 
  Wrong IV length: must be 16 bytes long    at
com.sun.crypto.provider.SunJCE_h.a(DashoA12275)     at
com.sun.crypto.provider.AESCipher.engineInit(DashoA12275)   at
javax.crypto.Cipher.a(DashoA12275)  at
javax.crypto.Cipher.a(DashoA12275)  at
javax.crypto.Cipher.init(DashoA12275)   at
javax.crypto.Cipher.init(DashoA12275)

How can I use this fixed IV with this implementation of AES? Is there any way?

Catfall answered 18/7, 2011 at 7:30 Comment(1)
Actually Im not confused with this error, im just not sure how i can use the curretn IV i have nowCatfall
P
46

Firstly,

byte[] iv = {00000000000000000000000000000000};

creates a byte array of size 1 and not a byte array of size 32 (if that is your intention).

Secondly, the IV size of AES should be 16 bytes or 128 bits (which is the block size of AES-128). If you use AES-256, the IV size should be 128 bits large, as the AES standard allows for 128 bit block sizes only. The original Rijndael algorithm allowed for other block sizes including the 256 bit long block size.

Thirdly, if you are intending to use a AES-256, this does not come out of the box. You need to download and install the JCE Unlimited Strength Jurisdiction Policy Files (scroll to the bottom of the page); I would also recommend reading the accompanying license.

This would result in the following change to your code:

byte[] iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

Finally, the initialization vector is meant to be unique and unpredictable. A sequence of 16 bytes, with each byte represented by a value of 0, is not a suitable candidate for an IV. If this is production code, consider getting help.

Precursor answered 18/7, 2011 at 7:44 Comment(15)
Thanks a lot for the correction, that really helped. Can you please suggest me how can i change the code for AES-256? Actually AES-256 is what i want to implement.Catfall
The IV size is based around the block size, not the key size.Exeunt
So how i can modify the block size to use my current IV?Catfall
@Shahed, I don't think the JCE implementation will allow for that. Note the edit I made - the AES standard allows for only block sizes of 128 bits.Precursor
@Reynolds Thanks man, I understand. I guess for block size more than 128 bit, i need to implement RijndaelCatfall
@Shahed, Bouncycastle supports Rjindael. Btw, the only other block sizes in Rjindael are 192 and 256.Precursor
@Reynolds, Block size of 256 should be fine for me. The only problem I may face with Bouncycastle will be FIPS certification. If they are not FIPS certified, my implementation will not be FIPS complaint. Do you have any suggestion regarding this issue?Catfall
@Shahed, I doubt you will be FIPS compliant if you use Rijndael in the first place so BouncyCastle usage is moot; perhaps you need to use AES itself which is specified in FIP-197 (I'm thinking aloud here and I have no idea about the FIPS compliance needs, but I suspect I am right).Precursor
@Raynolds, Actually the test IV and key im using on the example i posted, are from FIPS test case. The key and IV both are 32 bit and the IV is not working with my current AES implementation. So I thought may be Rijndael is the solution but im not sure either.Catfall
@Shahed, if you are referring to the AES validation suite, then you are misinterpreting the data. Those appear to be hex-encoded values of the bits. Each character represents a nibble and not a byte.Precursor
@Raynolds, Yes, that is what i was referring to and wow, i did not realize that. In that case, can you please explain how can i use IV = 57f02a5c5339daeb0a2908a06ac6393f in my test?Catfall
Use a Hex decoder, like the one in Apache Commons Codec to decode the hex-encoded value and to get the byte array. If you have any further questions, I would suggest asking that as a new question, as the comments area is not really meant for asking new questions.Precursor
can you please take a look at my question. i cant seem to make it work. #34062175Arlo
if IV size is based on block size so why mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); returns 32? Does it return the bytes size to generate the IV bytes?Jackquelinejackrabbit
This answer & comments solved my headache. Wasted 2days because of wrong iv issues. Really thanks!.Deltadeltaic
E
17

From Advanced Encryption Standard:

The standard comprises three block ciphers, AES-128, AES-192 and AES-256, adopted from a larger collection originally published as Rijndael. Each of these ciphers has a 128-bit block size, with key sizes of 128, 192 and 256 bits, respectively

(Emphasis added)

From Initialization Vector:

For block cipher modes of operation, the IV is usually as large as the block size of the cipher

Combine those two factors together, and you get that the IV is always 128 bits for AES, independent of the key size.

Exeunt answered 18/7, 2011 at 7:41 Comment(4)
can you please take a look at my question. i cant seem to make it work. #34062175Arlo
if IV size is based on block size so why mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); returns 32? Does it return the bytes size to generate the IV bytes?Jackquelinejackrabbit
@Jackquelinejackrabbit - RIJNDAEL was the basis for AES, and did indeed use different block sizes. You need to decide whether you're doing AES (16 bytes always) or RIJNDAEL.Exeunt
I know that, I am asking about how to calculate IV size? should I convert the block size from bites into bytes for IV size?Jackquelinejackrabbit
M
2

AES here is probably AES-128 not AES-256.You must include extra jar if you want to enable AES-256 as there are export control policies in place. So check that first. AES-128 is enough in most cases.

Your IV can't be more than 128 bits i.e. 16 bytes when it is AES-128. So change the initialization vector length.

That must work. Also, read this http://en.wikipedia.org/wiki/Initialization_vector

Warning: It is not a good practice to have a fixed IV. It must be random or pseudorandom to offer better security.

Mercantile answered 18/7, 2011 at 7:41 Comment(3)
Can you please give me any idea on what jars i might need to enable AES-256?Catfall
Either use jars from Bouncy castle from bouncycastle.org/java.html or read this link java.sun.com/developer/technicalArticles/Security/AES/… Bouncy castle may help you but the other link, I doubt. Try googling for that jar after reading it. Hope it helps. If my answer solved your problem, then accept it! :)Mercantile
can you please take a look at my question. i cant seem to make it work. #34062175Arlo
C
2

Why not just use something like that instead of using "magic numbers":

SecureRandom random = new SecureRandom();
byte[] iv = random.generateSeed(16);

So you get 16 random bytes for your iv.

Codicodices answered 26/6, 2014 at 15:55 Comment(2)
There's no need to generate IV by hand. It can be obtained from Cipher after encryption: cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();Ventricle
to decrypt you will need the same IV, so uses the random IV do not works at least you save the generated IVOestrone
U
2

The reason why I had this problem was because I was reading the IV as a String, and converting it to a byte array the wrong way.

Right way:

Hex.decodeHex(initializationVector.toCharArray()

using org.apache.commons.codec.binary.Hex

Wrong way:

initializationVector.getBytes()

The reason this was wrong, is because when you call getBytes(), it just takes all bits that represent the string and cuts them into bytes. So 0 ends up being written as the bits that make up the index of 0 in the Unicode table, which is not 0 but 30, and which would be written on 2 bytes.

Conversely, what you want here is actually that 0 be represented as the byte 00000000.

Unconditioned answered 27/4, 2019 at 20:47 Comment(1)
The only thing that worked for me.. also had to do this to create the SecretKeySpecCrumhorn
U
0

Not related to this but faced same issue.

IvParameterSpec ivParameterSpec = new IvParameterSpec(key1.getBytes("UTF-8")); SecretKeySpec skeySpec = new SecretKeySpec(key2.getBytes("UTF-8"),"AES"); The mistake I made was key1 and key2 were Strings of length greater than 16. Changing their length to 16 fixed it.

Unchartered answered 7/1, 2022 at 8:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.