我需要编写一个 Java 函数,该函数使用 AES256、CBC 模式和 PKCS#5 填充来加密字符串。我已经获得了一个密钥和一些前后示例,以便我可以验证我的实现。这就是我所拥有的一切。我发现预期的结果正是这个在线生成器产生的结果:https://encode-decode.com/aes-256-cbc-encrypt-online/
我必须向 Cipher 实例提供的参数之一是初始化向量(“IV”)。如果我不指定一个,Java 将使用随机一个,因此每次运行都会产生不同的结果,这不是我想要的行为。
上面的生成器不会要求用户提供 IV,但它仍然会产生与我的目标相同的结果。所以我想知道这怎么可能。人们是否倾向于使用相同的 IV(无论它是否安全),例如“0000000000000000”、“1234567812345678”(我都尝试过,以防万一)?或者有没有其他方法可以在不使用 IV 的情况下使用上述参数进行加密?
以防万一,这是我目前的代码:
package com.example.test;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class AesTest {
public static String key = "abcdefghijklmnopqrstuvwxyz012345";
public static String email = "[email protected]";
public static String initVector = "????????????????";
public static void main(String []args) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(
Cipher.ENCRYPT_MODE,
new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES"),
new IvParameterSpec(initVector.getBytes(StandardCharsets.UTF_8))
);
byte[] encrypted = cipher.doFinal(email.getBytes());
System.out.println(Base64.getEncoder().encodeToString(encrypted));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
是的,如果协议中未明确定义 IV,则通常会使用全零 IV 作为默认值。初始化向量与 CBC 的第一个明文块进行异或,因此如果所有bytes都设置为零值,则简单地保留明文。
请注意,重复使用 IV 作为密钥将会泄露哪些初始明文块与能够窃听密文消息的任何人相同。所以静态 IV 在大多数情况下都是不安全的。
如果使用全零(或静态)IV 进行解密会导致第一个块被随机化,而其余部分包含完整消息,则密文的第一个块实际上是 IV - 请参阅以下部分。
如果只有第一个块被成功解密,那么可能会使用EBC模式。
对于 Java,你可以像这样创建一个
IvParameterSpec
:
new IvParameterSpec(new byte[cipher.getBlockSize()]):
如果密码尚不可用,那么您可以将 AES 块大小定义为 16 字节。
private static final int AES_BLOCKSIZE = 16;
库实现通常会默认随机化 IV。将其作为密文前缀是很常见的。
CBC 仅在 IV 对于对手而言完全不可预测的情况下才提供语义安全性,即 IV 中的所有位对于对手来说必须是随机的。这意味着 IV 必须是“随机化”的,这可以通过随机 IV 或通过例如加密随机数并将其用作 IV。 如果您尝试使用第一个块解密密文,并且第一个明文块丢失,则 IV 要么是静态的,要么是以不同的方式计算的。