runliuv

runliuv@cnblogs

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

 

在执行:

(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);

 

-

posted on 2025-06-10 09:50  runliuv  阅读(69)  评论(0)    收藏  举报