网联回执报文签名验证和敏感信息解密报错:failed to construct sequence from byte[]: corrupted stream detected [国密SM2]

3 篇文章 0 订阅
2 篇文章 0 订阅

网联回执报文签名验证和敏感信息解密报错:failed to construct sequence from byte[]: corrupted stream detected [国密SM2]

验签问题场景参数:

使用BC包1.57版本将网联签名值格式: ASN.1(R,S)转加密机签名值格式:RS 过程报错

网联签名值格式: ASN.1(R,S)

加密机签名值格式:RS

转换解析过程: org.bouncycastle.asn1.ASN1Sequence.getInstance(网联签名值)

BC包版本:1.57

异常信息:java.lang.IllegalArgumentException: failed to construct sequence from byte[]: corrupted stream detected
异常情况: 随机出现

问题原因

使用BC包1.57版本将网联签名值格式: ASN.1(R,S)转加密机签名值格式:RS 过程报错,推断BC包1.57版本在解释网联签名值的ASN1数据格式有问题

解决方案:

根据网联签名算法的签名值格式来解析读取R值和S值

  • SM2签名结果
    签名格式为TLV嵌套格式,签名的主体分为R和S两部分。R(或S)的长度等于ECC私钥长度。R(或S)前的T为0x02,签名T为0x30。总体格式如下:
  1. 30 + LEN1 + 02 + LEN2 + 00 (optional) + r + 02 + LEN3 + 00(optional) + s
    当r或s的第1字节大于0x80时,需要在r或s前加1字节0x00。
  2. LEN3为,0x00(optional) + s 的字节长度。
  3. LEN2为,0x00(optional) + r 的字节长度。
  4. LEN1为,LEN2+LEN3+4字节长度。
    示例签名值:

** 1.57未报错签名: ** 304502210090538DC25A2F8FA9AB251C43D74351C524906188DEA497315A7EF9FA4D56D5210220001C61BA47FBA968F975A0A2381B2B9C1128C1B0C622AA8AA263CB08BA1F788B
**1.57报错签名: ** 3045022100B9BEA487F8E7D53950F197129CB3F2071E6F72B397891D28956B1FBA249A09EB0220208CFF213212A6D311CB4E8D122BE020E924CBC1E033B14C4BDFA12EE2BFD8D9

附解释测试代码
//签名值十六进制
String signvalue = "3045022100B9BEA487F8E7D53950F197129CB3F2071E6F72B397891D28956B1FBA249A09EB0220208CFF213212A6D311CB4E8D122BE020E924CBC1E033B14C4BDFA12EE2BFD8D9";
//签名值转二进制
Byte[] signValueData = Hex.decode(signvalue );
//读取LEN1
int len1 = (int) signValueData [1];
//读取LEN2
int len2 = signValueData [3];
//计算LEN3
int len3 = len1 - len2 - 4;
//计算R值长度&R值PADDING长度
int padRLen = len2 - 32;
int rLen = 32;
if(len2 < 32){
    rLen = len2;
    padRLen = 0;
}
//读取R值
byte[] rByte = readField(signValueData , 4 + padRLen, rLen);
if(len3>32){
    len3 = 32;
}
 //读取S值
byte[] sByte = readField(signValueData , signValueData .length - len3, len3);
byte[] rsByte = mergeByte(rByte, sByte);
return rsByte;


  • 相关方法代码
/**
     * 合并字节数组
     * 
     * @param bt1 字节数组1
     * @param bt2 字节数组2
     * @return
     * @throws Exception
     */
    public static byte[] mergeByte(byte[] bt1, byte[] bt2) {
        byte[] dest = new byte[bt1.length + bt2.length];
        System.arraycopy(bt1, 0, dest, 0, bt1.length);
        int offset = bt1.length;
        System.arraycopy(bt2, 0, dest, offset, bt2.length);
        return dest;
    }
 /**
     * 读取数据域
     * 
     * @param data       数据
     * @param fieldIndex 数据域起始索引
     * @param fieldLen   数据域数据长度
     * @return
     */
    public static byte[] readField(byte[] data, int fieldIndex, int fieldLen) {
        byte[] filedData = new byte[fieldLen];
        System.arraycopy(data, fieldIndex, filedData, 0, fieldLen);
        return filedData;
    }

    /**
     * ASN1格式签名值转RS格式签名值
     * @param asn1Base64Signature
     * @return
     */
    public static byte[] toRSSignature(String asn1Base64Signature) {
        byte[] signatureByte = Base64.getDecoder().decode(asn1Base64Signature);
        return toRSSignature(signatureByte);
    }

    /**
     * ASN1格式签名值转RS格式签名值
     * @param asn1Signature
     * @return
     */
    public static byte[] toRSSignature(byte[] asn1Signature) {
        int len1 = (int) asn1Signature[1];
        int len2 = asn1Signature[3];
        int len3 = len1 - len2 - 4;
        int padRLen = len2 - 32;
        int rLen = 32;
        if(len2 < 32){
            rLen = len2;
            padRLen = 0;
        }
        byte[] rByte = EMUtil.readField(asn1Signature, 4 + padRLen, rLen);
        if(len3>32){
            len3 = 32;
        }
       
        byte[] sByte = EMUtil.readField(asn1Signature, asn1Signature.length - len3, len3);
        byte[] rsByte = EMUtil.mergeByte(rByte, sByte);
        return rsByte;
    }
解密问题场景:

