【问题标题】:Correct implementation of AES 128 encryption with initialization vector and padding使用初始化向量和填充正确实现 AES 128 加密
【发布时间】:2019-07-06 17:56:08
【问题描述】:

我使用初始化向量和填充实现了 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')

【问题讨论】:

    标签: encryption coldfusion aes


    【解决方案1】:

    不要不要自己做填充,而是让加密函数来做。它附加到纯文本中,而不是附加在前面。通常的填充称为 PKCS5 填充,将 $t$ 乘以字节 $t \in {1,2,3,\ldots,16}$ 以组成完整的块。

    另外,iv 是 encrypt 函数的参数,而不是在明文之前。它实际上是(当你使用像 CBC、OFB、CFB 这样的链模式时)预先添加到密文中。

    因此,您可以照常生成 IV(尽管可能有更好的功能),然后按原样使用明文并加密:

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

    (基于this documentation

    添加了 2 个 根据这些文档,iv 应该是二进制的,因此必须转换 generateKey 的 base64。感谢@Agax 和他的“cftry”示例向 cmets 致谢...

    加了1原来省略IV会导致函数 以一种看似不重复的方式生成自己的 IV。 在任何情况下我们都可以使用

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

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

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

    【讨论】:

    • 这对我来说是最有帮助的答案。在您的代码 sn-p 中,我无法让 IV 参数令人满意地工作,但通过额外的研究,我发现您的代码 sn-p 没有“,IV”默认添加了一个初始化向量(当然,PKCS5Padding 添加了填充),并且加密结果中的重复模式为零。如果您编辑答案以删除“,IV”,并解释默认情况下添加了IV,那么我会接受它。谢谢。
    • @FlanMan 文档建议您可以提供自己的 IV(但它必须是“二进制数据”,并且您使用的是 base64 编码数据,所以这可能是个问题?)。如果您省略它,它可能会随机生成一个 IV(重要的是它们是不可预测的)。
    • @Ageax 他甚至没有使用 PKCS5 填充。您也不应该在该要点中进行填充,只需使用原始输入字符串即可。我保存了一个新的更简单的版本。
    • @HennoBrandsma - 是的,从技术上讲,他是,无论是否需要填充,因为 ECB 和 PKCS5Padding 是 CF 中的默认设置。但是gah ..您对输入是正确的。在我的手机上再次粘贴了错误的要点!这是正确的链接trycf.com/gist/d8bb46669a0a152c0562cb8a9a0f5a1e/…
    • @Ageax 为什么 CF 在 binaryDecode(encryptionKey, "base64") 之后不接受二进制密钥,它说 AES 密钥 2 个字节(不是,解码后是 16)...
    【解决方案2】:

    一个可能的原因是您使用的 AES 模式在加密当前块之前没有将前一个块与当前块一起使用。

    例如,CBC 模式在加密当前块之前与前一个块密文和当前块明文执行 XOR。这意味着即使使用相同的字符串(“string3”)和相同的键,不同的IV也会产生完全不同的结果,并且永远不会出现字符串重复。

    使用 XOR 的其他 AES 模式包括:CBC、PCBC、OFB、CFB。这个 link 更详细地描述了 AES 的不同模式(在“常见模式”部分下)。

    【讨论】:

    • 还要注意,循环中每次迭代都会进行base64编码,16绝对不是3的倍数(毕竟3个字节编码为4个字符)。
    猜你喜欢
    • 2016-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-22
    • 2014-10-15
    相关资源
    最近更新 更多