在节点中使用aes-128-gcm“不支持的状态或无法验证数据”

时间:2016-12-21 15:58:20

标签: node.js encryption aes-gcm

我正在尝试使用节点加密提供的aes-128-gcm来实现加密/解密功能。根据我的理解,gcm对密文进行加密,但也对其进行哈希处理,并将其作为“身份验证标记”提供。但是,我不断收到错误:“不支持的状态或无法验证数据”。

我不确定这是否是我的代码中的错误 - 查看加密的密文和auth标记,解密函数提取的密码与加密函数生成的密码相同。

    function encrypt(plaintext) {
    // IV is being generated for each encryption
    var iv = crypto.randomBytes(12),
        cipher = crypto.createCipheriv(aes,key,iv),
        encryptedData = cipher.update(plaintext),
        tag;

    // Cipher.final has been called, so no more encryption/updates can take place
    encryptedData += cipher.final();

    // Auth tag must be generated after cipher.final()
    tag = cipher.getAuthTag();

    return encryptedData + "$$" + tag.toString('hex') + "$$" + iv.toString('hex');
}

function decrypt(ciphertext) {
    var cipherSplit = ciphertext.split("$$"),
        text = cipherSplit[0],
        tag = Buffer.from(cipherSplit[1], 'hex'),
        iv = Buffer.from(cipherSplit[2], 'hex'),
        decipher = crypto.createDecipheriv(aes,key,iv);

    decipher.setAuthTag(tag);

    var decryptedData = decipher.update(text);

    decryptedData += decipher.final();
}

decipher.final()抛出错误。

5 个答案:

答案 0 :(得分:1)

我设法解决了这个问题:问题是我没有为cipher.final()指定编码类型,而是在String中返回它,所以它没有返回一个Buffer对象,它是decipher.final ()期待。

要修复,我在cipher.update和cipher.final中的'hex'编码参数中添加'utf-8',反之亦然。

答案 1 :(得分:0)

为什么要重新发明轮子? kruptein处理大多数AES模式和密钥大小,并使用了authTagAADCCM模式下可用的GCMOCB功能。 / p>

const kruptein = require('kruptein');

kruptein.init({secret: 'squirrel'});

let ciphertext = kruptein.set('Foo Bar!');
let plaintext = kruptein.get(ciphertext);

答案 2 :(得分:0)

我的选择是:

1)下载crypto-js.js文件并保存在项目的lib文件夹中

2)导入库

const CryptoJS = require("../lib/crypto-js.js");

3)使用它(改编自@mayur-s answer

var encryptedMessage = CryptoJS.AES.encrypt(messageToencrypt, secretkey).toString();
var decryptedMessage = CryptoJS.AES.decrypt(encryptedMessage, secretkey).toString(CryptoJS.enc.Utf8);

答案 3 :(得分:0)

如果有人仍然试图获得加密和解密过程的工作示例。

我留下了一些应该考虑的意见。

import * as crypto from 'crypto';

const textToEncode = 'some secret text'; // utf-8
const algo = 'aes-128-gcm';

// Key bytes length depends on algorithm being used:
// 'aes-128-gcm' = 16 bytes
// 'aes-192-gcm' = 24 bytes
// 'aes-256-gcm' = 32 bytes
const key = crypto.randomBytes(16);

const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algo, key, iv);

const encrypted = Buffer.concat([
  cipher.update(Buffer.from(textToEncode, 'utf-8')),
  cipher.final(),
]);

const authTag = cipher.getAuthTag();

console.info('Value encrypted', {
  valueToEncrypt: textToEncode,
  encryptedValue: encrypted.toString('hex'),
  authTag: authTag.toString('hex'),
});

// It's important to use the same authTag and IV that were used during encoding
const decipher = crypto.createDecipheriv(algo, key, iv);
decipher.setAuthTag(authTag);

const decrypted = Buffer.concat([
  decipher.update(encrypted),
  decipher.final(),
]);

console.info('Value decrypted', {
  valueToDecrypt: encrypted.toString('hex'),
  decryptedValue: decrypted.toString('utf-8'),
});

答案 4 :(得分:-2)

为了更容易使用AES GCM,我编写了一个可以直接使用的npm包node-cryto-gcm。您还可以参考source code以了解AES GCM的工作原理。

npm install node-crypto-gcm

用法示例:

const GCM = require('node-crypto-gcm').GCM;

let plainText = 'To be or not to be, that is the question.';
let gcm = new GCM('password');

let output = gcm.encrypt(plainText);

let decryptedText = gcm.decrypt(output);    // decryptedText should equals plainText