和验签类似,此问题是由于在读取解析网联格式ASN.1(C1C3C2)的密文值转换传递给加密机(加密机密文值格式:C1C3C2 )解密的过程中导致的一个报错。

问题场景参数:

网联密文值格式: ASN.1(C1C3C2)

加密机密文值格式:C1C3C2

转换解析过程: org.bouncycastle.asn1.ASN1Sequence.getInstance(网联密文值)

BC包版本:1.57

异常信息:java.lang.IllegalArgumentException: failed to construct sequence from byte[]: corrupted stream detected
异常情况: 随机出现

问题原因

网联格式ASN.1(C1C3C2)的密文值转换传递给加密机(加密机密文值格式:C1C3C2 )解密的过程报错,推断BC包1.57版本在解释网联加密数据值的ASN1数据格式有问题

解决方案:

根据网联ASN.1密文值格式来解析读取C1C3C2 格式的密文值

  • 加密数据的ASN.1 数据结构如下:
    CipherData ::= SEQUENCE {
    xcoordinate INTEGER,
    ycoordinate INTEGER,
    hash OCTET STRING,
    cigherText OCTET STRING
    }

  • C1C3C2格式对应:
    c1 = xcoordinate + ycoordinate
    c3 = hash;
    c2 = cigherText;

  • 格式解析如下:
    30 + totalLen + xTag + xlen + x + yTag + ylen +y + c3Tag + c3len + c3 + c2Tag + c2len + c2;

  • 示例数据:
    307c022100e739650179d8dea27e17c126c927a4c9934090b8921599bbe6463aff546ed7b5022021de9b9b3ca414c3e4d947cfb0df1a146caa427ee41cd687c4eed23097b9ea4e04200eb2f3e3f230cd0e5dd6d109d24c0913b76cb4e2a48e554a0018bd0b69b8e21d04130b5f55e5b98ee53bc43cdb55b730114cf75fd6

附网联国密ASN.1加密数据转C1C3C2格式密文测试代码

  • 直接上代码
/**
   * 加密数据的ASN.1 数据结构如下:
   *  CipherData ::= SEQUENCE {
   *      xcoordinate INTEGER,
   *      ycoordinate INTEGER,
   *      hash OCTET STRING,
   *      cigherText OCTET STRING
   *  }
   *
   *  C1C3C2格式对应:
   *  c1 = xcoordinate + ycoordinate
   *  c3 = hash;
   *  c2 = cigherText;
   *
   *  格式解析如下:
   *  30 + totalLen  + xTag + xlen + x  + yTag + ylen +y + c3Tag + c3len + c3 + c2Tag + c2len + c2;
   * @paramasn1Data
   * @throwsIOException
   */

  publicstaticbyte[] asn1CipherDataToc1c3c2(byte[] asn1Data) throwsIOException {

      inttotalLen = (int) asn1Data[1];
      intxlen = (int) asn1Data[3];
      intylen = (int) asn1Data[5 + xlen];
      intc3len = (int) asn1Data[7 + xlen + ylen];
      intc2len = totalLen - xlen - ylen - c3len - 8;
      System.out.println("totalLen>>" + totalLen);
      System.out.println("xlen>>" + xlen);
      System.out.println("ylen>>" + ylen);
      System.out.println("c3len>>" + c3len);
      System.out.println("c2len>>" + c2len);

      byte[] xByte = EMUtil.readField(asn1Data, 4, xlen);
      byte[] yByte = EMUtil.readField(asn1Data, 6 + xlen, ylen);
      xByte = fixToCurveLengthBytes(xByte);
      yByte = fixToCurveLengthBytes(yByte);
      byte[] c3Byte = EMUtil.readField(asn1Data, 8 + xlen + ylen, c3len);
      byte[] c2Byte = EMUtil.readField(asn1Data, asn1Data.length - c2len, c2len);
      byte[] c1c3c2Byte = mergeC1c3c2Byte(xByte, yByte, c3Byte, c2Byte);
      returnc1c3c2Byte;
  }

  /**
   * 过滤大数补位,转为Curve长度字节
   * @paramsrc
   * @return
   */
  privatestaticbyte[] fixToCurveLengthBytes(byte[] src) {

      if (src.length == CURVE_LEN) {
          returnsrc;
      }
      byte[] result = newbyte[CURVE_LEN];
      if (src.length > CURVE_LEN) {
          System.arraycopy(src, src.length - result.length, result, 0, result.length);
      } else {
          System.arraycopy(src, 0, result, result.length - src.length, src.length);
      }
      returnresult;
  }

  /**
   * 合并c1c3c2数据
   * @paramxByte
   * @paramyByte
   * @paramc3
   * @paramc2
   * @return
   */
  privatestaticbyte[] mergeC1c3c2Byte(byte[] xByte, byte[] yByte, byte[] c3, byte[] c2) {
      byte[] c1c3c2 = newbyte[xByte.length + yByte.length + c3.length + c2.length];
      System.arraycopy(xByte, 0, c1c3c2, 0, xByte.length);
      intoffset = xByte.length;
      System.arraycopy(yByte, 0, c1c3c2, offset, yByte.length);
      offset += yByte.length;
      System.arraycopy(c3, 0, c1c3c2, offset, c3.length);
      offset += c3.length;
      System.arraycopy(c2, 0, c1c3c2, offset, c2.length);
      returnc1c3c2;
  }
  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北海山人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值