【问题标题】:AES-256-GCM decryption in nodejsnodejs中的AES-256-GCM解密
【发布时间】:2021-06-04 22:29:53
【问题描述】:

我正在尝试在将数据库中存储的数据发送到客户端之前对其进行解密。

我正在使用带有 AES-256-GCM 加密的内置加密模块。

我已经成功实施了加密并且它工作正常我的问题是我试图解密不同文件中的数据但我不断收到错误。

这是错误:

(node:35798) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The "iv" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined

1.js

router.post(
"/",
async(req, res) => {

function getFullAddress({housenumber, address1, address2, city, postcode, country}) {
return [housenumber, address1, ...(address2 ? [address2]: []), city, postcode, country].join(", ");
}

const aes256gcm = (key) => {

const encrypt = (str) => {
const iv = new crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);

let enc = cipher.update(str, 'utf8', 'base64');
enc += cipher.final('base64');
return Buffer.concat([Buffer.from(enc), iv, cipher.getAuthTag()]).toString("base64");
};

return {
encrypt,
};
};

const aesCipher = aes256gcm(key);

const hashedPasscode = await bcrypt.hash(req.body.passcode, 12);

        await User.create({
                            email: req.body.email,
                            mobilenumber: aesCipher.encrypt(req.body.mobilenumber),
                            passcode: hashedPasscode,
                            address: aesCipher.encrypt(getFullAddress(req.body))

                          })

2.js

router.get(
"/",
async(req, res) => {

const aes256gcm = (key) => {

  const decrypt = (enc, iv, authTag) => {
    const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
    decipher.setAuthTag(authTag);
    let str = decipher.update(enc, 'base64', 'utf8');
    str += decipher.final('utf8');
    return str;
  };

  return {
    decrypt,
  };
};

const aesCipher = aes256gcm(key);

const decrypted_MobileNumber = aesCipher.decrypt(user.mobilenumber);
const decrypted_address = aesCipher.decrypt(user.address);

console.log('decrypted_MobileNumber',decrypted_MobileNumber)
console.log('decrypted_address',decrypted_address)

这是存储在我的数据库中的数据示例

mobilenumber: 'Sm4xQjA2bmUwUUdEdW4zQkZ3PT3QEq5fBbTJ9ht4TgpQXTLmPYBSoQA836977j0rr3GYwg==',

【问题讨论】:

    标签: node.js encryption


    【解决方案1】:

    这是您在加密期间所做的:

    Buffer.concat([Buffer.from(enc), iv, cipher.getAuthTag()]).toString("base64");
    

    现在,您需要在解密期间将其反转:

    enc = Buffer.from(enc, "base64");
    const iv = enc.slice(enc.length-32, enc.length-16);
    const tag = enc.slice(enc.length-16);
    enc = enc.slice(0, enc.length-32);
    

    第二个问题是 GCM 模式的 nonce/iv 应该是 12 字节长。我已经改变了,所以上一期的一些索引也应该改变。

    第三个问题是您无法连接加密和 Base64 编码的块。您必须在 Base64 编码之前将它们连接起来,以便字符串中间没有 Base64 填充。这对 GCM 来说应该不是什么大问题,因为对 cipher.final('base64'); 的调用应该返回一个空字符串。

    第四个很明显的问题是,在加密过程中你要编码两次,但你只需要编码一次。

    这看起来像这样:

    const crypto = require('crypto');
    
    const aes256gcm = (key) => {
    
      const encrypt = (str) => {
        const iv = new crypto.randomBytes(12);
        const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
    
        let enc1 = cipher.update(str, 'utf8');
        let enc2 = cipher.final();
        return Buffer.concat([enc1, enc2, iv, cipher.getAuthTag()]).toString("base64");
      };
    
      const decrypt = (enc) => {
        enc = Buffer.from(enc, "base64");
        const iv = enc.slice(enc.length - 28, enc.length - 16);
        const tag = enc.slice(enc.length - 16);
        enc = enc.slice(0, enc.length - 28);
        const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
        decipher.setAuthTag(tag);
        let str = decipher.update(enc, null, 'utf8');
        str += decipher.final('utf8');
        return str;
      };
    
      return {
        encrypt,
        decrypt,
      };
    };
    
    const cipher = aes256gcm(Buffer.alloc(32)); // just a test key
    const ct = cipher.encrypt('test');
    const pt = cipher.decrypt(ct);
    console.log(pt);
    

    【讨论】:

    • 感谢您的回答,现在就试一试。我的编码问题是什么?
    • 你很晚才从 base64 解码,我把它移到开头。
    • 哦我现在明白了,因为我需要在切片 iv 和 auth 标签之前解码第一件事。我已经尝试过这个解决方案,但由于某种原因得到了这个错误(node:55820) UnhandledPromiseRejectionWarning: Error: Unsupported state or unable to authenticate data
    • 您好,非常感谢您的时间和帮助,非常感谢。你能指出我在哪里编码两次吗?我还是加密新手,这就是为什么
    • 加密期间enc已经是base64编码的密文。然后你做Buffer.from(enc),它使用默认的utf8解码而不是base64。然后你做toString("base64") 这是第二个base64编码
    猜你喜欢
    • 1970-01-01
    • 2018-10-29
    • 2021-01-10
    • 1970-01-01
    • 2021-09-23
    • 2021-03-05
    • 2019-02-27
    • 1970-01-01
    • 2021-11-07
    相关资源
    最近更新 更多