繁体   English   中英

Java AES密文文本大小

[英]Java AES cipher text size

我正在使用一种非常标准的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位? 我觉得我有点混淆块大小的定义。

在接近你的问题之前,有一些必须要做的事情要做。 我在此代码中看到的一个有潜在危险的事情是,未使用显式模式和填充指定密码。 这意味着它取决于提供程序默认值。 如果这是当前与Oracle JVM一起分发的提供程序,则这些默认PKCS5Padding 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字节长度的倍数,因为它根本不会填充它。 如果不是,则抛出异常。

了解您正在尝试做什么以提供好的建议可能是有益的。

您的密码实例正在使用PKCS5Padding填充,它将最多16个字节的填充添加到密文。 有几种方法可以解决这个问题:

选项1:使用Cipher.getInstance(“AES / CBC / NoPadding”)而不是使用填充的Cipher.getInstance(“AES”)。 但是,不建议这样做,因为它要求明文是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,但同样,它不需要保密。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM