节点Google Cloud KMS加密似乎有效,但解密失败

时间:2019-12-14 06:23:20

标签: node.js encryption google-cloud-platform google-cloud-kms

这是我的第一个堆栈溢出问题!

无论如何,我正在尝试使用Cloud KMS为我在App Engine中运行的Node API设置DB连接秘密的解密。为了使其正常工作,我一直在本地进行测试。我使用gcloud CLI加密了机密,然后将其上载到Cloud Storage存储桶(如果重要的话,可以使用与API不同的项目)。在API中提取加密的机密很好,但是当我尝试解密这些机密时,我得到了:

Error: 3 INVALID_ARGUMENT: Decryption failed: verify that 'name' refers to the correct CryptoKey.

我检查并重新检查我是否具有正确的项目ID,密钥环ID,密钥ID。

在上传到存储桶之前,我曾尝试在base64中对加密的机密进行编码。我尝试对API中的编码和加密机密进行硬编码。这些都不起作用。

因此,仅出于完整性检查的目的,我重新编写了代码以对字符串进行简单加密,然后使用相同的cryptoKeyPath对API进行解密。加密似乎可以正常工作,但是在解密过程中仍然出现上述错误。

(某些Cloud Storage代码仍然存在,但直到弄清楚解密后才使用)。

const Storage = require('@google-cloud/storage');
console.log(process.env.GOOGLE_APPLICATION_CREDENTIALS);

// if running in production we need to get the .env file from a storage bucket and decrypt.
const addSecretsToEnv = async () => {
    // setup for storage bucket
    const bucketName=<bucketName>;
    const fileName=<fileName>;
    const storage = new Storage.Storage();
    const file = storage.bucket(bucketName).file(fileName);

    // setup for KMS
    const client = new kms.KeyManagementServiceClient();
    const locationId = 'global';
    const projectId = <projectId>;
    const keyRingID = <keyRingID>;
    const keyID = <keyID>;

    try {
        const formattedName = client.cryptoKeyPath(
            projectId,
            locationId,
            keyRingID,
            keyID,
        );

        const [result] = await client.encrypt({
            name: formattedName,
            plainText: 'help me!!!'
        });

        console.log(typeof result);
        console.log(result);

        const cipherText = result.ciphertext;
        console.log(typeof cipherText);
        console.log(cipherText);

        const [decrypted] = await client.decrypt({
            name: formattedName,  
            cipherText,
        });

        console.log(decrypted);

    } catch(error) {
        console.log(error);
    }
}

module.exports = {
    addSecretsToEnv
};

我通过GOOGLE_APPLICATION_CREDENTIALS env变量设置了身份验证,该变量指向具有Cloud KMS CryptoKey Encrypter / Decrypter和Cloud KMS Admin角色(无奈地添加了admin角色)的服务帐户的JSON密钥文件。 / p>

有人可以帮我吗?

谢谢。

1 个答案:

答案 0 :(得分:0)

大写字母T是您的罪魁祸首。在Node中,没有值的键将扩展为它们的对象名称。例如,给定:

let foo = "banana";

foo传递到这样的对象中:

doTheThing({ foo });

扩展为:

doTheThing({ foo: foo }); // which is { foo: "banana" }

使用plainTextcipherText时,它们在Node对象中分别扩展为{plainText: "..."}{cipherText: "..."}。不幸的是,那些不是公认的字段,但是它们被默默地忽略了。因此,有效地您没有将任何纯文本或密文传递给任何API调用。

对空字符串进行加密 是有效的,但对空字符串进行解密则无效。这就是为什么您在加密时没有收到错误的原因。

要解决此问题,请将plainTextcipherText分别替换为plaintextciphertext。我个人建议您改为明确声明该函数的参数调用:

const [decrypted] = await client.decrypt({
  name: "projects/p/...",  
  ciphertext: myCiphertext,
});

否则,对变量进行微妙的重命名会以非常晦涩的方式彻底破坏代码。