AES 中输入和密文长度之间的关系

2022-08-30 18:30:36

最近开始在我的应用程序中使用密码学,我发现自己对输入文本长度与它所产生的密文之间的关系感到困惑。在应用加密之前,很容易确定数据库列大小。但是,现在,列大小略有不同。

两个问题:

  1. 我假设这是由于我的输入的填充,所以它符合密码的要求,我是正确的吗?
  2. 有没有办法根据输入的最大长度准确预测密文的最大长度?

对于奖励点:我应该将密文base64编码存储在varchar中,还是将其保留为原始字节并将它们存储在varbinary中?在我的数据库中存储字节是否存在风险(我使用的是参数化查询,因此理论上意外中断转义不应该是问题)?

哎呀!

补充:我使用的密码是AES / Rijndael-256 - 这种关系在可用的算法之间是否有所不同?


答案 1

这种关系取决于所使用的填充链接模式,以及算法块大小(如果它是块密码)。

一些加密算法是流密码,它“逐位”(或“逐字节”)加密数据。它们中的大多数产生与密钥相关的伪随机字节流,并且加密是通过XORing执行的,该流与数据一起流式传输(解密是相同的)。使用流密码时,加密的长度等于纯数据长度。

其他加密算法是块密码。块密码名义上对固定长度的单个数据块进行加密。AES 是具有 128 位块(16 字节)的块密码。请注意,AES-256也使用128位块。“256”是关于密钥长度,而不是块长度。链接模式是关于如何将数据拆分为几个这样的块(这并不容易安全地完成,但CBC模式很好)。根据链接模式的不同,数据可能需要一些填充,即在末尾添加一些额外的字节,以便长度适合链接模式。填充必须能够在解密时明确删除。

在CBC模式下,输入数据的长度必须具有块长度的倍数,因此习惯上添加PKCS#5填充:如果块长度为n,则至少添加1个字节,最多为n,使得总大小是n的倍数,并且最后添加的字节(可能全部)具有数值k,其中k是添加的字节数。解密后,只需查看最后解密的字节即可恢复k,从而知道最终必须删除多少填充字节。

因此,对于CBC模式和AES,假设PKCS#5填充,如果输入数据的长度为d,则加密的长度为。我在这里使用类似C的符号;简单来说,长度介于 d+1d+16 之间,是 16 的倍数。(d + 16) & ~15

有一种称为CTR(作为“计数器”)的模式,其中块密码加密计数器的连续值,从而产生伪随机字节流。这有效地将块密码转换为流密码,因此长度为d的消息被加密为d字节。

警告:关于所有加密系统(包括流密码)和模式都需要一个称为IV(初始值)的额外值。每条消息应具有其IV,并且使用相同密钥加密的两条消息不得使用相同的IV。某些模式有额外的要求;特别是,对于CBC和CTR,IV应使用加密强伪随机数生成器随机和均匀地选择。IV不是秘密的,但必须由解密器知道。由于每条消息都有自己的 IV,因此通常需要将 IV 与加密的消息一起编码。对于CBC或CTR,IV的长度为n,因此,对于AES,这是额外的16个字节。我不知道mcrypt对IV有什么作用,但是,从密码学上讲,IV必须在某个时候进行管理。

至于Base64,它适用于通过纯文本媒体传输二进制数据,但这对于适当的数据库来说不是必需的。此外,Base64将数据放大约33%,因此不应盲目应用。我认为你最好在这里避免Base64。


答案 2

根据我的理解,在块模式(cbc,ecb)中,输出长度将四舍五入到块大小,如mcrypt_enc_get_block_size返回的那样。另外,您需要将IV与数据一起存储,因此大小将四舍五入strlen(data)+ mcrypt_enc_get_iv_size()。

至于base64编码,我不会打扰(但确保在转储数据库时使用十六进制编码)。


推荐