我使用初始化矢量和填充实现了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>
下面是示例输出:
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
当原始字符串相同时(在第3和第4个示例中为“ String3”),EncryptedString以相同的42个字符结尾:
8Egv8Oiyb2yy12hiVcJjqFyT4jUMzZ56pG5uFt6bGG
更新:按照接受的答案,我不应该自己做填充或初始化向量。 Coldfusion的加密/解密功能可以自动处理,并且加密的值将没有重复的模式。例如:
EncryptedString=encrypt(StringToEncrypt, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64')
DecryptedString=decrypt(EncryptedString, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64')
答案 0 :(得分:4)
不要不做自己的填充,但是让加密函数来做。它被追加到明文中,而不是前置的。通常的填充称为PKCS5填充,并在{1,2,3,\ ldots,16} $中将$ t $乘以字节$ t \来构成完整的块。
此外,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作为参数提供时,IV实际上并不位于密码文本的前面,因此您必须以某种方式记住它才能解密第一段纯文本。相当不规范。当您让加密本身生成时,它确实会在其前面。因此,您必须使用相同的签名版本的解密。
答案 1 :(得分:1)
一个可能的原因是,您使用的AES模式在加密当前块之前没有将前一个块与当前块一起使用。
例如,CBC模式在对当前块进行加密之前,对前一个块密文和当前块明文执行XOR。这意味着即使使用相同的字符串(“ string3”)和相同的键,不同的IV也会产生完全不同的结果,并且永远不会重复字符串。
使用XOR的AES的其他模式包括:CBC,PCBC,OFB,CFB。 link (在“普通模式”部分下)更详细地描述了AES的不同模式。