Нужно решение для неправильной длины IV в AES

Я пытаюсь реализовать AES на Java, и это код, который я использую:

 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);

Мне нужен этот фиксированный ключ и IV для целей тестирования, но я получаю следующее исключение:

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)

Как я могу использовать этот фиксированный IV с этой реализацией AES? Там в любом случае?


person Shahed    schedule 18.07.2011    source источник
comment
На самом деле меня не смущает эта ошибка, я просто не уверен, как я могу использовать текущий IV, который у меня есть сейчас   -  person Shahed    schedule 18.07.2011


Ответы (5)


Во-первых,

byte[] iv = {00000000000000000000000000000000};

создает массив байтов размером 1, а не массив байтов размером 32 (если это ваше намерение).

Во-вторых, размер IV AES должен составлять 16 байт или 128 бит (что соответствует размеру блока AES-128). Если вы используете AES-256, размер IV должен быть 128 бит, поскольку стандарт AES допускает только 128-битные размеры блоков. Первоначальный алгоритм Rijndael допускал другие размеры блоков, включая 256-битный размер блока.

В-третьих, если вы собираетесь использовать AES-256, это не входит в стандартную комплектацию. Вам необходимо загрузить и установить файлы политик юрисдикции неограниченной силы JCE (прокрутите вниз страницы); Я бы также рекомендовал прочитать прилагаемую лицензию.

Это приведет к следующему изменению вашего кода:

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

Наконец, вектор инициализации должен быть уникальным и непредсказуемым. Последовательность из 16 байтов, где каждый байт представлен значением 0, не является подходящим кандидатом для IV. Если это производственный код, подумайте о том, чтобы получить помощь.

person Vineet Reynolds    schedule 18.07.2011
comment
Большое спасибо за поправку, очень помогло. Не могли бы вы предложить мне, как я могу изменить код для AES-256? На самом деле AES-256 - это то, что я хочу реализовать. - person Shahed; 18.07.2011
comment
Размер IV зависит от размера блока, а не от размера ключа. - person Damien_The_Unbeliever; 18.07.2011
comment
Итак, как я могу изменить размер блока, чтобы использовать мой текущий IV? - person Shahed; 18.07.2011
comment
@Shahed, я не думаю, что реализация JCE позволит это сделать. Обратите внимание на сделанное мной редактирование — стандарт AES допускает только блоки размером 128 бит. - person Vineet Reynolds; 18.07.2011
comment
@Reynolds Спасибо, чувак, я понимаю. Я думаю, что для размера блока более 128 бит мне нужно реализовать Rijndael - person Shahed; 18.07.2011
comment
@Shahed, Bouncycastle поддерживает Rjindael. Кстати, единственные другие размеры блоков в Rjindael — 192 и 256. - person Vineet Reynolds; 18.07.2011
comment
@Reynolds, размер блока 256 меня вполне устроит. Единственная проблема, с которой я могу столкнуться с Bouncycastle, — это сертификация FIPS. Если они не сертифицированы FIPS, моя реализация не будет жаловаться на FIPS. Есть ли у вас какие-либо предложения по этому вопросу? - person Shahed; 18.07.2011
comment
@Shahed, я сомневаюсь, что вы будете соответствовать требованиям FIPS, если будете использовать Rijndael в первую очередь, поэтому использование BouncyCastle спорно; возможно, вам нужно использовать сам AES, который указан в FIP-197 (я размышляю здесь вслух и понятия не имею о требованиях соответствия FIPS, но подозреваю, что прав). - person Vineet Reynolds; 18.07.2011
comment
@Raynolds, на самом деле тест IV и ключ, которые я использую в опубликованном мной примере, взяты из тестового примера FIPS. Ключ и IV являются 32-битными, и IV не работает с моей текущей реализацией AES. Поэтому я подумал, что может быть Rijndael - это решение, но я тоже не уверен. - person Shahed; 18.07.2011
comment
@Shahed, если вы имеете в виду комплект проверки AES, то вы неправильно интерпретируете данные. Похоже, что это шестнадцатеричные значения битов. Каждый символ представляет собой кусок, а не байт. - person Vineet Reynolds; 18.07.2011
comment
@Raynolds, да, это то, что я имел в виду, и ничего себе, я этого не осознавал. В таком случае, не могли бы вы объяснить, как я могу использовать IV = 57f02a5c5339daeb0a2908a06ac6393f в своем тесте? - person Shahed; 18.07.2011
comment
Используйте шестнадцатеричный декодер, например один в кодеке Apache Commons, чтобы декодировать шестнадцатеричное значение и получить массив байтов. Если у вас есть какие-либо дополнительные вопросы, я бы предложил задать их как новый вопрос, поскольку область комментариев на самом деле не предназначена для того, чтобы задавать новые вопросы. - person Vineet Reynolds; 18.07.2011
comment
не могли бы вы взглянуть на мой вопрос. я не могу заставить его работать. stackoverflow.com/questions/34061675/ - person MetaSnarf; 23.12.2015
comment
если размер IV основан на размере блока, то почему mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); возвращает 32? Возвращает ли он размер байтов для генерации байтов IV? - person user4271704; 04.01.2016

