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

Node Google Cloud KMS encryption seems to work but decryption fails

这是我的第一个 Stack Overflow 问题!

无论如何,我正在尝试使用云 KMS 为节点设置数据库连接机密的解密 API 我在 App Engine 中有 运行。为了使它正常工作,我一直在本地对其进行测试。我使用 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 中对编码和加密的秘密进行硬编码。这些都不起作用。

因此,为了完整性检查,我重写了代码以简单地加密一个字符串,然后在 API 中使用相同的 cryptoKeyPath 对其进行解密。加密似乎有效,但我在解密过程中仍然遇到上述错误。

(一些云存储代码仍然存在,但在解密被弄清楚之前不会被使用)。

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 的服务帐户的 JSON 密钥文件管理员角色(无奈之下添加了管理员角色)。

有人可以帮我吗?

提前致谢。

首都T是你的罪魁祸首。在 Node 中,没有值的键会扩展为它们的对象名称。例如,给定:

let foo = "banana";

foo 传递给这样的对象:

doTheThing({ foo });

展开为:

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

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

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

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

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

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