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

编程入门 行业动态 更新时间:2024-10-07 22:22:33

网联回执<a href=https://www.elefans.com/category/jswz/34/1768911.html style=报文签名验证和敏感信息解密报错:failed to construct sequence from byte[]: corrupted stream detected [国密SM2]"/>

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

网联回执报文签名验证和敏感信息解密报错: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;}

更多推荐

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

本文发布于:2024-02-13 21:10:10,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1760296.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:报文   回执   报错   网联   敏感

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!