Правильная реализация шифрования AES 128 с вектором инициализации и заполнением - PullRequest
5 голосов
/ 06 июля 2019

Я реализовал 128-битное шифрование AES с использованием вектора инициализации и заполнения, как видно из кода ниже.Я использую ColdFusion, но я не думаю, что это имеет значение.Зашифрованный результат показывает некоторые повторяющиеся шаблоны, которые я бы не ожидал, но опять же я не знаю характеристик правильного вывода для этого.Я правильно делаю вектор инициализации и заполнение?

<code><!---
To encrypt this, for example:
    "String1"
Prefix the string with an Initialization Vector of 16 random characters,
plus enough padding ("000000001") to make the entire string a multiple of 16 characters (32 characters, here)
    "HoMoz4yT0+WAU7CX000000001String1"
Now encrypt the string to this (64 characters):
    "Bn0k3q9aGJt91nWNA0xun6va8t8+OiJVmCqv0RzUzPWFyT4jUMzZ56pG5uFt6bGG"
--->

<cfoutput>

    <cfset EncryptKey="LpEecqQe3OderPakcZeMcw==">

    <cfloop index="StringToEncrypt" list="String1,String2,String3,String3">
        <!--- Make random Initialization Vector (IV) of length 16 
        (create it from GenerateSecretKey(), but GenerateSecretKey is NOT the key that we encrypt/decrypt with) --->
        <cfset IV=left(GenerateSecretKey("AES",128),16)>
        <!--- Pad the string so its length is a multiple of 16 --->
        <cfset padlength=16 - (len(StringToEncrypt) mod 16)>
        <cfset padding=repeatstring("0",padlength-1) & "1">
        <cfset NewStringToEncrypt=IV & padding & StringToEncrypt>
        <cfset EncryptedString=encrypt(NewStringToEncrypt,EncryptKey,"AES","Base64")>
<pre>Original string: #StringToEncrypt#
StringToEncrypt: #NewStringToEncrypt#
EncryptedString: #EncryptedString#

Ниже приведен пример вывода:

Original string: String1
StringToEncrypt: QLkApY6XKka7mQge000000001String1
EncryptedString: BOAVeSKidQyyHrEa15x9Uava8t8+OiJVmCqv0RzUzPWFyT4jUMzZ56pG5uFt6bGG

Original string: String2
StringToEncrypt: DboCmHHuVrU05oTV000000001String2
EncryptedString: 4Yk14F0ffz9+djbvSiwA1/X3FHhS5Vhta7Q8iocBPhmFyT4jUMzZ56pG5uFt6bGG

Original string: String3
StringToEncrypt: 8om5VbbWQgvRWK7Q000000001String3
EncryptedString: 01AF+pmF9sDsUHcIXSVfom8Egv8Oiyb2yy12hiVcJjqFyT4jUMzZ56pG5uFt6bGG

Original string: String3
StringToEncrypt: T4qJodVe6aEv0p1E000000001String3
EncryptedString: aAjCbSBRZ+cd7ZwpFPZUxW8Egv8Oiyb2yy12hiVcJjqFyT4jUMzZ56pG5uFt6bGG

Каждая строка EncryptedString заканчивается одинаковым21 символ:

FyT4jUMzZ56pG5uFt6bGG

Когда исходная строка совпадает («String3» в 3-м и 4-м примере), EncryptedString заканчивается теми же 42 символами:

8Egv8Oiyb2yy12hiVcJjqFyT4jUMzZ56pG5uFt6bGG

Обновление: Согласно принятому ответу, я не должен делать свой собственный вектор заполнения или инициализации.Функции Coldfusion для шифрования / дешифрования могут обрабатывать это автоматически, и зашифрованные значения не будут иметь повторяющихся шаблонов.Например:

EncryptedString=encrypt(StringToEncrypt, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64')
DecryptedString=decrypt(EncryptedString, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64')

Ответы [ 2 ]

4 голосов
/ 07 июля 2019

Do not сделайте свой собственный отступ, но пусть функция шифрования сделает это. Это добавлено к открытому тексту, не добавлено. Обычное заполнение называется дополнением PKCS5 и добавляет $ t $ к байту $ t \ in {1,2,3, \ ldots, 16} $, которое составляет полные блоки.

Кроме того, iv является аргументом функции шифрования и не ставится перед открытым текстом. На самом деле (когда вы используете цепочечный режим, такой как CBC, OFB, CFB), он добавляется к зашифрованному тексту.

Таким образом, вы можете сгенерировать IV как вы (хотя, возможно, есть и лучшие функции для этого), а затем использовать открытый текст как есть и шифровать:

EncryptedString=encrypt(StringToEncrypt, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64', binaryDecode(IV, "base64"))

(на основании этой документации )

добавлено 2 В соответствии с этими документами iv должен быть двоичным, поэтому необходимо преобразовать base64 из generateKey. Спасибо за комментарии @Agax и его "cftry" примеров ...

добавлено 1 Оказывается, что пропуск IV вызовет функцию генерировать свою собственную IV, и, казалось бы, неповторяющимся способом. В любом случае мы можем использовать

EncryptedString=encrypt(StringToEncrypt, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64')

вместо этого. Важно использовать режим цепочки, такой как CBC, чтобы получить эффект распространения от случайного IV, который маскирует идентичные незашифрованные тексты и который по умолчанию «AES» оставляет видимым (предположительно, это делает режим ECB).

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

1 голос
/ 07 июля 2019

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

Например, режим CBC выполняет XOR с текстом предыдущего блочного шифра и открытым текстом текущего блока перед шифрованием текущего блока. Это означает, что даже с одной и той же строкой ("string3") и одним и тем же ключом другой IV приведет к совершенно другому результату, и никогда не будет повторения строки.

Другие режимы AES, которые используют XOR, включают: CBC, PCBC, OFB, CFB. Эта ссылка описывает различные режимы AES более подробно (в разделе «общие режимы»).

...