Java “这句话的确切含义是什么?”;否加入?’;密码类中的参数do?

Java “这句话的确切含义是什么?”;否加入?’;密码类中的参数do?,java,encryption,cryptography,padding,block-cipher,Java,Encryption,Cryptography,Padding,Block Cipher,Java的Cipher类支持转换。其中有几个变体: AES/CBC/NOP(128) AES/ECB/NOP(128) AES/GCM/NoPadding(128) DES/CBC/NOP(56) DES/ECB/NOP(56) DESede/CBC/NoPadding(168) DESede/ECB/NoPadding(168) 我首先假设这里的“填充”是指填充最后一个明文块的方法,如果明文的大小不是密码块大小的倍数 但在这种情况下,像ECB或CBC这样的分组密码模式如何在“无填充”的情况

Java的
Cipher
类支持转换。其中有几个变体:

  • AES/CBC/NOP(128)
  • AES/ECB/NOP(128)
  • AES/GCM/NoPadding(128)
  • DES/CBC/NOP(56)
  • DES/ECB/NOP(56)
  • DESede/CBC/NoPadding(168)
  • DESede/ECB/NoPadding(168)
我首先假设这里的“填充”是指填充最后一个明文块的方法,如果明文的大小不是密码块大小的倍数


但在这种情况下,像ECB或CBC这样的分组密码模式如何在“无填充”的情况下使用呢?假设我们使用
AES/ECB/NoPadding
加密250位消息。明文的第一块显然是消息的前128位。第二个明文块的最后6位是什么?

首先,您不能在任何模式下直接向250位消息馈送
密码。原因是,与大多数运行时一样,字节是可以处理的最小数据量。如果要对250位进行编码,则必须考虑以字节为单位对这些位进行编码(例如,通过指示最后一个字节中不使用的位,如对DER编码ASN.1定义的位字符串进行值编码时所做的那样)


仅11位设置为1的DER位字符串示例:

05 FF E0
最后一个字节中有5个未使用的位(设置为值
0
)。因此,第一个字节只是为了表明这一事实而牺牲的——它不是值的一部分


其次,即使输入是8位的倍数,您仍然无法使用ECB或CBC模式的
NoPadding
进行加密,除非输入本身已经是块大小的倍数。如果指定
NoPadding
,则实际上不添加任何字节(甚至不添加
00
值字节),因此如果
明文大小不是块大小的倍数(AES为16字节,DES&DES-EDE为8字节),则将得到
非法块大小异常

明文大小是同时提供给
update
doFinal
方法的输入字节数。最后一个块之前的块的字节将在需要时进行缓冲-只有最终计数才重要


Cipher#doFinal
文档中:

抛出:


IllegalBlockSizeException
-如果此密码是块密码,则未请求填充(仅在加密模式下),并且此密码处理的数据的总输入长度不是块大小的倍数;或者如果此加密算法无法处理提供的输入数据。

请注意,这是一个非常糟糕的描述,在我看来:在解密过程中,如果大小不是块大小的倍数,则无论使用何种填充(同样,仅适用于ECB和CBC模式),
doFinal
都会引发此异常。只有在使用分组密码和操作模式进行解密之后,才能进行解锁

当然,加密期间ECB和CBC模式的输出应始终是块大小的倍数,因此这意味着密文在解密之前被截断或以其他方式更改



因为不需要GCM填充(在中使用CTR模式加密),所以
NoPadding
是唯一现实的选择,任何数量的数据都可以使用,但是
Cipher
要加密的最小元素是一个字节。尽管GCM算法是以位而不是字节来指定的,但这个实现并不支持它。

请参阅Maarten的优秀答案,但简而言之:
NoPadding
并不一定意味着不需要填充,它意味着你已经承担了适当填充的责任。是的,这是解释它的一种方式。但如果可能的话,我会尽量不自己填充,而把它留给图书馆。然而,在一些用例中,填充自己是唯一现实的选择,在这种情况下,
NoPadding
非常有用。没有人真正使用密文窃取(CTS)的三种模式中的任何一种,因此我将其从我的描述中删除。OpenJDK不支持开箱即用的CTS,但其他加密提供程序(如Bouncy Castle)可以支持它。