我正在尝试使用当前使用Bouncy Castle提供程序在Java中执行的AES-256-CCM重现加密操作。当使用openssl在PHP中尝试相同的操作时,我找不到一组产生相同输出的参数。
由于最近将AEAD模式添加到PHP(7.1),因此文档的工作原理很少。
Java中“工作”加密的最小示例如下:
public static void main(String args[]) {
try {
java.security.Security.addProvider(new BouncyCastleProvider());
byte[] key = Base64.decodeBase64("Z4lAXU62WxDi46zSV67FeLj3hSK/th1Z73VD4/y6Eq4=".getBytes());
byte[] iv = Base64.decodeBase64("rcFcdcgZ3Q/A+uHW".getBytes());
SecretKey aesKey = new SecretKeySpec(key, 0, key.length, "AES");
Cipher aesCipher = Cipher.getInstance("AES/CCM/NoPadding", "BC");
aesCipher.init(1, aesKey, new IvParameterSpec(iv));
byte[] encrypted = aesCipher.doFinal("test".getBytes());
System.out.println(Hex.encodeHex(encrypted));
// Output: 411d89ff74205c106d8d85a8
}
catch (Throwable e) {
e.printStackTrace();
}
}
当我尝试使用不同的两个不同的库和语言重新生成它时,我已将键和iv设置为已知值。
当尝试使用PHP和openssl重新生成它时,我正在尝试使用以下代码
$key = base64_decode("Z4lAXU62WxDi46zSV67FeLj3hSK/th1Z73VD4/y6Eq4=");
$iv = base64_decode('rcFcdcgZ3Q/A+uHW');
$data = 'test';
$tag = null;
$encrypted = openssl_encrypt($data,'aes-256-ccm', $key,OPENSSL_RAW_DATA, $iv, $tag,"",8);
echo(bin2hex($encrypted . $tag));
// d1a7403799b8c37240f36edb
显然结果不符合。为了找到关于什么是不正确的答案,我在javascript中使用SJCL创建了相同的操作。这方面的例子是:
var data = "test";
var key = sjcl.codec.base64.toBits("Z4lAXU62WxDi46zSV67FeLj3hSK/th1Z73VD4/y6Eq4=");
var iv = sjcl.codec.base64.toBits("rcFcdcgZ3Q/A+uHW");
var p = {
adata: "",
iter: 0,
mode: "ccm",
ts: 64,
ks: 256,
iv: iv,
salt: ""
};
var encrypted = sjcl.encrypt(key, data, p, {});
console.log(encrypted);
// Output: {"iv":"rcFcdcgZ3Q/A+uHW","v":1,"iter":0,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"","ct":"QR2J/3QgXBBtjYWo"}
// QR2J/3QgXBBtjYWo === 411d89ff74205c106d8d85a8
Bouncy Castle和SJCL库产生相同的输出,但我不知道有什么不同。
我已尝试按Encrypt in Javascript with SJCL and decrypt in PHP中的建议预先处理PBKDF2的密钥,但没有成功。我试过SHA256的关键没有成功。
为什么php / openssl中的输出与Bouncy Castle和SJCL不同?
答案 0 :(得分:0)
当我偶然发现一个类似的问题时,我发现问题出在IV中,确切地说是它的长度。就使用长度小于12的IV而言,其哈希值相同。您可以使用自己的代码进行尝试:
java.security.Security.addProvider(new BouncyCastleProvider());
byte[] key = Base64.getDecoder().decode("Z4lAXU62WxDi46zSV67FeLj3hSK/th1Z73VD4/y6Eq4=".getBytes());
byte[] iv = "12345678901".getBytes();
SecretKey aesKey = new SecretKeySpec(key, 0, key.length, "AES");
Cipher aesCipher = Cipher.getInstance("AES/CCM/NoPadding", "BC");
aesCipher.init(1, aesKey, new IvParameterSpec(iv));
byte[] encrypted = aesCipher.doFinal("test".getBytes());
System.out.println(Hex.encodeHex(encrypted));
// Output: e037af9889af21e78252ab58
与PHP相同:
$key = base64_decode("Z4lAXU62WxDi46zSV67FeLj3hSK/th1Z73VD4/y6Eq4=");
$iv = "12345678901";
$tag = null;
$encrypted = openssl_encrypt("test", "aes-256-ccm", $key, OPENSSL_RAW_DATA, $iv, $tag, null, 8);
print bin2hex($encrypted . $tag);
# e037af9889af21e78252ab58
如果您延长IV,您会看到结果会有所不同。 注意!请记住,如果您将AES密钥缩短为128个字节,那么Java将自动切换到aes-128,但是在PHP中,您必须手动更改算法。