gpt4 book ai didi

javascript - AES GCM在nodejs中加密并在浏览器中解密?

转载 作者:行者123 更新时间:2023-12-03 17:14:08 27 4
gpt4 key购买 nike

我正在尝试在 nodejs 中加密一段字符串,并需要在前端 javascript 中解密它。在 nodejs 中,我使用的是加密库,而在前端使用的是网络加密。
在前端解密时遇到一些错误。

NodeJS

const crypto = require('crypto');
const iv = crypto.randomBytes(12);
const algorithm = 'aes-256-gcm';
let password = 'passwordpasswordpasswordpassword';
let text = 'Hello World!';
let cipher = crypto.createCipheriv(algorithm, password, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
var tag = cipher.getAuthTag();
let cipherObj = {
content: encrypted,
tag: tag,
iv: iv
}

前端
let cipherObj;  //GET FROM BE
let aesKey = await crypto.subtle.importKey(
"raw",
Buffer.from('passwordpasswordpasswordpassword'), //password
"AES-GCM",
true,
["decrypt"]
);

let decrypted = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: Buffer.from(cipherObj.iv),
tagLength: 128
},
aesKey,
Buffer.concat([Buffer.from(cipherObj.content), Buffer.from(cipherObj.tag)])
);

前端的解密函数抛出错误。
ERROR Error: Uncaught (in promise): OperationError
at resolvePromise (zone.js:814)
at zone.js:724
at rejected (main.js:231)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:388)
at Object.onInvoke (core.js:3820)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:387)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:138)
at zone.js:872
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
at Object.onInvokeTask (core.js:3811)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188)
at drainMicroTaskQueue (zone.js:595)

PS:我在前端使用 Angular 7

最佳答案

我能够通过一些更改来完成这项工作:

  • 我使用 SHA-256 对密码进行哈希处理,所以它可以是任意长度。 (OP 需要一个 32 字节的字符串。)
  • 我从 another answer 添加了额外的辅助函数用于将缓冲区转换为十六进制。
  • 我以 JSON 格式打印输出 cipherObj。这是您的加密消息有效负载。

  • 助手 - NodeJS 和浏览器
    // look up tables
    var to_hex_array = [];
    var to_byte_map = {};
    for (var ord=0; ord<=0xff; ord++) {
    var s = ord.toString(16);
    if (s.length < 2) {
    s = "0" + s;
    }
    to_hex_array.push(s);
    to_byte_map[s] = ord;
    }

    // converter using lookups
    function bufferToHex2(buffer) {
    var hex_array = [];
    //(new Uint8Array(buffer)).forEach((v) => { hex_array.push(to_hex_array[v]) });
    for (var i=0; i<buffer.length; i++) {
    hex_array.push(to_hex_array[buffer[i]]);
    }
    return hex_array.join('')
    }
    // reverse conversion using lookups
    function hexToBuffer(s) {
    var length2 = s.length;
    if ((length2 % 2) != 0) {
    throw "hex string must have length a multiple of 2";
    }
    var length = length2 / 2;
    var result = new Uint8Array(length);
    for (var i=0; i<length; i++) {
    var i2 = i * 2;
    var b = s.substring(i2, i2 + 2);
    result[i] = to_byte_map[b];
    }
    return result;
    }
    后端使用 hex2buffer,前端使用 buffer2hex,但您可以在两者中都包含该代码。
    所以后端代码是上面的助手加上:
    NodeJS
    const crypto = require('crypto');
    const iv = crypto.randomBytes(12);
    const algorithm = 'aes-256-gcm';
    let password = 'This is my password';
    let key = crypto.createHash("sha256").update(password).digest();
    let text = 'This is my test string, with 🎉 emoji in it!';
    let cipher = crypto.createCipheriv(algorithm, key, iv);
    let encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    var tag = cipher.getAuthTag();
    let cipherObj = {
    content: encrypted,
    tag: bufferToHex2(tag),
    iv: bufferToHex2(iv)
    }

    console.log(JSON.stringify(cipherObj));
    由于随机 IV,输出每次运行都会发生变化,但例如:
    {"content":"22da4796365ac1466f40022dd4510266fa3e24900b816f365e308cf06c95237783d1043c7deeb45d00381f8ff9ed","tag":"b7007905163b2d4890c9452c8edc1821","iv":"eb4758787164f95ac22ee50d"}
    那么示例前端代码就是上面的辅助函数,加上:
    浏览器
    let cipherObj;  //GET FROM BACKEND
    // For example:
    cipherObj = {"content":"22da4796365ac1466f40022dd4510266fa3e24900b816f365e308cf06c95237783d1043c7deeb45d00381f8ff9ed","tag":"b7007905163b2d4890c9452c8edc1821","iv":"eb4758787164f95ac22ee50d"}

    let password = 'This is my password';

    let enc = new TextEncoder();
    let key = await window.crypto.subtle.digest({ name:"SHA-256" }, enc.encode(password));
    let aesKey = await crypto.subtle.importKey(
    "raw",
    key,
    "AES-GCM",
    true,
    ["decrypt"]
    );

    let decrypted = await window.crypto.subtle.decrypt(
    {
    name: "AES-GCM",
    iv: hexToBuffer(cipherObj.iv),
    tagLength: 128
    },
    aesKey,
    hexToBuffer(cipherObj.content + cipherObj.tag)
    );

    let dec = new TextDecoder();
    console.log(dec.decode(decrypted));
    // This is my test string, with 🎉 emoji in it!
    一些加密 reference examples .

    关于javascript - AES GCM在nodejs中加密并在浏览器中解密?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55390714/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com