"NoPadding" 参数在 Cipher class 中究竟做了什么?
What exactly does the "NoPadding" parameter do in the Cipher class?
Java 的 Cipher
class 支持转换 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)
起初我假设 "padding" 这里的意思是用于填充最后一个明文块的方法,如果明文的大小不是密码块大小的倍数。
但在那种情况下,ECB 或 CBC 等分组密码模式如何与 "no padding" 一起使用?假设我们使用 AES/ECB/NoPadding
来加密一条 250 位的消息。明文的第一块显然是消息的前 128 位。第二个明文块的后6位是多少?
嗯,首先,您不能直接提供 Cipher
- 在任何模式下 - 250 位的消息。原因是 - 与大多数运行时一样 - 字节是您可以处理的最小数据量。如果你想编码 250 位,你将不得不考虑以字节为单位的这些位的编码(例如,通过指示你不使用的最后一个字节中的位,就像对 DER 编码的 ASN.1 的值编码执行的那样)定义的位串)。
仅 11 位设置为 1 的 DER BIT STRING 示例:
05 FF E0
此处最后一个字节中有 5 个未使用的位(设置为值 0
)。所以第一个字节只是牺牲来表明这个事实——它不是值的一部分。
其次,即使输入 是 8 位的倍数,您仍然无法使用 NoPadding
对 ECB 或 CBC 模式进行加密 unless 输入本身已经是块大小的倍数。如果您指定 NoPadding
那么实际上没有添加任何字节(甚至没有 00
值字节)所以您将获得 IllegalBlockSizeException
if 明文大小不是块大小的倍数(AES 为 16 字节,DES 和 DES-EDE 为 8 字节)。
明文大小是提供给 update
和 doFinal
方法的输入字节的总和。最后一个块之前的块的字节将在需要时进行缓冲 - 只有最终计数很重要。
来自 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
抛出,而不管 使用的填充(再次,仅适用于 ECB 和 CBC 模式)如果大小不是块大小的倍数。毕竟只有在分组密码和操作模式解密后才会发生填充。
当然,加密期间 ECB 和 CBC 模式的输出应该始终是块大小的倍数,因此这意味着密文在解密之前被截断或以其他方式更改。
对于 GCM 不需要填充(在其中使用 CTR 模式加密),因此 NoPadding
是唯一现实的选择,并且任何数量的数据都可以 - 但同样是要由 [= 加密的最小元素11=] 是一个字节。尽管 GCM 算法 是以位而不是字节指定的,但此 实现 不支持它。
Java 的 Cipher
class 支持转换 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)
起初我假设 "padding" 这里的意思是用于填充最后一个明文块的方法,如果明文的大小不是密码块大小的倍数。
但在那种情况下,ECB 或 CBC 等分组密码模式如何与 "no padding" 一起使用?假设我们使用 AES/ECB/NoPadding
来加密一条 250 位的消息。明文的第一块显然是消息的前 128 位。第二个明文块的后6位是多少?
嗯,首先,您不能直接提供 Cipher
- 在任何模式下 - 250 位的消息。原因是 - 与大多数运行时一样 - 字节是您可以处理的最小数据量。如果你想编码 250 位,你将不得不考虑以字节为单位的这些位的编码(例如,通过指示你不使用的最后一个字节中的位,就像对 DER 编码的 ASN.1 的值编码执行的那样)定义的位串)。
仅 11 位设置为 1 的 DER BIT STRING 示例:
05 FF E0
此处最后一个字节中有 5 个未使用的位(设置为值 0
)。所以第一个字节只是牺牲来表明这个事实——它不是值的一部分。
其次,即使输入 是 8 位的倍数,您仍然无法使用 NoPadding
对 ECB 或 CBC 模式进行加密 unless 输入本身已经是块大小的倍数。如果您指定 NoPadding
那么实际上没有添加任何字节(甚至没有 00
值字节)所以您将获得 IllegalBlockSizeException
if 明文大小不是块大小的倍数(AES 为 16 字节,DES 和 DES-EDE 为 8 字节)。
明文大小是提供给 update
和 doFinal
方法的输入字节的总和。最后一个块之前的块的字节将在需要时进行缓冲 - 只有最终计数很重要。
来自 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
抛出,而不管 使用的填充(再次,仅适用于 ECB 和 CBC 模式)如果大小不是块大小的倍数。毕竟只有在分组密码和操作模式解密后才会发生填充。
当然,加密期间 ECB 和 CBC 模式的输出应该始终是块大小的倍数,因此这意味着密文在解密之前被截断或以其他方式更改。
对于 GCM 不需要填充(在其中使用 CTR 模式加密),因此 NoPadding
是唯一现实的选择,并且任何数量的数据都可以 - 但同样是要由 [= 加密的最小元素11=] 是一个字节。尽管 GCM 算法 是以位而不是字节指定的,但此 实现 不支持它。