Из Расширенного стандарта шифрования:

Стандарт включает три блочных шифра, AES-128, AES-192 и AES-256, взятых из более крупной коллекции, первоначально опубликованной как Rijndael. Каждый из этих шифров имеет размер блока 128 бит с размером ключа 128, 192 и 256 бит соответственно.

(выделение добавлено)

Из вектора инициализации:

Для режимов работы блочного шифра IV обычно равен размеру блока шифра.

Объедините эти два фактора вместе, и вы получите, что IV всегда составляет 128 бит для AES, независимо от размера ключа.

person Damien_The_Unbeliever    schedule 18.07.2011
comment
не могли бы вы взглянуть на мой вопрос. я не могу заставить его работать. stackoverflow.com/questions/34061675/ - person MetaSnarf; 23.12.2015
comment
если размер IV основан на размере блока, то почему mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); возвращает 32? Возвращает ли он размер байтов для генерации байтов IV? - person user4271704; 04.01.2016
comment
@user4271704 user4271704 - RIJNDAEL был основой для AES и действительно использовал разные размеры блоков. Вам нужно решить, используете ли вы AES (всегда 16 байт) или RIJNDAEL. - person Damien_The_Unbeliever; 04.01.2016
comment
Я знаю это, я спрашиваю о том, как рассчитать размер IV? я должен преобразовать размер блока из укусов в байты для размера IV? - person user4271704; 04.01.2016

Почему бы просто не использовать что-то подобное вместо «магических чисел»:

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

Таким образом, вы получаете 16 случайных байтов для вашего iv.

person Markus    schedule 26.06.2014
comment
Нет необходимости генерировать IV вручную. Его можно получить из Cipher после шифрования: cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(); - person Piohen; 23.01.2015
comment
для расшифровки вам понадобится тот же IV, поэтому использование случайного IV не работает, по крайней мере, вы сохраняете сгенерированный IV - person ademar111190; 07.02.2015

AES здесь, вероятно, AES-128, а не AES-256. Вы должны включить дополнительную банку, если хотите включить AES-256, поскольку существуют политики экспортного контроля. Так что сначала проверьте это. В большинстве случаев достаточно AES-128.

Ваш IV не может быть больше 128 бит, т.е. 16 байтов, если это AES-128. Поэтому измените длину вектора инициализации.

Это должно сработать. Также прочтите этот http://en.wikipedia.org/wiki/Initialization_vector.

Предупреждение: Не рекомендуется иметь фиксированный IV. Это должно быть случайным или псевдослучайным, чтобы обеспечить лучшую безопасность.

person Andrew Anderson    schedule 18.07.2011
comment
Не могли бы вы дать мне представление о том, какие банки мне могут понадобиться для включения AES-256? - person Shahed; 18.07.2011
comment
Либо используйте банки из Bouncy Castle с bouncycastle.org/java.html, либо прочитайте эту ссылку java.sun.com/developer/technicalArticles/Security/AES/ Надувной замок может помочь вам, но другая ссылка, я сомневаюсь. Попробуйте погуглить эту банку после прочтения. Надеюсь, поможет. Если мой ответ решил вашу проблему, то примите его! :) - person Andrew Anderson; 18.07.2011
comment
не могли бы вы взглянуть на мой вопрос. я не могу заставить его работать. stackoverflow.com/questions/34061675/ - person MetaSnarf; 23.12.2015

Причина, по которой у меня возникла эта проблема, заключалась в том, что я читал IV как строку и неправильно преобразовывал ее в массив байтов.

Правильно:

Hex.decodeHex(initializationVector.toCharArray()

используя org.apache.commons.codec.binary.Hex

Неправильный способ:

initializationVector.getBytes()

Причина, по которой это было неправильно, заключается в том, что когда вы вызываете getBytes(), он просто берет все биты, представляющие строку, и разрезает их на байты. Таким образом, 0 в конечном итоге записывается как биты, составляющие индекс 0 в таблице Unicode, который равен не 0, а 30, и который будет записан в 2 байта.

И наоборот, здесь вы хотите, чтобы 0 было представлено как байт 00000000.

person Vic Seedoubleyew    schedule 27.04.2019