报文签名验证和敏感信息解密报错: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。总体格式如下:
- 30 + LEN1 + 02 + LEN2 + 00 (optional) + r + 02 + LEN3 + 00(optional) + s
当r或s的第1字节大于0x80时,需要在r或s前加1字节0x00。 - LEN3为,0x00(optional) + s 的字节长度。
- LEN2为,0x00(optional) + r 的字节长度。
- 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
发布评论