如何拆分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
相关产品推荐
相关产品推荐

