You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从GCS下载加密数据后调用Google KMS API解密遇TYPE_BYTES错误求助

Google KMS Decrypt Error: "Invalid value at 'ciphertext' (TYPE_BYTES)"

我尝试从Google Cloud存储桶下载并解密数据,参考Google KMS的解密方案,但触发了"Invalid value at 'ciphertext' (TYPE_BYTES)"错误。我确认密文内容正确,推测问题出在向Google KMS API发送POST请求前数据类型被意外修改。

我的代码如下:

gcs.bucket(bucketName)
 .file('mysecret.txt.encrypted.txt')
 .download({ destination: 'mysecret.txt.encrypted.txt' })
 .then(() => {
 fs.readFile('mysecret.txt.encrypted.txt', (err, data) => {
 if (err) throw err;
 console.log("DATA: "+data);
 var formData = { ciphertext: data, };
 request.post({
 headers: {
 'Content-Type': 'application/json',
 'Authorization': 'Bearer ...'
 },
 url: 'https://cloudkms.googleapis.com/v1/projects/kms-raimarketplace/locations/global/keyRings/.../cryptoKeys/...:decrypt',
 form: formData
 }, function (err, httpResponse, body) {
 if (err) {
 console.log("ERROR: "+err);
 } else {
 console.log("BODY: "+body);
 }
 console.log(err, body);
 });
 });
 }).catch(e => {
 console.error('getEnv.js: There was an error: ${JSON.stringify(e, undefined, 2)}');
 });

返回的错误输出为:

{
 "error": {
 "code": 400,
 "message": "Invalid value at 'ciphertext' (TYPE_BYTES), ",
 "status": "INVALID_ARGUMENT",
 "details": [
 {
 "@type": "type.googleapis.com/google.rpc.BadRequest",
 "fieldViolations": [
 {
 "field": "ciphertext",
 "description": "Invalid value at 'ciphertext' (TYPE_BYTES), "
 }
 ]
 }
 ]
 }
}

请问我哪里操作有误,该如何修复?


问题根源分析

你遇到的问题主要有两个核心原因:

  1. 数据编码不符合要求:Google KMS的decrypt API明确要求ciphertext必须是Base64编码的字符串,但你直接将fs.readFile返回的原始Buffer对象传了进去,而且通过form字段发送请求时,Buffer会被自动转换成乱码的字符串或原始字节流,完全不符合API的格式要求。
  2. 请求格式冲突:你设置了Content-Type: application/json头部,但却用form字段发送表单数据——这两者是完全冲突的,JSON格式的请求需要把数据序列化为JSON字符串,而不是表单格式。

修复方案

修改代码时需要做以下两处关键调整:

1. 将密文Buffer转换为Base64字符串

调用data.toString('base64')把fs.readFile返回的Buffer转换成Base64编码,这是KMS API接受的唯一格式。

2. 正确发送JSON格式请求

把请求数据序列化为JSON字符串,用body字段传递,而不是form字段,同时保持Content-Type: application/json头部不变。

修改后的完整代码如下:

gcs.bucket(bucketName)
 .file('mysecret.txt.encrypted.txt')
 .download({ destination: 'mysecret.txt.encrypted.txt' })
 .then(() => {
 fs.readFile('mysecret.txt.encrypted.txt', (err, data) => {
 if (err) throw err;
 console.log("DATA (Base64): "+data.toString('base64'));
 // 转换为Base64编码
 const requestBody = { ciphertext: data.toString('base64') };
 request.post({
 headers: {
 'Content-Type': 'application/json',
 'Authorization': 'Bearer ...'
 },
 url: 'https://cloudkms.googleapis.com/v1/projects/kms-raimarketplace/locations/global/keyRings/.../cryptoKeys/...:decrypt',
 // 用body传递JSON序列化后的字符串
 body: JSON.stringify(requestBody)
 }, function (err, httpResponse, body) {
 if (err) {
 console.log("ERROR: "+err);
 } else {
 console.log("BODY: "+body);
 }
 console.log(err, body);
 });
 });
 }).catch(e => {
 console.error(`getEnv.js: There was an error: ${JSON.stringify(e, undefined, 2)}`);
 });

额外优化建议

  • 用async/await替代嵌套回调,让代码更简洁易读:
async function decryptSecret() {
  try {
    await gcs.bucket(bucketName).file('mysecret.txt.encrypted.txt').download({ destination: 'mysecret.txt.encrypted.txt' });
    const data = await fs.promises.readFile('mysecret.txt.encrypted.txt');
    const requestBody = { ciphertext: data.toString('base64') };
    const response = await request.post({
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ...'
      },
      url: 'https://cloudkms.googleapis.com/v1/projects/kms-raimarketplace/locations/global/keyRings/.../cryptoKeys/...:decrypt',
      body: JSON.stringify(requestBody)
    });
    console.log("BODY: ", response.body);
  } catch (e) {
    console.error(`getEnv.js: There was an error: ${JSON.stringify(e, undefined, 2)}`);
  }
}

decryptSecret();
  • 优先使用官方的Google Cloud KMS客户端库(@google-cloud/kms),它会自动处理编码、请求格式和身份验证,避免手动调用API的各种坑:
const { KeyManagementServiceClient } = require('@google-cloud/kms');
const client = new KeyManagementServiceClient();

async function decrypt() {
  const name = client.cryptoKeyPath('kms-raimarketplace', 'global', 'YOUR_KEY_RING_NAME', 'YOUR_CRYPTO_KEY_NAME');
  const data = await fs.promises.readFile('mysecret.txt.encrypted.txt');
  const [result] = await client.decrypt({
    name,
    ciphertext: data,
  });
  console.log('Plaintext: ', result.plaintext.toString());
}

decrypt();

内容的提问来源于stack exchange,提问作者TheProgrammer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:38:16