在执行:
(DerSequence)(new Asn1InputStream(derCipher)).ReadObject()
这行代码时,多数情况下正常,偶尔会报异常:
ex2:corrupted stream detected。InnerException:malformed integer
在网上查了资料:
https://blog.csdn.net/MAX_VALUE/article/details/138191123
是因为硬件加密机生成的大整数(BigInteger)不合规范导致的。低版本的BC库解密没问题(无校验),高版本的BC库默认加了校验,就会报这错。
JAVA 那边解决方法是:
System.setProperty("org.bouncycastle.asn1.allow_unsafe_integer", "true");
网上没有找到C#相关的设置,自己摸索了下:
//Environment.SetEnvironmentVariable(DerInteger.AllowUnsafeProperty, "true"); //或 Environment.SetEnvironmentVariable("Org.BouncyCastle.Asn1.AllowUnsafeInteger", "true");
可以读取全局变量来测试是否设置变量成功。
string myVal1 = Environment.GetEnvironmentVariable("Org.BouncyCastle.Asn1.AllowUnsafeInteger");
来源于DerInteger的源码:
internal static bool AllowUnsafe() { string environmentVariable = Platform.GetEnvironmentVariable("Org.BouncyCastle.Asn1.AllowUnsafeInteger"); if (environmentVariable != null) { return Platform.EqualsIgnoreCase("true", environmentVariable); } return false; }
--
代码调用链:
(DerSequence)(new Asn1InputStream(derCipher)).ReadObject() - return BuildObject(num, num2, num3); - return CreatePrimitiveDerObject(tagNo, definiteLengthInputStream, tmpBuffers); - 2 => new DerInteger(array, clone: false),
其中:DerInteger 中有安全检测。
decodeDERSM2Cipher 方法报错几率非常高。远高于encodeSM2CipherToDER方法。
--
或者不用BC库,手工解析C1C3C2加密数据:
https://blog.csdn.net/weixin_39142884/article/details/133989633 ,
底部的 asn1CipherDataToc1c3c2 方法。
已经翻译成C#代码了:
using CommonUtils; using JSNXYUN.Models; using Newtonsoft.Json; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Utilities.Encoders; using Org.BouncyCastle.X509; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; namespace JSNXYUN.Utils { /// <summary> /// 用于替换decodeDERSM2Cipher方法。 /// </summary> public class JsnxYunEncUtil2 { /* 加密数据的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; */ /// <summary> /// der编码的数据转为C1C3C2。( 用于替换decodeDERSM2Cipher方法。) /// </summary> /// <param name="asn1Data"></param> /// <returns></returns> public static byte[] asn1CipherDataToc1c3c2(byte[] asn1Data) { //原文:https://blog.csdn.net/weixin_39142884/article/details/133989633 int totalLen = (int)asn1Data[1]; int xlen = (int)asn1Data[3]; int ylen = (int)asn1Data[5 + xlen]; int c3len = (int)asn1Data[7 + xlen + ylen]; int c2len = 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 = readField(asn1Data, 4, xlen); byte[] yByte = readField(asn1Data, 6 + xlen, ylen); xByte = fixToCurveLengthBytes(xByte); yByte = fixToCurveLengthBytes(yByte); byte[] c3Byte = readField(asn1Data, 8 + xlen + ylen, c3len); byte[] c2Byte = readField(asn1Data, asn1Data.Length - c2len, c2len); byte[] c1c3c2Byte = mergeC1c3c2Byte(xByte, yByte, c3Byte, c2Byte); return c1c3c2Byte; } /// <summary> /// .net解密前要加04 /// </summary> /// <param name="originalArray"></param> /// <returns></returns> public static byte[] Insert04(byte[] originalArray) { byte[] newArray = new byte[originalArray.Length + 1]; // 新数组(长度+1) newArray[0] = 4; // 在首位插入4 Array.Copy(originalArray, 0, newArray, 1, originalArray.Length); // 复制原数组内容 return newArray; } public static byte[] readField(byte[] data, int fieldIndex, int fieldLen) { byte[] filedData = new byte[fieldLen]; Array.Copy(data, fieldIndex, filedData, 0, fieldLen); return filedData; } static int CURVE_LEN = 32; /// <summary> /// 过滤大数补位,转为Curve长度字节 /// </summary> /// <param name="src"></param> /// <returns></returns> private static byte[] fixToCurveLengthBytes(byte[] src) { if (src.Length == CURVE_LEN) { return src; } byte[] result = new byte[CURVE_LEN]; if (src.Length > CURVE_LEN) { Array.Copy(src, src.Length - result.Length, result, 0, result.Length); } else { Array.Copy(src, 0, result, result.Length - src.Length, src.Length); } return result; } /// <summary> /// 合并c1c3c2数据 /// </summary> /// <param name="xByte"></param> /// <param name="yByte"></param> /// <param name="c3"></param> /// <param name="c2"></param> /// <returns></returns> private static byte[] mergeC1c3c2Byte(byte[] xByte, byte[] yByte, byte[] c3, byte[] c2) { byte[] c1c3c2 = new byte[xByte.Length + yByte.Length + c3.Length + c2.Length]; Array.Copy(xByte, 0, c1c3c2, 0, xByte.Length); int offset = xByte.Length; Array.Copy(yByte, 0, c1c3c2, offset, yByte.Length); offset += yByte.Length; Array.Copy(c3, 0, c1c3c2, offset, c3.Length); offset += c3.Length; Array.Copy(c2, 0, c1c3c2, offset, c2.Length); return c1c3c2; } } }
使用代码:
encryptedKey = JsnxYunEncUtil2.asn1CipherDataToc1c3c2(encryptedKey); //asn1CipherDataToc1c3c2 这个里边不带04 encryptedKey = JsnxYunEncUtil2.Insert04(encryptedKey); // .net解密前要加04
但是:
用asn1CipherDataToc1c3c2替换decodeDERSM2Cipher方法后,还有其它地方报 malformed integer 错误。还不如关闭BC库的范围检测。。
在SM2加密后转der编码时(encodeSM2CipherToDER)报错(1500次测试出现17次):
encKey = GmUtil.Sm2Encrypt(keyData, encCert.GetPublicKey()); // ** 将SM2加密的密文转换为DER编码格式,不然服务器报解密错误 GLog.WLog("enveloped encodeSM2CipherToDER start "); encKey = encodeSM2CipherToDER(encKey);
-