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

时间:2010-09-15 10:18:16

标签: php cryptography mcrypt

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

两个问题:

  1. 我是否正确认为这是由于我输入的填充,以便它符合密码的要求?
  2. 有没有办法根据输入的最大长度准确预测密文的最大长度?
  3. 对于奖励积分:我应该在varchar中存储base64编码的密文,还是将其保存为原始字节并将其存储在varbinary中?将数据存储在我的数据库中是否存在风险(我使用的是参数化查询,因此理论上意外断开转义应该不是问题)?

    TIA!

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

3 个答案:

答案 0 :(得分:26)

关系取决于您正在使用的填充链接模式,以及算法块大小(如果它是分组密码)。

某些加密算法是流密码,它“逐位”(或“逐字节”)加密数据。它们中的大多数产生依赖于密钥的伪随机字节流,并且通过用该数据对该流进行异或(解密是相同的)来执行加密。使用流密码,加密长度等于普通数据长度。

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

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

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

有一种称为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。

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

对于带有PKCS#5填充的AES CBC分组密码,

#define BLOCKSIZE 16

size_t CipherTextLen = (PlainTxtLen / BLOCKSIZE + 1) * BLOCKSIZE;

这没有考虑初始化向量