我有一个棘手的问题,我无法解决。我正在创建一个接受无符号字符缓冲区及其大小的dll(因为它是二进制)。然后我会加密它并返回缓冲区。此函数的调用者稍后将此缓冲区写入文件。
由于文件大小很大,调用者会在写入文件之前向我发送缓冲区以加密块(不是固定大小)。最终,最终文件已加密。
现在进行加密,我使用16个字符的密钥来加密缓冲区的每个字符。由于缓冲区大小不是16的倍数,因此有时我的密钥的所有字符都不能用于加密。这会在解密期间产生问题。因为并非所有字符都使用相同的密钥模式加密。因此,解密失败。
我该如何解决这个问题?
答案 0 :(得分:3)
具有block ciphers等对称密钥的所有AES都要求输入为块大小的倍数。他们通过padding数据解决了这个问题,因此它总是块大小的倍数。在这种情况下,“块”的大小就是键的大小。
填充的常用方法是PKCS#7,其中为填充选择的字符表示要填充的字节数。例如,假设您的块大小为16字节,而您的数据长度为60字节。这意味着你可以完全填满3个街区。您的最后一个块将包含12个字节的数据和4个未使用的字节。所以你用值4填充所有4个未使用的字节。如果你有61个字节的数据,你的最后一个块中有3个未使用的字节,所以你用3个字节的值3填充它。
您应该设计API,以便您的库在加密时添加填充并在解密时删除填充。用户不应该这样做。
答案 1 :(得分:2)
您描述此问题的方式表明您正在使用密码的ECB模式。 ECB(电子密码本)表示您独立加密每个块。这是一种非常不安全的加密方式,因此不安全,在许多情况下它几乎不具备加密的条件。
如果你独立地加密每个16字节,那么只要明文中出现相同的16个字节,密文就会出现相同的16个字节。在其中包含任何模式的数据中(大多数数据中都有模式),这可用于解密数据。
为了解决这个问题,我们几乎总是使用另一种分组密码模式,例如CBC(这是最常见的)。 CBC将每个块的输出混合到下一个块的加密中。使用CBC时,通常使用PKS#7填充,如@indiv所述。还有其他解决方案,但PKCS#7很常见且易于实现。请注意,在使用它时,如果给出的数据是16个字节的倍数,则需要添加一个16 0x10字节的额外块。
你不应该用零填充。这是不明确的(如果原始数据以零结尾怎么办?)并允许扩展攻击。这就是PKCS#7存在的原因。
编写自己的加密是非常具有挑战性的,并且很容易出错。我建议使用已建立的库,它将具有处理这些情况所需的工具。在C ++中,您应该查看cryptopp或Botan。如果您使用Botan,您可能需要考虑使用他们的CryptoBox格式。它为您处理更复杂的问题(构建加密格式存在许多复杂问题)。