Как выбрать подходящий IV (вектор инициализации) для AES / CTR / NoPadding? - PullRequest
31 голосов
/ 05 января 2011

Я хотел бы зашифровать куки, которые пишутся веб-приложением, и я хочу, чтобы размер куки был минимальным, поэтому я выбрал AES / CTR / NoPadding.

Что бы вы порекомендовали использовать в качестве IV, достаточно случайного и при этом приложение не должно иметь состояния. Я знаю, что могу просто сгенерировать случайный IV и добавить его к сообщению, но это увеличит размер куки.

Кроме того, каков рекомендуемый размер IV для 128-битного AES?

Как еще все это делают? Существуют ли "проверенные и верные" способы? Я не хочу изобретать велосипед.

Ответы [ 5 ]

49 голосов
/ 07 января 2011

CTR безопасность требует, чтобы вы никогда не использовали повторно IV для двух шифрований сообщений с одним и тем же ключом. На самом деле это еще строже: режим CTR работает путем шифрования последовательных значений счетчика (IV - просто начальное значение для этого счетчика), и надлежащая безопасность достигается только в том случае, если одно и то же значение счетчика не используется дважды; это означает, что шифрование значения с помощью IV фактически «потребляет» последовательность последовательных значений IV, которую нельзя использовать с другим шифрованием.

Самый простой способ сделать это - использовать криптографически безопасный генератор случайных чисел и создать новый 16-байтовый случайный IV для каждого сообщения. Я подчеркиваю «криптографически безопасный», потому что это важно; базового генератора случайных чисел недостаточно. С Java используйте java.util.SecureRandom. С Win32 звоните CryptGenRandom(). При случайном выборе пространство возможных 128-битных IV достаточно велико, поэтому коллизии крайне маловероятны. Собственно, поэтому AES использует 128-битные блоки (что подразумевает 128-битный IV).

Сущность, которая расшифровывает сообщение, должна знать IV, поэтому вы должны сохранить его вместе с зашифрованным сообщением. Это дополнительные 16 байтов. Я понимаю, что вы должны избегать этих издержек, хотя 16 байт не так уж много для куки. Эффективная максимальная длина файла cookie зависит от веб-браузера, но 4000 символов работают «везде». 16-байтовый IV, при кодировании в символах (например, с помощью Base64), будет использовать около 22 символов, т. Е. Намного меньше, чем 1% от вашего максимального размера cookie: возможно, вы можете себе это позволить?

Теперь мы можем сделать фанк и попытаться уменьшить длину IV с помощью хитрости:

  • Генерация IV с помощью хэш-функции: на стороне сервера, используйте счетчик, который начинается с 0 и увеличивается каждый раз, когда требуется новый IV. Чтобы получить IV, вы хэшируете счетчик с подходящей хеш-функцией, например, SHA-256, и вы сохраняете первые 16 байтов значения хеш-функции. «Рандомизирующих свойств» хеш-функции будет достаточно, чтобы сделать IV достаточно случайным в отношении требований CTR. Для этого требуется криптографически безопасная хеш-функция, следовательно, SHA-256 (избегайте MD5). Затем вам просто нужно сохранить значение счетчика в файле cookie, и счетчик будет короче 16 байтов (например, если у вас не более 4 миллиардов клиентов, счетчик поместится в 4 байта). Однако существует скрытая стоимость: сервер (я полагаю, сервер выполняет шифрование в вашей системе) должен убедиться, что он никогда не использует значение счетчика, поэтому он должен хранить «текущий счетчик» где-то таким образом, который сохраняется в течение более сервер перезагружается, а также не выходит из строя, если вы масштабируете до нескольких внешних интерфейсов. Это не так просто, как кажется.

  • Используйте внешнее уникальное значение: возможно, cookie может быть частью контекста, который предоставляет достаточно данных для генерации значения, которое будет уникальным для каждого шифрования. Например, если запрос также содержит (в открытом виде) «идентификатор пользователя», вы можете использовать идентификатор пользователя в качестве источника IV. Настройка аналогична приведенной выше: вы получаете все эти данные, помещаете их в SHA-256, и первые 16 байтов вывода SHA-256 - это то, что вам нужно. Это работает, только если эти данные не изменяются для данного зашифрованного сообщения, и если оно действительно уникально. Это редкое явление: например, «идентификатор пользователя» подходит для этого только в том случае, если нет необходимости повторно зашифровывать новое сообщение для того же пользователя, и если никогда не существует вероятность повторного использования идентификатора пользователя (например, старый пользователь выходит, новый пользователь приходит и выбирает теперь свободный идентификатор пользователя).

