.net core RSA 分段加密解密,签名验签(对接java)

参考地址:

https://www.cnblogs.com/stulzq/p/7757915.html

https://www.cnblogs.com/stulzq/p/8260873.html

https://github.com/stulzq/RSAExtensions(XC.RSAUtil)  

https://www.cnblogs.com/stulzq/p/12053976.html 

https://github.com/stulzq/RSAExtensions (RSAExtension)

 

参考以上的案例可以解决在.net core 中的RSA加密解密(包括分段),签名验签。

实际对接Java 时要根据Java的具体做法,做一些更改以适用于对接。

1、首先java是怎么做的呢?提供一个java rsa 的工具类

package com.card.psbc.facility.utils.xmlSignature;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;

import javax.crypto.Cipher;
import java.io.*;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @Auther:
 * @Description: //TODO  RSA2048加密    --如果需要改成1024的,需要改下生成方法的密钥长度并重新生成,然后MAX_DECRYPT_BLOCK改成128就可以了
 * @Date: 
 **/
public class RSAUtil2048 {

    //加密算法RSA
    public static final String KEY_ALGORITHM = "RSA";
    //签名算法
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
    //获取公钥的key
    private static final String PUBLIC_KEY = "RSAPublicKey";
    //获取私钥的key
    private static final String PRIVATE_KEY = "RSAPrivateKey";
    //RSA最大加密明文大小
    private static final int MAX_ENCRYPT_BLOCK = 117;
    //RSA最大解密密文大小
    private static final int MAX_DECRYPT_BLOCK = 256;


    /**
     * @return void
     * @Author:
     * @Description: //TODO 生成密钥对(公钥和私钥)文件并保存本地    下面的生成方法和这个差不多 只是不保存和初始密钥长度的地方有所区别
     * @Date: 
     * @Param: [filePath]  保存文件路径
     **/
    public static void genKeyPairByFilePath(String filePath) throws Exception {
        //KeyPairGenerator秘钥构成器,也就是可以生成一对秘钥,可以是公钥也可以是私钥,所以大部分用在非对称加密中   getInstance()设置密钥的格式
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //使用给定的随机源(和默认的参数集合)初始化确定密钥长度的密钥对生成器       SecureRandom()随机源
        keyPairGenerator.initialize(2048, new SecureRandom());
        //generateKeyPair()生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //强转成公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        //强转成私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        //二进制转字符串
        String publicKeyString = Base64.encode(publicKey.getEncoded());
        //二进制转字符串
        String privateKeyString = Base64.encode(privateKey.getEncoded());
        //下面是保存方法
        BufferedWriter publicbw = new BufferedWriter(new FileWriter(new File(filePath + "/publicKey")));
        BufferedWriter privatebw = new BufferedWriter(new FileWriter(new File(filePath + "/privateKey")));
        publicbw.write(publicKeyString);
        privatebw.write(privateKeyString);
        publicbw.flush();
        publicbw.close();
        privatebw.flush();
        privatebw.close();
    }

