【发布时间】:2023-04-04 07:46:01
【问题描述】:
我正在编写一个 Chrome 扩展程序,它使用 CryptoJS 进行一些 Apache Thrift 工作。我目前正在尝试让 CryptoJS 工作。我正面临 CryptoJS 解密由 CryptoJS 加密的数据的问题。在问题描述之后,我在下面附上了一个测试用例。
发生的事情如下,我有一个“字节”数组:
var bArr = [11,0,1,0,0,0,6,100,105,103,101,115,116,11,0,2,0,0,0,152,67,119,65,66,65,65,65,65,69,109,78,111,99,109,57,116,90,83,49,48,90,88,78,48,76,87,78,115,97,87,86,117,100,65,103,65,65,103,65,65,49,68,69,75,65,65,77,65,65,65,65,65,86,75,102,66,85,103,115,65,66,65,65,65,65,67,81,49,90,68,99,119,77,71,73,120,78,67,48,121,78,84,90,107,76,84,81,119,77,109,81,116,79,84,65,48,90,105,48,52,79,84,86,105,78,68,73,50,89,109,78,108,78,84,99,76,65,65,85,65,65,65,65,85,89,50,104,121,98,50,49,108,76,87,78,115,97,87,86,117,100,67,49,122,90,87,78,121,90,88,81,65,11,0,3,0,0,0,36,52,51,52,55,54,56,98,53,45,50,48,102,102,45,52,99,100,102,45,56,53,97,50,45,57,49,49,56,50,98,55,98,51,102,57,53,0];
var stringToEncode = String.fromCharCode.apply(null, bArr);
我用 CryptoJS 加密它然后解密。加密前的前 25 个字节:
11,0,1,0,0,0,6,100,105,103,101,115,116,11,0,2,0,0,0,152,67,119,65,66,65
解密后:
11,0,1,0,0,0,6,100,105,103,101,115,116,11,0,2,0,0,0,194,152,67,119,65,66
唯一的区别是位置 20 处多了一个 194。显然,除了填充之外,所有其他字节都完全相同。我试图了解这是从哪里来的。
有关帽子的更多信息是这些字节。这是一个具有 3 个字段的 Thrift 结构,字段 2 包含另一个嵌入的 Thrift 结构的 Base64 表示。输入的前 20 个字节说明:
- 11,0,1:字符串类型的 Thrift 字段,fid 1
- 0,0,0,6:fid 1的值的int32长度
- 100,67,119,65,66,65:字符串“摘要”
- 11,0,2:字符串类型的 Thrift 字段,fid 2
- 0,0,0,152:fid 2的值的int32长度
- 67 ...直到下一个字节11:嵌入结构的Base64表示
由于解密问题,Thrift 解析器错误地识别了 fid 2 值的长度。
我相信我在 OpenSSL 模式下使用 AES256 CBC 和 32 字节密钥 (SHA256) 和 16 字节 IV,并带有 PKCS7 填充。
这是我的 qunit 测试。
test("Decryption", function() {
var bArr = [11,0,1,0,0,0,6,100,105,103,101,115,116,11,0,2,0,0,0,152,67,119,65,66,65,65,65,65,69,109,78,111,99,109,57,116,90,83,49,48,90,88,78,48,76,87,78,115,97,87,86,117,100,65,103,65,65,103,65,65,49,68,69,75,65,65,77,65,65,65,65,65,86,75,102,66,85,103,115,65,66,65,65,65,65,67,81,49,90,68,99,119,77,71,73,120,78,67,48,121,78,84,90,107,76,84,81,119,77,109,81,116,79,84,65,48,90,105,48,52,79,84,86,105,78,68,73,50,89,109,78,108,78,84,99,76,65,65,85,65,65,65,65,85,89,50,104,121,98,50,49,108,76,87,78,115,97,87,86,117,100,67,49,122,90,87,78,121,90,88,81,65,11,0,3,0,0,0,36,52,51,52,55,54,56,98,53,45,50,48,102,102,45,52,99,100,102,45,56,53,97,50,45,57,49,49,56,50,98,55,98,51,102,57,53,0];
var stringToEncode = String.fromCharCode.apply(null, bArr);
var symmetricKey = "v3JElaRswYgxOt4b";
var key = CryptoJS.enc.Latin1.parse( CryptoJS.enc.Latin1.stringify( CryptoJS.SHA256( symmetricKey ) ) );
var iv = CryptoJS.lib.WordArray.random( 16 );
var encrypted = CryptoJS.AES.encrypt( stringToEncode,
key,
{ iv: iv, format: CryptoJS.format.OpenSSL }
).ciphertext.toString(CryptoJS.enc.Latin1);
var decrypted = CryptoJS.AES.decrypt( { ciphertext: CryptoJS.enc.Latin1.parse(encrypted) },
key,
{ iv: iv, padding: CryptoJS.pad.NoPadding }
).toString(CryptoJS.enc.Latin1);
var buf = [];
for (var i=0; i<decrypted.length; i++) {
buf.push( decrypted.charCodeAt(i) );
}
var bstr1 = "";
for (var i=0; i<bArr.length; i++) {
bstr1 += (i>0) ? ","+bArr[i] : bArr[i]+"";
}
var bstr2 = "";
for (var i=0; i<buf.length; i++) {
bstr2 += (i>0) ? ","+buf[i] : buf[i]+"";
}
console.log("------------------------------------------");
console.log(bstr1);
console.log(bstr2);
console.log("------------------------------------------");
equal( stringToEncode.slice(0,200), decrypted.slice(0,200) );
});
我的测试 HTML 包装器会加载这些:
<script src="../bower_components/jquery/dist/jquery.min.js"></script>
<script src="../bower_components/js-base64/base64.js"></script>
<script src="../bower_components/thrift/lib/js/src/thrift.js"></script>
<script src="../bower_components/underscore/underscore-min.js"></script>
<script src="../bower_components/qunit/qunit/qunit.js"></script>
<script src="../bower_components/browserify-cryptojs/components/core.js"></script>
<script src="../bower_components/browserify-cryptojs/components/sha256.js"></script>
<script src="../bower_components/browserify-cryptojs/components/enc-base64.js"></script>
<script src="../bower_components/browserify-cryptojs/components/cipher-core.js"></script>
<script src="../bower_components/browserify-cryptojs/components/format-hex.js"></script>
<script src="../bower_components/browserify-cryptojs/components/aes.js"></script>
<script src="../bower_components/browserify-cryptojs/components/pad-nopadding.js"></script>
<!-- the Test Suite-->
<script type="text/javascript" src="test-client.js" charset="utf-8"></script>
<!-- CSS-->
<link rel="stylesheet" href="../bower_components/qunit/qunit/qunit.css" type="text/css" media="screen" />
我的 bower.json 是:
{
"name": "gossiperl-client-chrome",
"version": "0.1.0",
"main": "manifest.json",
"dependencies": {
"jquery": "~1.11.0",
"underscore": "~1.7.0",
"thrift": "radekg/thrift#js-binary-protocol",
"js-base64": "~2.1.5",
"qunit": "~1.14.0",
"browserify-cryptojs": "~0.3.1"
},
"authors": [
"radekg <...@....com>"
],
"description": "Gossiperl Chrome client with a sample application",
"keywords": [
"gossiperl",
"client"
],
"license": "MIT",
"homepage": "http://....com",
"private": true
}
【问题讨论】:
-
C2或 194 是 UTF-8 中两字节编码字符的一部分。欢迎来到 JavaScript 字符串/二进制地狱。哦,152 是第一个不属于 US-ASCII 的字符 - 需要用 UTF-8 编码两个字节。 -
啊,没有办法了吗?
-
我正在寻找它,但 CryptoJS 没有直接数组到
WordArray转换。答案可能是先转换为十六进制,然后从中创建一个WordArray(效率非常低,但 JavaScript 通常用于字节数组/加密操作)。 -
这有点难过。 Erlang、java、mono、ruby 中的所有其他软件都需要这种格式的数据——无需对外部摘要进行编码。正如您所说,也许直接从我的数组创建一个 wordarray 是一种选择。或者看看 NaCl :-/
-
保持你的马,只是一点编码/解码不应该阻止你:P
标签: javascript encryption aes cryptojs