使用初始化向量和填充正确执行AES 128加密

Fla*_*Man 5 encryption coldfusion aes

我使用初始化矢量和填充来实现AES 128位加密,如下面的代码所示。我碰巧正在使用ColdFusion,但我认为这并不重要。加密的结果显示了一些重复的模式,这是我本来不会想到的,但是再次,我不知道为此正确输出的特征。我是否正在正确执行初始化向量和填充?

<!---
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#</pre>
    </cfloop>

</cfoutput>
Run Code Online (Sandbox Code Playgroud)

以下是示例输出:

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
Run Code Online (Sandbox Code Playgroud)

每个EncryptedString以相同的21个字符结尾:

FyT4jUMzZ56pG5uFt6bGG
Run Code Online (Sandbox Code Playgroud)

当原始字符串相同时(在第3和第4个示例中为“ String3”),EncryptedString以相同的42个字符结尾:

8Egv8Oiyb2yy12hiVcJjqFyT4jUMzZ56pG5uFt6bGG
Run Code Online (Sandbox Code Playgroud)

更新:按照公认的答案,我不应该自己做填充或初始化向量。Coldfusion的加密/解密功能可以自动处理此问题,并且加密的值将没有重复的模式。例如:

EncryptedString=encrypt(StringToEncrypt, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64')
DecryptedString=decrypt(EncryptedString, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64')
Run Code Online (Sandbox Code Playgroud)

Hen*_*sma 4

不要自己进行填充,而是让加密函数来完成附加到明文之后,而不是前置。通常的填充称为 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 应该是二进制的,因此必须转换generateKey 中的base64。感谢@Agax 的评论和他的“cftry”示例......

添加 1事实证明,省略 IV 将导致函数生成自己的 IV,并且以一种看似不重复的方式。无论如何我们都可以使用

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

反而。必须使用像 CBC 这样的链接模式来从随机 IV 中获得传播效果,该随机 IV 屏蔽相同的明文并且默认的“AES”保持可见(这可能是 ECB 模式)。

当我们将其作为参数给出时,IV 实际上并未添加到密文之前,因此您必须以某种方式记住它才能解密第一个纯文本块。相当不标准。当您让 encrypt 自己生成它时,它会在前面添加它。所以你必须使用相同签名版本的解密。