Google Cloud KMS:字段 ciphertext_crc32c 中的校验和与字段 ciphertext 中的数据不匹配

问题描述

我在设置系统以加密和解密 Node.js 后端中的数据时遇到问题。我正在关注this guide

我编写了一个辅助类 KMSEncryption 来抽象示例中的逻辑。这是我调用它的代码

const kms = new KMSEncryption();
const textToEncrypt = 'Hello World!';
const base64string = await kms.encrypt(textToEncrypt);
const decrypted = await kms.decrypt(base64string);

我遇到的问题是解密失败并出现以下错误

UnhandledPromiseRejectionWarning: E​​rror: 3 INVALID_ARGUMENT: 字段 ciphertext_crc32c 中的校验和与字段 ciphertext 中的数据不匹配。

我尝试与 Google 文档中的指南并排比较,但我看不出哪里出错了。

我尝试过的一些事情包括

  • base64string 转换为缓冲区
  • 尝试计算 base64string 缓冲区的校验和,而不是字符串本身

感谢任何帮助。谢谢

解决方法

我相信当你这样做时,你正在对密文进行 base64 编码:

        if (typeof ciphertext !== 'string') {
            return this.toBase64(ciphertext);
        }

但是在计算 crc32c 之前您没有反转编码。

我从示例代码中提取了这个示例,它在 Cloud Shell 中对我来说可以正常工作。 (抱歉有点乱):

// On Cloud Shell,install ts first with:
//   npm install -g typescript
//   npm i @types/node
//   npm i @google-cloud/kms
//   npm i fast-crc32c
// Then to compile and run:
//   tsc testcrc.ts && node testcrc.js

// Code adapted from https://cloud.google.com/kms/docs/encrypt-decrypt#kms-decrypt-symmetric-nodejs

const projectId = 'kms-test-1367';
const locationId = 'global';
const keyRingId = 'so-67778448';
const keyId = 'example';
const plaintextBuffer = Buffer.from('squeamish ossifrage');

// Imports the Cloud KMS library
const {KeyManagementServiceClient} = require('@google-cloud/kms');

const crc32c = require('fast-crc32c');

// Instantiates a client
const client = new KeyManagementServiceClient();

// Build the key name
const keyName = client.cryptoKeyPath(projectId,locationId,keyRingId,keyId);

// Optional,but recommended: compute plaintext's CRC32C.
async function encryptSymmetric() {
  const plaintextCrc32c = crc32c.calculate(plaintextBuffer);
  console.log(`Plaintext crc32c: ${plaintextCrc32c}`);
  const [encryptResponse] = await client.encrypt({
    name: keyName,plaintext: plaintextBuffer,plaintextCrc32c: {
      value: plaintextCrc32c,},});

  const ciphertext = encryptResponse.ciphertext;

  // Optional,but recommended: perform integrity verification on encryptResponse.
  // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:
  // https://cloud.google.com/kms/docs/data-integrity-guidelines
  if (!encryptResponse.verifiedPlaintextCrc32c) {
    throw new Error('Encrypt: request corrupted in-transit');
  }
  if (
    crc32c.calculate(ciphertext) !==
    Number(encryptResponse.ciphertextCrc32c.value)
  ) {
    throw new Error('Encrypt: response corrupted in-transit');
  }

  console.log(`Ciphertext: ${ciphertext.toString('base64')}`);
  console.log(`Ciphertext crc32c: ${encryptResponse.ciphertextCrc32c.value}`)
  return ciphertext;
}

async function decryptSymmetric(ciphertext) {
  const cipherTextBuf = Buffer.from(await ciphertext);
  const ciphertextCrc32c = crc32c.calculate(cipherTextBuf);
  console.log(`Ciphertext crc32c: ${ciphertextCrc32c}`);
  const [decryptResponse] = await client.decrypt({
    name: keyName,ciphertext: cipherTextBuf,ciphertextCrc32c: {
      value: ciphertextCrc32c,});

  // Optional,but recommended: perform integrity verification on decryptResponse.
  // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:
  // https://cloud.google.com/kms/docs/data-integrity-guidelines
  if (
    crc32c.calculate(decryptResponse.plaintext) !==
    Number(decryptResponse.plaintextCrc32c.value)
  ) {
    throw new Error('Decrypt: response corrupted in-transit');
  }

  const plaintext = decryptResponse.plaintext.toString();

  console.log(`Plaintext: ${plaintext}`);
  console.log(`Plaintext crc32c: ${decryptResponse.plaintextCrc32c.value}`)
  return plaintext;
}

decryptSymmetric(encryptSymmetric());

您可以看到它多次记录 crc32c。示例字符串“squeamish ossifrage”的正确 crc32c 是 870328919。密文的 crc32c 每次运行都会有所不同。

要自己运行此代码,只需将其指向您的项目、区域、密钥环和密钥(应该是对称加密密钥);希望将此代码与您的代码结果进行比较将有助于您找到问题。

感谢您使用 Google Cloud 和 Cloud KMS!