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

采用encrypt->sign->encrypt流程封装数据时CMSException异常求助

解决DER长度错误:encrypt->sign->encrypt流程中的BouncyCastle CMS封装问题

你遇到的DER length more than 4 bytes: 98错误,根源在于重复使用了同一个CMSEnvelopedDataStreamGenerator实例来创建内层和外层的EnvelopedData。BouncyCastle的CMS流生成器是有状态的,不能被复用在多个加密操作中——复用会破坏内部的ASN.1编码状态,最终导致生成的内容结构混乱,触发解析时的长度校验失败。

问题代码分析

在你的加密流程中,你只初始化了一次envelopedGenerator,却用它同时创建了内层和外层的加密流:

envelopedGenerator = getCMSEnvelopedDataStreamGenerator(builder);
// 用同一个生成器创建内层加密流
OutputStream envelopedStream1 = envelopedGenerator.open(signingStream,settings.getEncryptor());
// 又用同一个生成器创建外层加密流
OutputStream envelopedStream2 = envelopedGenerator.open(CMSObjectIdentifiers.signedData,out,settings.getEncryptor());

这种复用会让生成器的编码状态混乱,最终生成的外层EnvelopedData不符合DER规范,解密后得到的SignedData内容存在编码错误,进而触发解析时的IOException。

修复方案

你需要为每一层加密操作创建独立的CMSEnvelopedDataStreamGenerator实例,确保每一层的加密都是状态干净、独立的。同时严格遵循encrypt→sign→encrypt的数据流顺序:

修改后的加密代码如下:

CMSSignedDataStreamGenerator signedGenerator;
try {
 signedGenerator = getCMSSignedDataStreamGenerator(builder);
 // 为内层加密创建独立生成器
 CMSEnvelopedDataStreamGenerator innerEnvelopedGenerator = getCMSEnvelopedDataStreamGenerator(builder);
 // 为外层加密创建独立生成器
 CMSEnvelopedDataStreamGenerator outerEnvelopedGenerator = getCMSEnvelopedDataStreamGenerator(builder);

 // 外层加密流:最终输出到out,内容类型为signedData
 OutputStream envelopedStream2 = outerEnvelopedGenerator.open(CMSObjectIdentifiers.signedData, out, settings.getEncryptor());
 // 签名流:内容类型为envelopedData,输出到外层加密流
 OutputStream signingStream = signedGenerator.open(CMSObjectIdentifiers.envelopedData, envelopedStream2, encapsulate);
 // 内层加密流:输出到签名流,加密原始内容
 OutputStream envelopedStream1 = innerEnvelopedGenerator.open(signingStream, settings.getEncryptor());

 // 按从内到外的顺序写入内容并关闭流,确保ASN.1结构完整编码
 content.writeTo(envelopedStream1);
 envelopedStream1.close();
 signingStream.close();
 envelopedStream2.close();
} catch (CMSException | MessagingException e) {
 throw new IOException(e.toString());
}

额外注意事项

  • 流关闭顺序:必须从内到外关闭流(内层加密流→签名流→外层加密流),确保每一层的ASN.1结构都能正确完成编码。
  • 生成器独立性:不仅是CMSEnvelopedDataStreamGenerator,CMSSignedDataStreamGenerator也不建议复用,每次签名操作都应创建新实例,避免状态污染。
  • 解密流程补全:你的测试代码中,解密外层EnvelopedData后解析CMSSignedData是正确的,但验证签名后,还需要从SignedData中提取内层EnvelopedData并再次解密,才能获取原始内容(如果需要的话)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:47:16