.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!