C++ 当数据不是密钥大小的倍数时进行加密和解密

C++ 当数据不是密钥大小的倍数时进行加密和解密,c++,encryption,cryptography,C++,Encryption,Cryptography,我有一个棘手的问题,我无法解决。我正在创建一个dll,它接受一个无符号字符缓冲区及其大小(因为它是二进制的)。然后我会加密它并返回缓冲区。此函数的调用方稍后会将此缓冲区写入文件 由于文件的大小会很大,调用方将在写入文件之前向我发送缓冲区,以进行分块加密(其大小不是固定的)。最终,最终的文件被加密 现在对于加密,我使用16个字符的密钥对缓冲区的每个字符进行加密。由于缓冲区大小不会是16的倍数,因此在某些情况下,我的密钥的所有字符可能不会用于加密。这会在解密过程中产生问题。因为并非所有字符都使用相同

我有一个棘手的问题,我无法解决。我正在创建一个dll,它接受一个无符号字符缓冲区及其大小(因为它是二进制的)。然后我会加密它并返回缓冲区。此函数的调用方稍后会将此缓冲区写入文件

由于文件的大小会很大,调用方将在写入文件之前向我发送缓冲区,以进行分块加密(其大小不是固定的)。最终,最终的文件被加密

现在对于加密,我使用16个字符的密钥对缓冲区的每个字符进行加密。由于缓冲区大小不会是16的倍数,因此在某些情况下,我的密钥的所有字符可能不会用于加密。这会在解密过程中产生问题。因为并非所有字符都使用相同的密钥模式进行加密。因此,解密失败

如何解决此问题?

所有具有对称密钥(如)的都要求输入为块大小的倍数。他们通过数据来解决这个问题,使得数据总是块大小的倍数。在这种情况下,“块”的大小只是键的大小

一种常见的填充方法是,选择填充的字符表示填充的字节数。例如,假设块大小为16字节,数据长度为60字节。这意味着你可以完全填满3个街区。最后一个块将有12个字节的数据和4个未使用的字节。因此,用值4填充所有4个未使用的字节。如果您有61个字节的数据,那么在最后一个块中会有3个未使用的字节,因此您会用3个字节的值3填充它

您应该设计API,以便库在加密时添加填充,在解密时删除填充。用户不必这样做。

所有具有对称键(如)的输入都需要是块大小的倍数。他们通过数据来解决这个问题,使得数据总是块大小的倍数。在这种情况下,“块”的大小只是键的大小

一种常见的填充方法是,选择填充的字符表示填充的字节数。例如,假设块大小为16字节,数据长度为60字节。这意味着你可以完全填满3个街区。最后一个块将有12个字节的数据和4个未使用的字节。因此,用值4填充所有4个未使用的字节。如果您有61个字节的数据,那么在最后一个块中会有3个未使用的字节,因此您会用3个字节的值3填充它


您应该设计API,以便库在加密时添加填充,在解密时删除填充。用户不必这样做。

您描述此问题的方式表明您正在使用密码的ECB模式。ECB(电子码本)意味着您独立地加密每个块。这是一种非常不安全的加密方式,非常不安全,在许多情况下,它几乎不符合加密的条件

如果单独加密每16个字节,那么无论何时相同的16个字节出现在明文中,相同的16个字节都将出现在密文中。在包含任何模式的数据中(大多数数据中都包含模式),这可以用于解密数据

为了解决这个问题,我们几乎总是使用另一种分组密码模式,例如CBC(这是最常见的)。CBC将每个块的输出混合到下一个块的加密中。在使用CBC时,通常使用PKCS#7填充,如@indiv所述。还有其他解决方案,但PKCS#7是常见的,易于实现。请注意,在使用它时,如果给定的数据是16字节的倍数,则需要添加16 0x10字节的额外块

你不应该用零填充。这是不明确的(如果原始数据以零结尾怎么办?)并且允许扩展攻击。这就是PKCS#7存在的原因


编写自己的密码非常具有挑战性,很容易出错。我建议使用一个已建立的库,它将提供处理这些情况所需的工具。在C++中,你应该看看或。如果使用Botan,则可能需要考虑使用它们的密码盒格式。它为您处理更复杂的问题(在构建加密格式时有很多复杂的问题)。

您描述这个问题的方式表明您正在使用密码的ECB模式。ECB(电子码本)意味着您独立地加密每个块。这是一种非常不安全的加密方式,非常不安全,在许多情况下,它几乎不符合加密的条件

如果单独加密每16个字节,那么无论何时相同的16个字节出现在明文中,相同的16个字节都将出现在密文中。在包含任何模式的数据中(大多数数据中都包含模式),这可以用于解密数据

为了解决这个问题,我们几乎总是使用另一种分组密码模式,例如CBC(这是最常见的)。CBC将每个块的输出混合到下一个块的加密中。在使用CBC时,通常使用PKCS#7填充,如@indiv所述。还有其他解决方案,但PKCS#7是常见的,易于实现。请注意,在使用它时,如果给定的数据是16字节的倍数,则需要添加16 0x10字节的额外块

你不应该用零填充。这是不明确的(如果原始数据以零结尾怎么办?)并且允许扩展攻击。这就是PKCS#7存在的原因


编写自己的密码非常具有挑战性,很容易出错。我建议使用一个已建立的库,它将提供处理这些情况所需的工具。在C++中,你应该看看或。如果使用Botan,则可能需要考虑使用它们的密码盒格式。它为您处理更复杂的问题(在构建加密格式时有很多复杂的问题)。

谢谢您的回答。听起来是一个完美的解决方案