我的问题是 - 如何确定输出密文的长度?
我隐约知道输出长度必须是所使用密码的块大小的倍数。但这是否意味着:
- 如果输入数据的长度是密码块大小的倍数,那么输出长度将与输入长度相同吗?
- 如果输入数据的长度不是密码块大小的倍数,那么输出长度将是输入长度+一个块大小?
谢谢!
我的问题是 - 如何确定输出密文的长度?
我隐约知道输出长度必须是所使用密码的块大小的倍数。但这是否意味着:
谢谢!
罗伯特关于密文大小是正确的,这取决于密码模式和填充,可能还有块模式。
如果您在流模式下使用密码(例如 CTR),则密文大小与明文大小相同。如果您使用诸如 GCM 之类的身份验证模式,那么您必须至少使用身份验证标签来增加它。您还可以使用 CBC 模式和密文窃取 (CTS) 来摆脱填充开销,但这仅适用于两个或更多块。
现在让我们假设 CBC 模式的 PKCS#5/7 兼容填充,这是目前最常用的模式。在这种情况下,您的明文至少填充了一个填充字节(否则 unpadding 无法区分例如用单个01
值填充字节填充的明文和明文 - 可除以块大小 - 以01
值字节结尾)。这意味着如果明文已经块对齐,则添加整个块。
当然,如果明文不是块对齐的,那么 PKCS#7 填充只需要填充最后一个块。因此,在这种情况下,block size
添加了 1 个字节。于是计算变为:
L密文=(L明文/L块)*(L块+1)
其中 L明文/ L块被四舍五入(在大多数编程语言中进行整数计算时通常如此)。
现在让我们假设 AES,它的块大小总是 16 字节:
0 bytes -> 16 bytes
1 byte -> 16 bytes
2 bytes -> 16 bytes
...
15 bytes -> 16 bytes
16 bytes -> 32 bytes
17 bytes -> 32 bytes
...
请注意,有相当多的实现使用非标准化填充。一个例子是 PHP 中的 mcrypt 库(您可能可以使用 mcrypt 作为密码学中任何不良做法的基础)。这使用零填充,因此它只是填充00
有价值的字节,直到明文块对齐。在这种情况下,结果大小可以这样计算:
L密文= (L明文/ L块- 1) * (L块+ 1)
显然,当您将它与任何不期望非标准化零填充的实现一起使用时,或者当明文可能以一个或多个00
有价值的字节结尾时,您会遇到麻烦。
最后说明:某些语言(例如 Java Cipher
)具有检索块大小甚至从加密实现中得到的密文的方法。在你开始自己实现之前检查 API 永远不会有坏处。
在撰写本文时,维基百科对填充模式有很好的解释。
输出密文的长度取决于块长度、密码模式以及是否使用填充。
有一些像 CTS 这样的密码模式可以创建与输入相等的密码输出长度,即使使用分组密码也是如此。
关于1:如果输入数据的长度是密码块大小的倍数并且使用了填充,那么输出长度将大一个块,因为您需要至少一个字节来指定填充长度。
关于2:输出长度必须是块长度的倍数,因此它是输入长度+(输入长度模块长度)