參考地址:html
http://www.javashuo.com/article/p-hsfrtrha-m.htmljava
http://www.javashuo.com/article/p-guigbega-md.htmlnode
https://github.com/stulzq/RSAExtensions(XC.RSAUtil) git
http://www.javashuo.com/article/p-upapmlxk-kz.html github
https://github.com/stulzq/RSAExtensions (RSAExtension)算法
參考以上的案例能夠解決在.net core 中的RSA加密解密(包括分段),簽名驗籤。spring
實際對接Java 時要根據Java的具體作法,作一些更改以適用於對接。apache
一、首先java是怎麼作的呢?提供一個java rsa 的工具類app
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; } }
二、.net core 如何來作 ?dom
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 } }
三、詳細解釋:
一、分段加密解密:參考中的.net core分段加密解密使用 ‘$’ 來做爲分段的標識,而java 中沒有,所以關鍵在於解密時找準分段的大小即代碼中的 splitLength,加密時爲117 ,而這個數字可由
var modulusLength = _publicKeyRsaProvider.KeySize / 8; var splitLength = modulusLength - PaddingLimitDic[padding];
來計算,當前寫死;解密時爲128,不要問我怎麼來的,我是調試加密代碼時,debug出來的。望有大佬給個理論的說法?
二、加簽驗籤:這裏有個坑爲 加簽驗籤時的算法名稱 HashAlgorithmName 必定要一致,java中爲MD5,對應 .net core 也要MD5,。上面的的代碼能夠改進一下,能夠改爲靜態方法,暴露出 HashAlgorithmName 參數
以上踩坑,Over!