    /**
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @Author:
     * @Description: //TODO  生成密钥对(公钥和私钥)
     * @Date:
     **/
    public static Map<String, Object> genKeyPair() throws Exception {
        //秘钥构成器,也就是可以生成一对秘钥,可以是公钥也可以是私钥,所以大部分用在非对称加密中
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //设定密钥的大小整数值
        keyPairGen.initialize(2048);
        //generateKeyPair()生成密钥对
        KeyPair keyPair = keyPairGen.generateKeyPair();
        //强转成公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        //强转成私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * @Author:
     * @Description: //TODO  从文件中读取公钥或私钥
     * @Date: 
     * @Param: [filePath]
     * @return java.lang.String
     **/
    public static String readKeyFromFile(String filePath) {
        try {
            BufferedReader br = new BufferedReader(new FileReader(new File(filePath)));
            String readLine = null;
            StringBuilder sb = new StringBuilder();
            while ((readLine = br.readLine()) != null) {
                sb.append(readLine);
            }
            br.close();
            return sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param data       已加密数据
     * @param privateKey 私钥(BASE64编码)
     * @return java.lang.String
     * @Author:
     * @Description: //TODO  私钥加签
     * @Date: 
     **/
    public static String sign(byte[] data, String privateKey) throws Exception {
        //字符串解码为二进制数据
        byte[] keyBytes = Base64Utils.decode(privateKey);
        //私钥的ASN.1编码规范
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        //KeyFactory一般通过自己的静态方法keyFactory.generatePublic()获得;
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //根据给定的密钥材料生成私钥对象
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        //Signature类用做签名的,一般通过自己的静态方法getInstance("算法名称")获取
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        //通过传入的私钥初始化待签名对象
        signature.initSign(privateK);
        //更新待签名或验证的数据
        signature.update(data);
        //返回所有已更新的签名字节
        return Base64Utils.encode(signature.sign());
    }

    /**
     * @param data      已加密数据
     * @param publicKey 公钥(BASE64编码)
     * @param sign      数字签名
     * @return boolean
     * @Author:
     * @Description: //TODO  公钥验签
     * @Date: 
     **/
    public static boolean verify(byte[] data, String publicKey, String sign)
            throws Exception {
        //字符串解码为二进制数据
        byte[] keyBytes = Base64Utils.decode(publicKey);
        //密钥的X509编码
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        //KeyFactory一般通过自己的静态方法keyFactory.generatePublic()获得;
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //根据给定的密钥材料生成公钥对象
        PublicKey publicK = keyFactory.generatePublic(keySpec);
        //Signature类用做签名的,一般通过自己的静态方法getInstance("算法名称")获取
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        //通过给定的公钥初始化对象
        signature.initVerify(publicK);
        //更新待签名或验证的数据
        signature.update(data);
        //验证待传入的签名
        return signature.verify(Base64Utils.decode(sign));
    }

    /**
     * @param data      源数据
     * @param publicKey 公钥(BASE64编码)
     * @return java.lang.String
     * @Author:
     * @Description: //TODO  公钥加密
     * @Date: 
     **/
    public static String encryptByPublicKey(byte[] data, String publicKey)
            throws Exception {
        byte[] keyBytes = org.springframework.util.Base64Utils.decodeFromString(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(keySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        String s = org.springframework.util.Base64Utils.encodeToString(encryptedData);
//            System.out.println(s+"=====================================================");
        out.close();
        return s;
    }

    /**
     * @param encryptedData 已加密数据
     * @return byte[]
     * @Author:
     * @Description: //TODO  私钥解密
     * @Date:
     **/
    public static byte[] decryptByPrivateKey(String encryptedData, String privateKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        byte[] data = org.springframework.util.Base64Utils.decodeFromString(encryptedData);
        PKCS8EncodedKeySpec x509KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePrivate(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    /**
     * @param data       源数据
     * @param privateKey 私钥(BASE64编码)
     * @return java.lang.String
     * @Author:
     * @Description: //TODO  私钥加密
     * @Date:
     **/
    public static String encryptByPrivateKey(byte[] data, String privateKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        String s = org.springframework.util.Base64Utils.encodeToString(encryptedData);
//            System.out.println(s+"=====================================================");
        out.close();
        return s;
    }

    /**
     * @param encryptedData 已加密数据
     * @param publicKey     公钥(BASE64编码)
     * @return byte[]
     * @Author:
     * @Description: //TODO  公钥解密
     * @Date: 
     **/
    public static byte[] decryptByPublicKey(String encryptedData, String publicKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decode(publicKey);
        byte[] data = org.springframework.util.Base64Utils.decodeFromString(encryptedData);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }
}

2、.net core 如何来做 ?

using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Xml;

namespace Asmkt.Transmit.Core.Utilities
{
    /// <summary>
    /// RSA加解密 使用OpenSSL的公钥加密/私钥解密
    /// 作者:李志强
    /// 创建时间:2017年10月30日15:50:14
    /// QQ:501232752
    /// </summary>
    public class RSAHelper3
    {
        private readonly RSA _privateKeyRsaProvider;
        private readonly RSA _publicKeyRsaProvider;
        private readonly HashAlgorithmName _hashAlgorithmName;
        private readonly Encoding _encoding;

        /// <summary>
        /// 实例化RSAHelper
        /// </summary>
        /// <param name="rsaType">加密算法类型 RSA SHA1;RSA2 SHA256 密钥长度至少为2048</param>
        /// <param name="encoding">编码类型</param>
        /// <param name="privateKey">私钥</param>
        /// <param name="publicKey">公钥</param>
        public RSAHelper3(RSAType rsaType, Encoding encoding, string privateKey, string publicKey = null)
        {
            _encoding = encoding;
            if (!string.IsNullOrEmpty(privateKey))
            {
                _privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey);
            }

            if (!string.IsNullOrEmpty(publicKey))
            {
                _publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publicKey);
            }
            _hashAlgorithmName = HashAlgorithmName.SHA256;
            if (rsaType == RSAType.RSA)
            {
                _hashAlgorithmName = HashAlgorithmName.SHA1;
            }
            if (rsaType == RSAType.RSA2)
            {
                _hashAlgorithmName = HashAlgorithmName.SHA256;
            }
            if (rsaType == RSAType.MD5)
            {
                _hashAlgorithmName = HashAlgorithmName.MD5;
            }
        }

        #region 使用私钥签名

        /// <summary>
        /// 使用私钥签名
        /// </summary>
        /// <param name="data">原始数据</param>
        /// <returns></returns>
        public string Sign(string data)
        {
            byte[] dataBytes = _encoding.GetBytes(data);

            var signatureBytes = _privateKeyRsaProvider.SignData(dataBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1);

            return Convert.ToBase64String(signatureBytes);
        }

        #endregion

        #region 使用公钥验证签名

        /// <summary>
        /// 使用公钥验证签名
        /// </summary>
        /// <param name="data">原始数据</param>
        /// <param name="sign">签名</param>
        /// <returns></returns>
        public bool Verify(string data, string sign)
        {
            byte[] dataBytes = _encoding.GetBytes(data);
            var dataSign = sign.Replace(" ", "+");
            int mod4 = dataSign.Length % 4;
            if (mod4 > 0)
            {
                dataSign += new string('=', 4 - mod4);
            }

            byte[] signBytes = Convert.FromBase64String(dataSign);

            var verify = _publicKeyRsaProvider.VerifyData(dataBytes, signBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1);

            return verify;
        }

        #endregion

        #region 解密

        public string Decrypt(string cipherText)
        {
            if (_privateKeyRsaProvider == null)
            {
                throw new Exception("_privateKeyRsaProvider is null");
            }
            return Encoding.UTF8.GetString(_privateKeyRsaProvider.Decrypt(Convert.FromBase64String(cipherText), RSAEncryptionPadding.Pkcs1));
        }

        public string DecryptBigData(string dataStr)
        {
            //privateKey = RsaPrivateKeyJava2DotNet(privateKey);
            //FromXmlStringExtensions(rsa, privateKey);

            var data = dataStr.Split(new char[] { '$' }, StringSplitOptions.RemoveEmptyEntries);
            var byteList = new List<byte>();

            foreach (var item in data)
            {
                byteList.AddRange(_privateKeyRsaProvider.Decrypt(Convert.FromBase64String(item), RSAEncryptionPadding.Pkcs1));
            }
            return Encoding.UTF8.GetString(byteList.ToArray());
        }

        public string DecryptBigDataJava(string dataStr)
        {
            //privateKey = RsaPrivateKeyJava2DotNet(privateKey);
            //FromXmlStringExtensions(rsa, privateKey);

            dataStr = dataStr.Replace(" ", "+");
            int mod4 = dataStr.Length % 4;
            if (mod4 > 0)
            {
                dataStr += new string('=', 4 - mod4);
            }
            var byteList = new List<byte>();
            var data = Convert.FromBase64String(dataStr);

            var splitLength = 128;
            var splitsNumber = Convert.ToInt32(Math.Ceiling(data.Length * 1.0 / splitLength));

            var pointer = 0;
            for (int i = 0; i < splitsNumber; i++)
            {
                if (pointer + splitLength < data.Length)
                {
                    byte[] current = data.Skip(pointer).Take(splitLength).ToArray();
                    byteList.AddRange(_privateKeyRsaProvider.Decrypt(current, RSAEncryptionPadding.Pkcs1));
                    pointer += splitLength;
                }
                else
                {
                    byte[] current = data.Skip(pointer).Take(splitLength).ToArray();
                    byteList.AddRange(_privateKeyRsaProvider.Decrypt(current, RSAEncryptionPadding.Pkcs1));
                    pointer += splitLength;
                }
                //byte[] current = pointer + splitLength < data.Length ? data[pointer..(pointer + splitLength)] : data[pointer..];
            }
            return Encoding.UTF8.GetString(byteList.ToArray());
        }

        #endregion

        #region 加密

        public string Encrypt(string text)
        {
            if (_publicKeyRsaProvider == null)
            {
                throw new Exception("_publicKeyRsaProvider is null");
            }
            return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.Pkcs1));
        }

        public string EncryptBigData(string dataStr)
        {
            char connChar = '$';
            //publicKey = RsaPublicKeyJava2DotNet(publicKey);
            //FromXmlStringExtensions(rsa, publicKey);

            var data = Encoding.UTF8.GetBytes(dataStr);
            //var modulusLength = _publicKeyRsaProvider.KeySize / 8;
            //var splitLength = modulusLength - PaddingLimitDic[padding];
            var splitLength = 117;
            var sb = new StringBuilder();

            var splitsNumber = Convert.ToInt32(Math.Ceiling(data.Length * 1.0 / splitLength));

            var pointer = 0;
            for (int i = 0; i < splitsNumber; i++)
            {
                if (pointer + splitLength < data.Length)
                {
                    byte[] current = data.Skip(pointer).Take(splitLength).ToArray();
                    sb.Append(Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(current, RSAEncryptionPadding.Pkcs1)));
                    sb.Append(connChar);
                    pointer += splitLength;
                }
                else
                {
                    byte[] current = data.Skip(pointer).Take(data.Length - pointer).ToArray();
                    sb.Append(Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(current, RSAEncryptionPadding.Pkcs1)));
                    sb.Append(connChar);
                    pointer += splitLength;
                }
                //byte[] current = pointer + splitLength < data.Length ? data[pointer..(pointer + splitLength)] : data[pointer..];
            }

            return sb.ToString();
        }

        public string EncryptBigDataJava(string dataStr)
        {
            //publicKey = RsaPublicKeyJava2DotNet(publicKey);
            //FromXmlStringExtensions(rsa, publicKey);

            var data = Encoding.UTF8.GetBytes(dataStr);
            //var modulusLength = _publicKeyRsaProvider.KeySize / 8;
            //var splitLength = modulusLength - PaddingLimitDic[padding];
            var splitLength = 117;
            var byteList = new List<byte>();

            var splitsNumber = Convert.ToInt32(Math.Ceiling(data.Length * 1.0 / splitLength));

            var pointer = 0;
            for (int i = 0; i < splitsNumber; i++)
            {
                if (pointer + splitLength < data.Length)
                {
                    byte[] current = data.Skip(pointer).Take(splitLength).ToArray();
                    byteList.AddRange(_publicKeyRsaProvider.Encrypt(current, RSAEncryptionPadding.Pkcs1));
                    pointer += splitLength;
                }
                else
                {
                    byte[] current = data.Skip(pointer).Take(data.Length - pointer).ToArray();
                    byteList.AddRange(_publicKeyRsaProvider.Encrypt(current, RSAEncryptionPadding.Pkcs1));
                    pointer += splitLength;
                }
                //byte[] current = pointer + splitLength < data.Length ? data[pointer..(pointer + splitLength)] : data[pointer..];
            }
            return Convert.ToBase64String(byteList.ToArray());
        }
        #endregion

        #region 使用私钥创建RSA实例

        public RSA CreateRsaProviderFromPrivateKey(string privateKey)
        {
            var privateKeyBits = Convert.FromBase64String(privateKey);

            var rsa = RSA.Create();
            var rsaParameters = new RSAParameters();

            using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits)))
            {
                byte bt = 0;
                ushort twobytes = 0;
                twobytes = binr.ReadUInt16();
                if (twobytes == 0x8130)
                    binr.ReadByte();
                else if (twobytes == 0x8230)
                    binr.ReadInt16();
                else
                    throw new Exception("Unexpected value read binr.ReadUInt16()");

                twobytes = binr.ReadUInt16();
                if (twobytes != 0x0102)
                    throw new Exception("Unexpected version");

                bt = binr.ReadByte();
                if (bt != 0x00)
                    throw new Exception("Unexpected value read binr.ReadByte()");

                rsaParameters.Modulus = binr.ReadBytes(GetIntegerSize(binr));
                rsaParameters.Exponent = binr.ReadBytes(GetIntegerSize(binr));
                rsaParameters.D = binr.ReadBytes(GetIntegerSize(binr));
                rsaParameters.P = binr.ReadBytes(GetIntegerSize(binr));
                rsaParameters.Q = binr.ReadBytes(GetIntegerSize(binr));
                rsaParameters.DP = binr.ReadBytes(GetIntegerSize(binr));
                rsaParameters.DQ = binr.ReadBytes(GetIntegerSize(binr));
                rsaParameters.InverseQ = binr.ReadBytes(GetIntegerSize(binr));
            }

