来自 Java 脚本的 Java 无法识别加密字节?
Encrypted bytes is not recognized by Java from Javascript?
我已经在 Java 脚本上完成了 AES CTR 实施。现在我打算将加密的字节共享给 Java 以供进一步处理。但是我无法将值 return 从 JavaScript's Uint8Array
分配给 Java's byte[]
.
下面是 Uint8Array
格式的样本数据(AES CTR 加密后)
[71, 193, 223, 190, 6, 104, 11, 235, 249, 96, 54, 192, 233, 41, 198, 188, 15, 218, 10, 0, 61, 95, 58, 122, 74, 169, 27, 228, 121, 224, 128, 124, 198, 183, 23, 36, 89, 105, 184, 59, 245, 115, 244, 22, 122, 207, 217, 219, 160, 2, 227, 175, 134, 66, 165, 73, 102, 52, 14, 150, 182, 187, 228, 173, 96, 68, 11, 35, 166, 247, 45, 18, 202, 99, 81, 185, 216, 240, 66, 10, 105, 122, 45, 83]
当我在 byte[]
下的 Java
中传递从 JavaScript
收到的硬编码值时,如图所示,我收到了以下投诉。
byte[] resp = {71, 193, 223, 190, 6, 104, 11, 235, 249, 96, 54, 192, 233, 41, 198, 188, 15, 218, 10, 0, 61, 95, 58, 122, 74, 169, 27, 228, 121, 224, 128, 124, 198, 183, 23, 36, 89, 105, 184, 59, 245, 115, 244, 22, 122, 207, 217, 219, 160, 2, 227, 175, 134, 66, 165, 73, 102, 52, 14, 150, 182, 187, 228, 173, 96, 68, 11, 35, 166, 247, 45, 18, 202, 99, 81, 185, 216, 240, 66, 10, 105, 122, 45, 83};
// The complain is as follow:
Required type: byte
Provided: int
我这样做是为了解决上述问题:
byte[] resp = {71, (byte)193, (byte)223, (byte)190, 6, 104, 11, (byte)235, (byte)249, 96, 54, (byte)192, (byte)233, 41, (byte)198, (byte)188, 15, (byte)218, 10, 0, 61, 95, 58, 122, 74, (byte)169, 27, (byte)228, 121, (byte)224, (byte)128, 124, (byte)198, (byte)183, 23, 36, 89, 105, (byte)184, 59, (byte)245, 115, (byte)244, 22, 122, (byte)207, (byte)217, (byte)219, (byte)160, 2, (byte)227, (byte)175, (byte)134, 66, (byte)165, 73, 102, 52, 14, (byte)150, (byte)182, (byte)187, (byte)228, (byte)173, 96, 68, 11, 35, (byte)166, (byte)247, 45, 18, (byte)202, 99, 81, (byte)185, (byte)216, (byte)240, 66, 10, 105, 122, 45, 83};
下面是代码的一些实现
JS
var key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var textBytes = aesjs.utils.utf8.toBytes("textToEncrypt");
var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(16));
var encryptedBytes = aesCtr.encrypt(textBytes);
# Outcome of encryptedBytes
[71, 193, 223, 190, 6, 104, 11, 235, 249, 96, 54, 192, 233, 41, 198, 188, 15, 218, 10, 0, 61, 95, 58, 122, 74, 169, 27, 228, 121, 224, 128, 124, 198, 183, 23, 36, 89, 105, 184, 59, 245, 115, 244, 22, 122, 207, 217, 219, 160, 2, 227, 175, 134, 66, 165, 73, 102, 52, 14, 150, 182, 187, 228, 173, 96, 68, 11, 35, 166, 247, 45, 18, 202, 99, 81, 185, 216, 240, 66, 10, 105, 122, 45, 83]
Java
byte[] keyBytes = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte[] ivBytes = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
# Here I assign the value I've received from `Javascript` into `resp`
byte[] resp = {71, (byte)193, (byte)223, (byte)190, 6, 104, 11, (byte)235, (byte)249, 96, 54, (byte)192, (byte)233, 41, (byte)198, (byte)188, 15, (byte)218, 10, 0, 61, 95, 58, 122, 74, (byte)169, 27, (byte)228, 121, (byte)224, (byte)128, 124, (byte)198, (byte)183, 23, 36, 89, 105, (byte)184, 59, (byte)245, 115, (byte)244, 22, 122, (byte)207, (byte)217, (byte)219, (byte)160, 2, (byte)227, (byte)175, (byte)134, 66, (byte)165, 73, 102, 52, 14, (byte)150, (byte)182, (byte)187, (byte)228, (byte)173, 96, 68, 11, 35, (byte)166, (byte)247, 45, 18, (byte)202, 99, 81, (byte)185, (byte)216, (byte)240, 66, 10, 105, 122, 45, 83};
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] plaintext = cipher.doFinal(decoded);
String plaintextString = new String(plaintext, StandardCharsets.UTF_8);
# Here I expect the value `textToEncrypt` to be decrypted under variable `plaintextString`.
我做错了什么吗?例如,我在 Java
.
中设置计数器 (IV) 的方式
仅供参考信息
- cipher.getAlgorithm() 是 SunJCE 版本 15
问题是由于 java 字节数据类型是 8 位有符号二进制补码整数。它的最小值为 -128,最大值为 127(含),如官方 datatypes 教程中所述。这意味着像 193 这样的值是 int
而不是 byte
,所以编译器抱怨在字节数组中找到 int 值,你不得不将它们转换为字节,结果不可预测。您可以考虑改为声明 int 数组或 short 数组或 char 数组而不是字节数组来解决你的问题
在 Java 代码中,IV 指定不正确。
CTR Mode 逐块增加传递的 IV。 new aesjs.Counter(16)
在 Java 脚本代码中将 IV 的起始值设置为 16。
因此,Java代码中对应的是:
byte[] ivBytes = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16};
通过此更改,可以使用 Java 代码进行解密。
请注意,如果重复使用 key/IV 对,CTR 的安全性就会失效。由于通常密钥是固定的,这意味着不能使用固定的 IV(但是在发布的代码中是这种情况),请参阅 here 了解更多详细信息。
此外,CTR 不提供任何消息验证。这可以用 MAC 更正,或者可以使用 GCM 模式。这是基于 CTR 模式并且 隐式地 应用 MAC.
有关从 JavaScript 到 Java 代码的二进制数据的必要调整的解释,请参阅 。
传输二进制数据的替代方法是使用 binary to text encoding 将数据转换为字符串并传输该字符串。通常为此应用 Base64 或十六进制编码,例如使用 Base64:
var key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var textBytes = aesjs.utils.utf8.toBytes("The quick brown fox jumps over the lazy dog");
var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(16));
var encryptedBytes = aesCtr.encrypt(textBytes);
document.getElementById("bin").innerHTML = encryptedBytes; // 12,218,38,59,177,203,183,97,62,47,34,81,230,30,130,88,98,127,198,220,167,147,249,59,26,253,111,11,142,145,186,233,212,59,4,153,120,222,196,212,28,222,190
document.getElementById("b64").innerHTML = ui8ToB64(encryptedBytes); // DNomO7HLt2E+LyJR5h6CWGJ/xtynk/k7Gv1vC46RuunUOwSZeN7E1Bzevg==
// from
function ui8ToB64( arr ) {
return btoa(String.fromCharCode.apply(null, arr));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/aes-js/3.1.2/index.min.js"></script>
<p style="font-family:'Courier New', monospace;" id="bin"></p>
<p style="font-family:'Courier New', monospace;" id="b64"></p>
在Java端,内置Base64.Decoder#decode()
可用于Base64解码。
我已经在 Java 脚本上完成了 AES CTR 实施。现在我打算将加密的字节共享给 Java 以供进一步处理。但是我无法将值 return 从 JavaScript's Uint8Array
分配给 Java's byte[]
.
下面是 Uint8Array
格式的样本数据(AES CTR 加密后)
[71, 193, 223, 190, 6, 104, 11, 235, 249, 96, 54, 192, 233, 41, 198, 188, 15, 218, 10, 0, 61, 95, 58, 122, 74, 169, 27, 228, 121, 224, 128, 124, 198, 183, 23, 36, 89, 105, 184, 59, 245, 115, 244, 22, 122, 207, 217, 219, 160, 2, 227, 175, 134, 66, 165, 73, 102, 52, 14, 150, 182, 187, 228, 173, 96, 68, 11, 35, 166, 247, 45, 18, 202, 99, 81, 185, 216, 240, 66, 10, 105, 122, 45, 83]
当我在 byte[]
下的 Java
中传递从 JavaScript
收到的硬编码值时,如图所示,我收到了以下投诉。
byte[] resp = {71, 193, 223, 190, 6, 104, 11, 235, 249, 96, 54, 192, 233, 41, 198, 188, 15, 218, 10, 0, 61, 95, 58, 122, 74, 169, 27, 228, 121, 224, 128, 124, 198, 183, 23, 36, 89, 105, 184, 59, 245, 115, 244, 22, 122, 207, 217, 219, 160, 2, 227, 175, 134, 66, 165, 73, 102, 52, 14, 150, 182, 187, 228, 173, 96, 68, 11, 35, 166, 247, 45, 18, 202, 99, 81, 185, 216, 240, 66, 10, 105, 122, 45, 83};
// The complain is as follow:
Required type: byte
Provided: int
我这样做是为了解决上述问题:
byte[] resp = {71, (byte)193, (byte)223, (byte)190, 6, 104, 11, (byte)235, (byte)249, 96, 54, (byte)192, (byte)233, 41, (byte)198, (byte)188, 15, (byte)218, 10, 0, 61, 95, 58, 122, 74, (byte)169, 27, (byte)228, 121, (byte)224, (byte)128, 124, (byte)198, (byte)183, 23, 36, 89, 105, (byte)184, 59, (byte)245, 115, (byte)244, 22, 122, (byte)207, (byte)217, (byte)219, (byte)160, 2, (byte)227, (byte)175, (byte)134, 66, (byte)165, 73, 102, 52, 14, (byte)150, (byte)182, (byte)187, (byte)228, (byte)173, 96, 68, 11, 35, (byte)166, (byte)247, 45, 18, (byte)202, 99, 81, (byte)185, (byte)216, (byte)240, 66, 10, 105, 122, 45, 83};
下面是代码的一些实现
JS
var key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var textBytes = aesjs.utils.utf8.toBytes("textToEncrypt");
var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(16));
var encryptedBytes = aesCtr.encrypt(textBytes);
# Outcome of encryptedBytes
[71, 193, 223, 190, 6, 104, 11, 235, 249, 96, 54, 192, 233, 41, 198, 188, 15, 218, 10, 0, 61, 95, 58, 122, 74, 169, 27, 228, 121, 224, 128, 124, 198, 183, 23, 36, 89, 105, 184, 59, 245, 115, 244, 22, 122, 207, 217, 219, 160, 2, 227, 175, 134, 66, 165, 73, 102, 52, 14, 150, 182, 187, 228, 173, 96, 68, 11, 35, 166, 247, 45, 18, 202, 99, 81, 185, 216, 240, 66, 10, 105, 122, 45, 83]
Java
byte[] keyBytes = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte[] ivBytes = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
# Here I assign the value I've received from `Javascript` into `resp`
byte[] resp = {71, (byte)193, (byte)223, (byte)190, 6, 104, 11, (byte)235, (byte)249, 96, 54, (byte)192, (byte)233, 41, (byte)198, (byte)188, 15, (byte)218, 10, 0, 61, 95, 58, 122, 74, (byte)169, 27, (byte)228, 121, (byte)224, (byte)128, 124, (byte)198, (byte)183, 23, 36, 89, 105, (byte)184, 59, (byte)245, 115, (byte)244, 22, 122, (byte)207, (byte)217, (byte)219, (byte)160, 2, (byte)227, (byte)175, (byte)134, 66, (byte)165, 73, 102, 52, 14, (byte)150, (byte)182, (byte)187, (byte)228, (byte)173, 96, 68, 11, 35, (byte)166, (byte)247, 45, 18, (byte)202, 99, 81, (byte)185, (byte)216, (byte)240, 66, 10, 105, 122, 45, 83};
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] plaintext = cipher.doFinal(decoded);
String plaintextString = new String(plaintext, StandardCharsets.UTF_8);
# Here I expect the value `textToEncrypt` to be decrypted under variable `plaintextString`.
我做错了什么吗?例如,我在 Java
.
仅供参考信息
- cipher.getAlgorithm() 是 SunJCE 版本 15
问题是由于 java 字节数据类型是 8 位有符号二进制补码整数。它的最小值为 -128,最大值为 127(含),如官方 datatypes 教程中所述。这意味着像 193 这样的值是 int
而不是 byte
,所以编译器抱怨在字节数组中找到 int 值,你不得不将它们转换为字节,结果不可预测。您可以考虑改为声明 int 数组或 short 数组或 char 数组而不是字节数组来解决你的问题
在 Java 代码中,IV 指定不正确。
CTR Mode 逐块增加传递的 IV。 new aesjs.Counter(16)
在 Java 脚本代码中将 IV 的起始值设置为 16。
因此,Java代码中对应的是:
byte[] ivBytes = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16};
通过此更改,可以使用 Java 代码进行解密。
请注意,如果重复使用 key/IV 对,CTR 的安全性就会失效。由于通常密钥是固定的,这意味着不能使用固定的 IV(但是在发布的代码中是这种情况),请参阅 here 了解更多详细信息。
此外,CTR 不提供任何消息验证。这可以用 MAC 更正,或者可以使用 GCM 模式。这是基于 CTR 模式并且 隐式地 应用 MAC.
有关从 JavaScript 到 Java 代码的二进制数据的必要调整的解释,请参阅
传输二进制数据的替代方法是使用 binary to text encoding 将数据转换为字符串并传输该字符串。通常为此应用 Base64 或十六进制编码,例如使用 Base64:
var key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var textBytes = aesjs.utils.utf8.toBytes("The quick brown fox jumps over the lazy dog");
var aesCtr = new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(16));
var encryptedBytes = aesCtr.encrypt(textBytes);
document.getElementById("bin").innerHTML = encryptedBytes; // 12,218,38,59,177,203,183,97,62,47,34,81,230,30,130,88,98,127,198,220,167,147,249,59,26,253,111,11,142,145,186,233,212,59,4,153,120,222,196,212,28,222,190
document.getElementById("b64").innerHTML = ui8ToB64(encryptedBytes); // DNomO7HLt2E+LyJR5h6CWGJ/xtynk/k7Gv1vC46RuunUOwSZeN7E1Bzevg==
// from
function ui8ToB64( arr ) {
return btoa(String.fromCharCode.apply(null, arr));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/aes-js/3.1.2/index.min.js"></script>
<p style="font-family:'Courier New', monospace;" id="bin"></p>
<p style="font-family:'Courier New', monospace;" id="b64"></p>
在Java端,内置Base64.Decoder#decode()
可用于Base64解码。