Java AES密码文本大小

3

我正在使用一种非常标准的Java AES加密/解密方式。

byte[] key = hexStringToByteArray("C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF");

byte[] message = hexStringToByteArray("01A0A1A2A3A4A5A6A703020100060001");

SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);

byte[] encrypted = cipher.doFinal(message);

cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] original = cipher.doFinal(encrypted);

您可以看到,我正在使用128位密钥和128位消息。基本上我总是得到了我期望的结果,然而,加密结果总是256位长。第二个128位始终相同。除了截断结果外,如何确保密码返回仅前128位,而不改变前128位?我感觉在这里块大小的定义有些混淆。

2个回答

12

在回答您的问题之前,有几件必须先处理的事情。我在这段代码中看到的一个潜在危险是没有明确指定密码模式和填充方式。这意味着由提供者默认值决定。如果这是目前Oracle JVM随附的提供者,则这些默认值为ECBPKCS5Padding。如果这正是您想使用的,请通过以下方式指定:

 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

第二个问题是,ECB不是一个好的加密模式选择,因为它不够安全。相比之下,CBC是一个更好的选择,因为它使用了初始化向量。

回到问题上来。加密文本大小的原因在于填充方案,这里采用的是PKCS5。填充是必要的,以确保明文长度适合算法处理。对于AES,它必须是16字节的倍数。在未加密数据长度已经是16字节的倍数的情况下,填充必须添加额外的16字节(参见jbtule在此处的评论)。像这样初始化Cipher可以产生16字节的加密数据:

Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");

这要求未加密的数据长度已经是16字节的倍数,因为它不会进行任何填充。如果不是,就会抛出异常。

为了给出好的建议,了解你要做什么可能会很有益。


1
只是为了澄清您非常正确的答案,无论实现如何,PKCS5填充都会在密文恰好为块大小时始终添加完整的块填充。否则,您将如何确定填充与密文之间的区别。 - jbtule
好的,那很有道理。 - laz
我需要它以这种方式工作,我正在尝试使用它来加密CCM块,因此块大小和加密数据的大小始终相同。我需要默认实现的原因是我需要编写一些单元测试,并且似乎已经使用了这个密码,因为我得到了完全相同的结果。谢谢您的答案,它确实帮了我很多! - Peter Jaloveczki
你可能会考虑使用CTR模式与初始化向量,正如Zim-Zam O'Pootertoot所提到的,因为它可以处理任意长度的数据而不需要填充。 - laz

3
你的密码实例正在使用PKCS5Padding填充,这会向密文添加最多16个字节的填充。有几种方法可以纠正此问题:
选项1:不要使用使用填充的Cipher.getInstance(“AES”),而要使用Cipher.getInstance(“AES / CBC / NoPadding”)。但是,这并不推荐,因为它要求明文是16字节的倍数。
选项2:使用BouncyCastle作为加密提供程序,然后使用
import org.bouncycastle.jce.provider.BouncyCastleProvider;
Cipher.getInstance("AES/CTR/NoPadding", new BouncyCastleProvider());

初始化密码。这里使用计数器模式(CTR)而不是密码块链接模式(CBC),计数器模式不需要任何填充。在计数器模式下,重要的是使用唯一的初始化向量,它可以与密文一起以明文形式传输;例如,

byte[] IV = new byte[16];
new SecureRandom().getBytes(IV);
cipher.init(Cipher.ENCRYPT_MODE, key, IV);

解密密文时,使用相同的初始化向量初始化密码。您可以自行决定如何传输IV,但是它不需要保密。

对于密码块链接模式,初始化向量也应该是唯一的,但这并不像计数器模式那样关键。


1
使用BouncyCastle并非使用CTR所必需,因此即使使用Oracle的提供程序也可以正常工作。 - laz

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