            rsa.ImportParameters(rsaParameters);
            return rsa;
        }

        #endregion

        #region 使用公钥创建RSA实例

        public RSA CreateRsaProviderFromPublicKey(string publicKeyString)
        {
            // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
            byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
            byte[] seq = new byte[15];

            var x509Key = Convert.FromBase64String(publicKeyString);

            // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
            using (MemoryStream mem = new MemoryStream(x509Key))
            {
                using (BinaryReader binr = new BinaryReader(mem))  //wrap Memory Stream with BinaryReader for easy reading
                {
                    byte bt = 0;
                    ushort twobytes = 0;

                    twobytes = binr.ReadUInt16();
                    if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                        binr.ReadByte();    //advance 1 byte
                    else if (twobytes == 0x8230)
                        binr.ReadInt16();   //advance 2 bytes
                    else
                        return null;

                    seq = binr.ReadBytes(15);       //read the Sequence OID
                    if (!CompareBytearrays(seq, seqOid))    //make sure Sequence for OID is correct
                        return null;

                    twobytes = binr.ReadUInt16();
                    if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
                        binr.ReadByte();    //advance 1 byte
                    else if (twobytes == 0x8203)
                        binr.ReadInt16();   //advance 2 bytes
                    else
                        return null;

                    bt = binr.ReadByte();
                    if (bt != 0x00)     //expect null byte next
                        return null;

                    twobytes = binr.ReadUInt16();
                    if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                        binr.ReadByte();    //advance 1 byte
                    else if (twobytes == 0x8230)
                        binr.ReadInt16();   //advance 2 bytes
                    else
                        return null;

                    twobytes = binr.ReadUInt16();
                    byte lowbyte = 0x00;
                    byte highbyte = 0x00;

                    if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
                        lowbyte = binr.ReadByte();  // read next bytes which is bytes in modulus
                    else if (twobytes == 0x8202)
                    {
                        highbyte = binr.ReadByte(); //advance 2 bytes
                        lowbyte = binr.ReadByte();
                    }
                    else
                        return null;
                    byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian order
                    int modsize = BitConverter.ToInt32(modint, 0);

                    int firstbyte = binr.PeekChar();
                    if (firstbyte == 0x00)
                    {   //if first byte (highest order) of modulus is zero, don't include it
                        binr.ReadByte();    //skip this null byte
                        modsize -= 1;   //reduce modulus buffer size by 1
                    }

                    byte[] modulus = binr.ReadBytes(modsize);   //read the modulus bytes

                    if (binr.ReadByte() != 0x02)            //expect an Integer for the exponent data
                        return null;
                    int expbytes = (int)binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
                    byte[] exponent = binr.ReadBytes(expbytes);

                    // ------- create RSACryptoServiceProvider instance and initialize with public key -----
                    var rsa = RSA.Create();
                    RSAParameters rsaKeyInfo = new RSAParameters
                    {
                        Modulus = modulus,
                        Exponent = exponent
                    };
                    rsa.ImportParameters(rsaKeyInfo);

                    return rsa;
                }

            }
        }

        #endregion

        #region 导入密钥算法

        private int GetIntegerSize(BinaryReader binr)
        {
            byte bt = 0;
            int count = 0;
            bt = binr.ReadByte();
            if (bt != 0x02)
                return 0;
            bt = binr.ReadByte();

            if (bt == 0x81)
                count = binr.ReadByte();
            else
            if (bt == 0x82)
            {
                var highbyte = binr.ReadByte();
                var lowbyte = binr.ReadByte();
                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                count = BitConverter.ToInt32(modint, 0);
            }
            else
            {
                count = bt;
            }

            while (binr.ReadByte() == 0x00)
            {
                count -= 1;
            }
            binr.BaseStream.Seek(-1, SeekOrigin.Current);
            return count;
        }

        private bool CompareBytearrays(byte[] a, byte[] b)
        {
            if (a.Length != b.Length)
                return false;
            int i = 0;
            foreach (byte c in a)
            {
                if (c != b[i])
                    return false;
                i++;
            }
            return true;
        }

        #endregion

        static readonly Dictionary<RSAEncryptionPadding, int> PaddingLimitDic = new Dictionary<RSAEncryptionPadding, int>()
        {
            [RSAEncryptionPadding.Pkcs1] = 11,
            [RSAEncryptionPadding.OaepSHA1] = 42,
            [RSAEncryptionPadding.OaepSHA256] = 66,
            [RSAEncryptionPadding.OaepSHA384] = 98,
            [RSAEncryptionPadding.OaepSHA512] = 130,
        };

        /// <summary>
        /// private key ,java->.net
        /// </summary>
        /// <param name="privateKey"></param>
        /// <returns></returns>
        public static string RsaPrivateKeyJava2DotNet(string privateKey)
        {
            if (string.IsNullOrEmpty(privateKey))
            {
                return string.Empty;
            }
            var privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
            return
                $"<RSAKeyValue><Modulus>{Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned())}</Modulus><Exponent>{Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned())}</Exponent><P>{Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned())}</P><Q>{Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned())}</Q><DP>{Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned())}</DP><DQ>{Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned())}</DQ><InverseQ>{Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned())}</InverseQ><D>{Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned())}</D></RSAKeyValue>";
        }

        /// <summary>
        /// 扩展FromXmlString
        /// </summary>
        /// <param name="rsa"></param>
        /// <param name="xmlString"></param>
        private static void FromXmlStringExtensions(RSA rsa, string xmlString)
        {
            var parameters = new RSAParameters();

            var xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xmlString);

            if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
            {
                foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
                {
                    switch (node.Name)
                    {
                        case "Modulus":
                            parameters.Modulus = (string.IsNullOrEmpty(node.InnerText)
                                ? null
                                : Convert.FromBase64String(node.InnerText));
                            break;
                        case "Exponent":
                            parameters.Exponent = (string.IsNullOrEmpty(node.InnerText)
                                ? null
                                : Convert.FromBase64String(node.InnerText));
                            break;
                        case "P":
                            parameters.P = (string.IsNullOrEmpty(node.InnerText)
                                ? null
                                : Convert.FromBase64String(node.InnerText));
                            break;
                        case "Q":
                            parameters.Q = (string.IsNullOrEmpty(node.InnerText)
                                ? null
                                : Convert.FromBase64String(node.InnerText));
                            break;
                        case "DP":
                            parameters.DP = (string.IsNullOrEmpty(node.InnerText)
                                ? null
                                : Convert.FromBase64String(node.InnerText));
                            break;
                        case "DQ":
                            parameters.DQ = (string.IsNullOrEmpty(node.InnerText)
                                ? null
                                : Convert.FromBase64String(node.InnerText));
                            break;
                        case "InverseQ":
                            parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText)
                                ? null
                                : Convert.FromBase64String(node.InnerText));
                            break;
                        case "D":
                            parameters.D = (string.IsNullOrEmpty(node.InnerText)
                                ? null
                                : Convert.FromBase64String(node.InnerText));
                            break;
                    }
                }
            }
            else
            {
                throw new Exception("Invalid XML RSA key.");
            }

            rsa.ImportParameters(parameters);
        }

        /// <summary>
        /// public key ,java->.net
        /// </summary>
        /// <param name="publicKey"></param>
        /// <returns>格式转换结果</returns>
        public static string RsaPublicKeyJava2DotNet(string publicKey)
        {
            if (string.IsNullOrEmpty(publicKey))
            {
                return string.Empty;
            }

            var publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
            return string.Format(
                "<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
                Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
                Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned())
            );
        }
    }

    /// <summary>
    /// RSA算法类型
    /// </summary>
    public enum RSAType
    {
        /// <summary>
        /// SHA1
        /// </summary>
        RSA = 0,
        /// <summary>
        /// RSA2 密钥长度至少为2048
        /// SHA256
        /// </summary>
        RSA2 = 1,
        MD5 = 2
    }
}

3、详细解释:

   1、分段加密解密:参考中的.net core分段加密解密使用 ‘$’ 来作为分段的标识,而java 中没有,因此关键在于解密时找准分段的大小即代码中的 splitLength,加密时为117 ,而这个数字可由 

    var modulusLength = _publicKeyRsaProvider.KeySize / 8;
    var splitLength = modulusLength - PaddingLimitDic[padding]; 

  来计算,当前写死;解密时为128,不要问我怎么来的,我是调试加密代码时,debug出来的。望有大佬给个理论的说法?

2、加签验签:这里有个坑为 加签验签时的算法名称 HashAlgorithmName 一定要一致,java中为MD5,对应 .net core 也要MD5,。上面的的代码可以改进一下,可以改成静态方法,暴露出 HashAlgorithmName  参数

 

以上踩坑,Over!

 

posted @ 2020-03-02 14:10  caolingyi  阅读(1509)  评论(0编辑  收藏  举报