Использование случайного 16-байтового IV, сгенерированного с помощью криптографически безопасного PRNG, все еще остается «безопасным» способом, и я рекомендую его. Если в файле cookie недостаточно места, это означает, что вы приближаетесь к пределу в 4 КБ, и в этот момент вы можете захотеть использовать сжатие (для данных до шифрования; после шифрования сжатие очень очень вряд ли сработает). Используйте zlib (в Java вы можете получить доступ к zlib через java.util.zip).

Предупреждение: во всех вышеперечисленных случаях я не говорю что-нибудь о том, помогает ли шифрование файлов cookie обеспечивать любые характеристики безопасности, которые вы пытаетесь достичь. Обычно, когда требуется шифрование, вам действительно нужны и шифрование, и целостность, а затем вам следует использовать режим комбинированного шифрования и целостности. Найти GCM и CCM . Кроме того, шифрование cookie в основном подходит для одной цели, которая заключается в том, чтобы избежать затрат на хранение на стороне сервера части пользовательских данных. Если вы хотите зашифровать куки для чего-то другого, например, аутентифицировать действительного пользователя, тогда вы делаете это неправильно: шифрование не является подходящим инструментом для этого.

4 голосов
/ 05 января 2011

У меня нет прямого ответа на ваш вопрос, но есть несколько вещей, которые нужно добавить.

Прежде всего, шифрование куки не имеет смысла для меня. Если вы хотите сохранить конфиденциальность ваших данных, вы не должны хранить их в cookie-файлах. Если вы хотите сохранить целостность (т. Е. Невозможно изменить содержимое файла cookie), вам следует использовать хеш с ключами (например, HMAC).

Еще одно замечание: никогда не используйте IV, который для удобства равен 0.

IV равны по размеру с вашего блока. В случае AES-128 размер блока равен 128, размер ключа равен 128, и, следовательно, IV равен 128 битам.

Лучший способ сделать это - создать случайный ключ AES и использовать его в качестве IV. Этот случайный IV может быть общедоступным, если он не используется повторно в последующих шифрованиях с тем же ключом

редактировать

Возможно, вы захотите просмотреть эту вики-страницу для получения дополнительной информации о том, какой режим использовать. Однако никогда не используйте ECB, если вы не уверены, что должны его использовать. И даже тогда сверьтесь с экспертом. CBC, насколько я знаю, самый безопасный (вместе с PCBC).

http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation

2 голосов
/ 05 января 2011

Если вы не сделаете IV случайным (т.е. вы используете какую-то повторяющуюся группу чисел), вам будет легче определить ключ, если cookie всегда начинаются с одного и того же открытого текста.

Размер IV для AES-128 составляет 128 бит. IIRC, IV такой же размер, как и блок шифра. 128 бит это 16 байтов. 32 байта, если вы храните его в виде шестнадцатеричной строки ASCII. Это действительно слишком много? 32 байта в этот день и возраст совсем немного ...

0 голосов
/ 27 августа 2017

Можно избежать случайного IV, используя CBC и сохраняя HMAC перед сообщением.Использование случайно выбранной константы IV в порядке.Но вы должны быть уверены, что сообщения все разные.

Это тот случай, когда зашифрованное сообщение всегда отличается.Лицензионный ключ с серийным номером будет соответствовать этому критерию.Файл cookie с идентификатором пользователя или идентификатором сеанса также будет ему соответствовать.

Вы можете использовать CBC со случайной константой IV, если вы храните hmac перед сообщением.Хеш будет суммировать все вариации в сообщении в первом блоке.Вы также можете добавить несколько случайных байтов или предпочтительно серийный номер, если вы можете быть уверены, что он будет уникальным или не будет использоваться повторно в течение очень длительного времени.

Даже не думайте об использовании CTR с постоянным IV.

0 голосов
/ 06 января 2011

Включите большое случайное число с cookie. 64 или 128-битное число, вероятно, достаточно велико. Он должен быть достаточно большим, чтобы было очень трудно получить дубликаты. Не забудьте положить достаточно энтропии в этом числе. Не просто используйте gettime (). Если у вас есть доступ к CRNG, используйте его здесь.

Сохраните 256-битный мастер-ключ вместе с вашим приложением. Используйте SHA256 для получения вашей ключевой информации. Опять же, используйте CRNG для этого.

$keyblob = sha256( concat("aeskeyid", $masterkey , $randomnumberwithcookie ) )
$aeskey = $keyblob[0..15]
$aesiv = $keyblob[16..31]

Вы также можете получить ключ для HMAC.

$mackeyblob = sha256( concat("hmackeyid", $masterkey , $randomnumberwithcookie ) )

В качестве альтернативы вы можете объединить две вышеупомянутые операции хеширования в одну, используя SHA512.

$keyblob = sha512( concat("randomkeyid", $masterkey , $randomnumberwithcookie ) )
$aeskey = $keyblob[0..15]
$aesiv = $keyblob[16..31]
$hmackey = $keyblob[32..63] 
...