Java 的 Cipher
类支持转换 listed there 。其中有几个 NoPadding
变体:
- AES/CBC/NoPadding (128)
- AES/ECB/NoPadding (128)
- AES/GCM/NoPadding (128)
- DES/CBC/NoPadding (56)
- DES/ECB/NoPadding (56)
- DESede/CBC/NoPadding (168)
- DESede/ECB/NoPadding (168)
我首先假设这里的“填充”是指用于填充最后一个明文 block 的方法,如果明文的大小不是密码 block 大小的倍数。
但在这种情况下,如何才能在“无填充”的情况下使用 ECB 或 CBC 等分组密码模式呢?假设我们使用 AES/ECB/NoPadding 来加密 250 位消息。明文的第一个 block 显然是消息的前 128 位。第二个明文 block 的最后 6 位是多少?
最佳答案
嗯,首先,你不能喂Cipher
- 在任何模式下 - 直接发送 250 位消息。原因是 - 就像在大多数运行时一样 - 字节是您可以处理的最小数据量。如果要编码 250 位,则必须考虑以字节为单位对这些位进行编码(例如,通过指示最终字节中不使用的位,如对 DER 编码的 ASN.1 的值编码所执行的那样)定义的位串)。
DER BIT STRING 仅 11 位设置为 1 的示例:
05 FF E0
这里最后一个字节中有 5 个未使用的位(设置为值 0
)。因此,只是牺牲第一个字节来表明这一事实 - 它不是值的一部分。
其次,即使输入是 8 位的倍数,您仍然无法使用NoPadding
进行加密。对于 ECB 或 CBC 模式除非输入本身已经是 block 大小的倍数。如果指定NoPadding
那么确实没有添加任何字节(甚至没有 00
有值(value)的字节),所以你会得到一个 IllegalBlockSizeException
如果明文大小不是 block 大小的倍数(AES 为 16 字节,DES 和 DES-EDE 为 8 字节)。
明文大小是提供给update
的输入字节数。和doFinal
方法在一起。最后一个 block 之前的 block 的字节将在需要时进行缓冲 - 只有最终计数很重要。
来自Cipher#doFinal
文档:
throws:
...
IllegalBlockSizeException
- if this cipher is a block cipher, no padding has been requested (only in encryption mode), and the total input length of the data processed by this cipher is not a multiple of block size; or if this encryption algorithm is unable to process the input data provided.
...
请注意,在我看来,这是一个糟糕的描述:在解密过程中,doFinal
将抛出此异常。如果大小不是 block 大小的倍数,则无论使用什么填充(同样,仅适用于 ECB 和 CBC 模式)。毕竟,填充仅在通过分组密码和操作模式解密后才会发生。
当然,加密期间 ECB 和 CBC 模式的输出应始终是 block 大小的倍数,因此这意味着密文在解密之前被截断或以其他方式更改。
<小时/>对于GCM来说不需要padding(内部使用了CTR模式加密),所以NoPadding
是唯一现实的选择,任何数量的数据都可以 - 但同样是由 Cipher
加密的最小元素是一个字节。尽管 GCM 算法是以位而不是字节为单位指定的,但此实现并不支持它。
关于java - "NoPadding"参数在 Cipher 类中到底有什么作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59923645/