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

如何拆分Peppol AS4多部分请求二进制数据为IV、加密载荷和MAC标签?

问题:Peppol AS4规范下AES-128-GCM加密二进制部分解密失败

问题背景

我收到一个multipart/related请求,包含带有安全头和消息数据的SOAP部分,以及一个二进制部分。SOAP消息中包含加密二进制部分所用的密钥,我已成功获取。该二进制部分是经aes-128-gcm加密的gzip压缩字符串,结构为[iv][encryptedPayload][tag](iv前置、MAC标签后置)。

当我自行控制所有二进制数据时,加密解密均正常,但按Peppol AS4规范生成的二进制部分却无法正常处理,需指导如何正确编码及拆分该二进制部分。

自研加密解密示例代码

import crypto from 'crypto';

const plaintext = 'hello aes-128-gcm'; // 待加密字符串

const algorithm = 'aes-128-gcm';
const encryptionKey = crypto.randomBytes(16);
const nonce = crypto.randomBytes(12); // 生成要前置到 payload 的 iv
const cipher = crypto.createCipheriv(algorithm, encryptionKey, nonce); // 初始化加密器

let payloadEncrypted = cipher.update(Buffer.from(plaintext).toString('base64'), 'base64', 'binary');
payloadEncrypted += cipher.final('binary'); // 加密后的字符串
const tag = cipher.getAuthTag(); // 获取要追加到 payload 的 MAC 标签

const payload = nonce.toString('binary') + payloadEncrypted + tag.toString('binary');
console.log(payload); // 最终要提交的 payload

// 模拟请求 payload:构造示例 multipart 请求并进行 base64 编码
const body = `
--uuid:4535f302-c49e-4a8e-b32f-49c3da3577fc
Content-Type: application/soap+xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

<env:Envelope</env:Envelope>
--uuid:4535f302-c49e-4a8e-b32f-49c3da3577fc
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-ID: <0a7f6252-3854-4376-920d-5a01ae89a6e9@ip-10-10-131-116.eu-west-1.compute.internal>
CompressionType: application/gzip
MimeType: application/xml

${payload}
--uuid:4535f302-c49e-4a8e-b32f-49c3da3577fc--
`;
const b64Payload = Buffer.from(body).toString('base64');

// 解码 base64 请求并解密二进制部分的 payload
const request = Buffer.from(b64Payload, 'base64').toString();
const bData = Buffer.from(request.split('\n')[14], 'binary').toString('binary'); // 获取 payload

const splitNonce = bData.substring(0, 12); // 提取前置的 nonce
const splitEncryptedPayload = bData.substring(12, bData.length - 16); // 提取加密后的 payload
const splitTag = bData.substring(bData.length - 16); // 提取追加的标签

const decrypt = (content, tag, iv, password) => {
  const decipher = crypto.createDecipheriv(algorithm, Buffer.from(password, 'binary'), Buffer.from(iv, 'binary'));
  decipher.setAuthTag(Buffer.from(tag, 'binary'));
  let dec = decipher.update(content, 'binary', 'utf8');
  dec += decipher.final('utf8');
  return dec;
}

// 这里复用上面的 encryptionKey,实际场景中该密钥会加密后放在 SOAP 消息中
const decrypted = decrypt(splitEncryptedPayload, splitTag, splitNonce, encryptionKey);
console.log(decrypted); // 解密后的消息

遇到的错误

当用实际请求执行解密步骤时,解密函数抛出错误:[Error: Unsupported state or unable to authenticate data]


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 14:47:40