AES中输入和密文长度之间的关系
Posted
技术标签:
【中文标题】AES中输入和密文长度之间的关系【英文标题】:Relation between input and ciphertext length in AES 【发布时间】:2011-04-12 14:45:32 【问题描述】:最近开始在我的应用程序中使用密码学,我发现自己对输入文本长度和它产生的密文之间的关系感到困惑。在应用密码之前,很容易确定数据库列的大小。但是,现在列大小略有不同。
两个问题:
-
我是否正确地假设这是由于我的输入填充,所以它符合密码的要求?
有没有办法根据输入的最大长度准确预测密文的最大长度?
对于奖励积分:我应该将密文 base64 编码存储在 varchar 中,还是将其保留为原始字节并将它们存储在 varbinary 中?将字节存储在我的数据库中是否存在风险(我正在使用参数化查询,所以理论上意外破坏转义应该不是问题)?
TIA!
补充:我使用的密码是 AES/Rijndael-256 - 这种关系是否因可用算法而异?
【问题讨论】:
为什么需要指定最大长度?这不是 80 年代 - 数据库支持具有较大或不存在长度限制的字段已经有一段时间了。 性能和所需的存储空间更少。 TEXT 和 BLOB 字段非常棒 - 但对于少量数据(我的意思是,我们正在谈论加密密码......不是 XML 数据或小说的大块)开销似乎无关紧要。 TEXT 和 BLOB 存储在数据库中与它们所属的记录不同的区域中,从而使您的数据库引擎执行两次读取而不是一次读取。 【参考方案1】:关系取决于您使用的填充和链接模式,以及算法块大小(如果是块密码)。
一些加密算法是流密码,它“逐位”(或“逐字节”)加密数据。它们中的大多数产生一个依赖于密钥的伪随机字节流,并且通过将该流与数据进行异或来执行加密(解密是相同的)。使用流密码,加密长度等于明文数据长度。
其他加密算法是分组密码。名义上,分组密码对固定长度的单个数据块进行加密。 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 @Thomas,很好的解释。如果您为要加密的每个文件生成一个新的会话密钥,您不可能使用/不使用 IV 用于 AES CBC 模式吗?谢谢 如果您为每个文件生成一个新密钥,那么您可以使用不需要编码的传统 IV(例如全零 IV)。但是为每个文件生成一个新的随机密钥至少与为每个文件生成一个新的随机 IV 一样困难。哪个最好取决于具体情况。 感谢您非常详细的回答 - 我将 IV 存储在与加密数据不同的列中,在同一记录中,因为 IV 是固定长度。我将远离对密文进行 Bas64 处理。 我认为 IV 代表“初始化向量”——虽然语义相同!【参考方案2】:据我了解,在块模式 (cbc, ecb) 中,输出长度将四舍五入为块大小,由 mcrypt_enc_get_block_size 返回。另外,您需要将 IV 与数据一起存储,因此大小将四舍五入 strlen(data) + mcrypt_enc_get_iv_size()。
至于 base64 编码,我不会打扰(但请确保在转储数据库时使用十六进制编码)。
【讨论】:
【参考方案3】:对于带有 PKCS#5 填充的 AES CBC 分组密码,
#define BLOCKSIZE 16
size_t CipherTextLen = (PlainTxtLen / BLOCKSIZE + 1) * BLOCKSIZE;
这里没有考虑初始化向量
【讨论】:
如果使用PKCS#7会怎样? - 编辑 - 发现这个:crypto.stackexchange.com/a/54022/60476以上是关于AES中输入和密文长度之间的关系的主要内容,如果未能解决你的问题,请参考以下文章