zoukankan      html  css  js  c++  java
  • .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!

  • 相关阅读:
    Android安全研究经验谈
    论文相关笔记5
    论文相关笔记4
    论文相关笔记3
    论文相关笔记2
    论文相关笔记1
    朝鲜RedStar_OS_3.0安装图解
    Careerup上的简历模板
    冒泡、二分排序
    火狐插件
  • 原文地址:https://www.cnblogs.com/caolingyi/p/12395379.html
Copyright © 2011-2022 走看看