我正在使用一种非常标准的 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 位 key 和 128 位消息。我几乎总是能得到我期望的结果,但是,加密结果总是 256 位长。第二个 128 位总是相同的。除了截断结果,我如何确保密码仅返回前 128 位,而不更改前 128 位?我觉得我有点混淆了这里 block 大小的定义。
最佳答案
在处理您的问题之前,有一些强制性的事情需要解决。我在这段代码中看到的一件潜在危险的事情是密码没有指定显式模式和填充。这意味着它取决于提供者的默认设置。如果这是当前与 Oracle 的 JVM 一起分发的提供程序,则这些默认值是 ECB
和 PKCS5Padding
。如果这些是您想要使用的,则以这种方式指定它们:
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
第二个是 ECB
不是使用模式的好选择,因为它不是很安全。 CBC
是一个更好的选择,因为它使用了初始化 vector 。
关于问题。加密文本大小的原因是由于填充方案,在本例中为 PKCS5
。填充是必要的,以确保纯文本的长度是算法可以处理的。对于 AES,它必须是 16 字节的倍数。在未加密数据的长度已经是 16 字节的倍数的情况下,填充必须添加额外的 16 字节(请参阅此处的 jbtule 注释)。像这样初始化 Cipher
会产生 16 个字节的加密数据:
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
这要求未加密数据的长度已经是 16 字节的倍数,因为它根本不会填充它。如果不是,则抛出异常。
准确了解您要执行的操作可能有助于提供好的建议。
关于Java AES密文大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15880901/