Cipher类中的"NoPadding"参数究竟是什么作用?

4
Java的Cipher类支持列出的多种转换方式,其中包括几种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)?假设我们使用AES/ECB/NoPadding加密一个250位的消息。明文的第一个块显然是消息的前128位。第二个明文块的最后6位是什么?

3
请参考Maarten的优秀回答,简而言之:NoPadding并不一定意味着不需要填充,它意味着您已经承担了适当填充的责任。 - President James K. Polk
1
嗯,是的,那是一种解释方法。但如果可能的话,我会尝试不自己执行填充,而是将其留给库来处理。然而,在某些用例中,自己进行填充是唯一现实的选择 - 在这种情况下,“NoPadding”真的非常有用。 - Maarten Bodewes
1个回答

3
首先,无论采用哪种模式,您都不能直接向Cipher输入250位的消息。原因是在大多数运行时中,字节是您可以处理的最小数据量。如果要编码250位,则必须考虑将这些位编码为字节(例如,通过在最终字节中指示未使用的位,如执行DER编码的ASN.1定义的BIT STRING的值编码所示)。
仅设置11个位为1的DER BIT STRING示例:
05 FF E0

在最后一个字节中有5位未使用的位(被设置为值0)。因此,第一个字节只是被牺牲来指示这个事实——它不是值的一部分。


其次,即使输入本身是8位的倍数,你仍然不能使用ECB或CBC模式的NoPadding进行加密,除非输入本身已经是块大小的倍数。如果指定了NoPadding,那么确实不会添加任何字节(甚至不是值为00的字节),所以如果明文大小不是块大小的倍数(AES为16字节,DES和DES-EDE为8字节),就会得到一个IllegalBlockSizeException

明文大小是提供给updatedoFinal方法的输入字节数。前面块的字节将在必要时缓冲——只有最后一个块的计数才重要。


Cipher#doFinal文档中可以看到:

throws:

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

请注意,这在我的看法中是一个可怕的描述:在解密期间,doFinal将抛出此异常,无论使用的填充方式如何(同样,仅适用于ECB和CBC模式),如果大小不是块大小的倍数。解密后块密码和操作模式才进行去填充。

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


对于GCM,不需要填充(在内部使用CTR模式加密),因此NoPadding是唯一现实的选择,任何数量的数据都可以——但是,由于最小的要被加密的元素是一个字节,所以这个Cipher实现不支持以比特而非字节为单位的GCM算法。


@foo 可能少了一位。对于 RSA,值需要在 [0,n) 范围内,其中 n 是模数。因此,如果将第一个字节与 0x7F 进行 AND 操作,则可能会起作用。对于 RSA 教科书加密来说是不安全的;通常你会使用混合加密(包装或派生随机秘密密钥,如 AES 密钥,并使用它来加密实际数据)。 - Maarten Bodewes
那是有道理的;但BouncyCastle源代码明确减去了一个完整的字节。请查看org.bouncycastle.crypt.engines.RSACoreEngine.java 49行及以下。 - foo
1
嗯,奇怪。我想他们采用了简单的方法来处理模数大小不是8的倍数的情况。 - Maarten Bodewes
我刚刚发现,与BouncyCastle相比,SunJCE在使用“RSA/ECB/NoPadding”时会为您提供一个使用完整块大小的Cipher实例,而不是减去1个字节。这两者之间有一个是错误的,还是只是一个隐藏的“警告”? - foo
它们用于特定填充模式的实现,正是它们之间的差异导致了问题。 - foo
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接