参考地址:
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;
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;
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;
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();
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
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
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
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();
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();
if (bt == 0x82)
var highbyte = binr.ReadByte();
var lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32(modint, 0);
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;
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!