简体   繁体   English

Java 无法从 Javascript 识别加密字节?

[英]Encrypted bytes is not recognized by Java from Javascript?

I've done the AES CTR implementation on Javascript.我已经在 J​​avascript 上完成了AES CTR实现。 Now I'm intended to share the encrypted bytes to Java for further processing.现在我打算将加密的字节共享给 Java 以进行进一步处理。 However I'm unable to assign the value return from JavaScript's Uint8Array to Java's byte[] .但是,我无法将从JavaScript's Uint8Array返回的值分配给Java's byte[]

Below's a sample data in Uint8Array format (After AES CTR encryption)以下是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]

When I pass try hardcoding value received from JavaScript in Java under byte[] as show, I received following complain.当我尝试通过硬编码从接收到的值JavaScriptJavabyte[]的演出,我收到以下抱怨。

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

I did this for resolving to the above issue :我这样做是为了解决上述问题

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};

Below is to show some implemented of the code下面是代码的一些实现

JS 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`.

Am I doing something wrong?难道我做错了什么? Eg, the way Im setting the counter(IV) in Java .例如,我在Java设置计数器(IV)的方式。

FYI info仅供参考

  • cipher.getAlgorithm() is SunJCE version 15 cipher.getAlgorithm() 是 SunJCE 版本 15

The problem is due to the fact in java the byte data type is an 8-bit signed two's complement integer.问题是由于在 java中字节数据类型是一个 8 位有符号二进制补码整数。 It has a minimum value of -128 and a maximum value of 127 (inclusive) , as stated for example in the official datatypes tutorial.它的最小值为 -128 ,最大值为 127 (含) ,如官方数据类型教程中所述。 This implies that values like 193 are int and not byte , so the compiler complains about to find int values inside a byte array and you are obliged to cast them to byte with unpredictable results.这意味着像 193 这样的值是int而不是byte ,所以编译器抱怨在字节数组中找到 int 值,你不得不将它们转换为字节,结果不可预测。 You can consider to instead declare an int array or a short array instead of a byte array to solve your problem您可以考虑改为声明一个int数组或一个数组而不是一个字节数组来解决您的问题

In the Java code the IV is specified incorrectly.在 Java 代码中,IV 指定不正确。

The CTR Mode increments the passed IV from block to block. CTR 模式会逐个块递增传递的 IV。 new aesjs.Counter(16) in the JavaScript code sets the starting value of the IV to 16. JavaScript 代码中的new aesjs.Counter(16)将 IV 的起始值设置为 16。

Therefore, the counterpart in the Java code is:因此,Java 代码中的对应物是:

byte[] ivBytes = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16};

With this change, decryption with the Java code works.通过此更改,可以使用 Java 代码进行解密。


Note that the security of CTR breaks down if key/IV pairs are used repeatedly.请注意,如果重复使用密钥/IV 对,CTR 的安全性就会失效。 Since usually the key is fixed, this means that no fixed IV may be used (which however is the case in the posted code), see here for more details.由于通常密钥是固定的,这意味着不能使用固定的 IV(但是在发布的代码中是这种情况),请参阅此处了解更多详细信息。

Also, CTR does not provide any authentication of the message.此外,CTR 不提供任何消息身份验证。 This can be corrected with a MAC, alternatively the GCM mode can be used.这可以通过 MAC 来纠正,或者可以使用GCM模式。 This is based on the CTR mode and implicitly applies a MAC.这基于 CTR 模式并隐式应用 MAC。


For an explanation of the necessary adaptation of the binary data regarding the transfer from JavaScript to Java code, see the other answer .有关从 JavaScript 到 Java 代码传输的二进制数据的必要调整的说明,请参阅其他答案

An alternative to the transfer of binary data would be to convert the data into a string using a binary to text encoding and to transfer this string.二进制数据传输的替代方法是使用二进制到文本编码将数据转换为字符串并传输该字符串。 Typically Base64 or hex encoding is applied for this, eg with Base64:通常为此应用 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 https://stackoverflow.com/a/11562550/9014097 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>

On the Java side, the built-in Base64.Decoder#decode() can be used for the Base64 decoding.在 Java 端,可以使用内置的Base64.Decoder#decode()进行 Base64 解码。

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

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