加密解析:
//假设私钥长度为1024, 1024/8-11=117。
//如果明文的长度小于117,直接全加密,然后转base64。(data.Length <= maxBlockSize)
//如果明文长度大于117,则每117分一段加密,写入到另一个Stream中,最后转base64。while (blockSize > 0)
如果要和其它语言互通,这个分段长度需要和其它语言约定好,不一是 私钥长度/8-11。
解密解析:
//假设私钥长度为1024, 1024/8 =128。
//如果明文的长度小于 128,直接全解密。(data.Length <= maxBlockSize)
//如果明文长度大于 128,则每 128 分一段解密,写入到另一个Stream中,最后 GetString。while (blockSize > 0)
核心重点是拿到 .NET 的RSACryptoServiceProvider 对象。
nuget 中引用 Portable.BouncyCastle。
工具类:
RsaUtil:
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace CommonUtils
{
public static class RsaUtil
{
#region 加载私钥
///
/// 转换私钥字符串为RSACryptoServiceProvider
///
/// 私钥字符串
/// PKCS8,PKCS1
/// RSA 私钥长度1024 ,RSA2 私钥长度2048
///
public static RSACryptoServiceProvider LoadPrivateKey(string privateKeyStr, string keyFormat)
{
string signType = "RSA";
if (privateKeyStr.Length > 1024)
{
signType = "RSA2";
}
//PKCS8,PKCS1
if (keyFormat == "PKCS1")
{
return LoadPrivateKeyPKCS1(privateKeyStr, signType);
}
else
{
return LoadPrivateKeyPKCS8(privateKeyStr);
}
}
///
/// PKCS1 格式私钥转 RSACryptoServiceProvider 对象
///
/// pcsk1 私钥的文本内容
/// RSA 私钥长度1024 ,RSA2 私钥长度2048
///
public static RSACryptoServiceProvider LoadPrivateKeyPKCS1(string privateKeyPemPkcs1, string signType)
{
try
{
privateKeyPemPkcs1 = privateKeyPemPkcs1.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();
privateKeyPemPkcs1 = privateKeyPemPkcs1.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();
byte[] data = null;
//读取带
data = Convert.FromBase64String(privateKeyPemPkcs1);
RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(data, signType);
return rsa;
}
catch (Exception ex)
{
throw ex;
}
return null;
}
private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey, string signType)
{
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
MemoryStream mem = new MemoryStream(privkey);
BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;
int elems = 0;
try
{
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();
if (twobytes != 0x0102) //version number
return null;
bt = binr.ReadByte();
if (bt != 0x00)
return null;
//------ all private key components are Integer sequences ----
elems = GetIntegerSize(binr);
MODULUS = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
E = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
D = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
P = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
Q = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DP = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DQ = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
IQ = binr.ReadBytes(elems);
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
CspParameters CspParameters = new CspParameters();
CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
int bitLen = 1024;
if ("RSA2".Equals(signType))
{
bitLen = 2048;
}
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(bitLen, CspParameters);
//RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAparams = new RSAParameters();
RSAparams.Modulus = MODULUS;
RSAparams.Exponent = E;
RSAparams.D = D;
RSAparams.P = P;
RSAparams.Q = Q;
RSAparams.DP = DP;
RSAparams.DQ = DQ;
RSAparams.InverseQ = IQ;
RSA.ImportParameters(RSAparams);
return RSA;
}
catch (Exception ex)
{
throw ex;
// return null;
}
finally
{
binr.Close();
}
}
private static int GetIntegerSize(BinaryReader binr)
{
byte bt = 0;
byte lowbyte = 0x00;
byte highbyte = 0x00;
int count = 0;
bt = binr.ReadByte();
if (bt != 0x02) //expect integer
return 0;
bt = binr.ReadByte();
if (bt == 0x81)
count = binr.ReadByte(); // data size in next byte
else
if (bt == 0x82)
{
highbyte = binr.ReadByte(); // data size in next 2 bytes
lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32(modint, 0);
}
else
{
count = bt; // we already have the data size
}
while (binr.ReadByte() == 0x00)
{ //remove high order zeros in data
count -= 1;
}
binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte
return count;
}
///
/// PKCS8 文本转RSACryptoServiceProvider 对象
///
///
///
public static RSACryptoServiceProvider LoadPrivateKeyPKCS8(string privateKeyPemPkcs8)
{
try
{
//PKCS8是“BEGIN PRIVATE KEY”
privateKeyPemPkcs8 = privateKeyPemPkcs8.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();
privateKeyPemPkcs8 = privateKeyPemPkcs8.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();
//pkcs8 文本先转为 .NET XML 私钥字符串
string privateKeyXml = RSAPrivateKeyJava2DotNet(privateKeyPemPkcs8);
RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
publicRsa.FromXmlString(privateKeyXml);
return publicRsa;
}
catch (Exception ex)
{
throw ex;
}
}
///
/// PKCS8 私钥文本 转 .NET XML 私钥文本
///
///
///
public static string RSAPrivateKeyJava2DotNet(string privateKeyPemPkcs8)
{
RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKeyPemPkcs8));
return string.Format("{0} {1} {2}
{3}
{4} {5} {6} {7} ",
Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
}
#endregion
///
/// 加载公钥证书
///
/// 公钥证书文本内容
///
public static RSACryptoServiceProvider LoadPublicCert(string publicKeyCert)
{
publicKeyCert = publicKeyCert.Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", "").Replace("\r", "").Replace("\n", "").Trim();
byte[] bytesCerContent = Convert.FromBase64String(publicKeyCert);
X509Certificate2 x509 = new X509Certificate2(bytesCerContent);
RSACryptoServiceProvider rsaPub = (RSACryptoServiceProvider)x509.PublicKey.Key;
return rsaPub;
}
///
/// pem 公钥文本 转 .NET RSACryptoServiceProvider。
///
///
///
public static RSACryptoServiceProvider LoadPublicKey(string publicKeyPem)
{
publicKeyPem = publicKeyPem.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();
//pem 公钥文本 转 .NET XML 公钥文本。
string publicKeyXml = RSAPublicKeyJava2DotNet(publicKeyPem);
RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
publicRsa.FromXmlString(publicKeyXml);
return publicRsa;
}
///
/// pem 公钥文本 转 .NET XML 公钥文本。
///
///
///
private static string RSAPublicKeyJava2DotNet(string publicKey)
{
RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
return string.Format("{0} {1} ",
Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
}
}
}
RsaEncryptUtil:
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace CommonUtils
{
public static class RsaEncryptUtil
{
#region 非标准的-私钥加密-公钥解密
///
/// 私钥加密 .Net平台默认是使用公钥进行加密,私钥进行解密。私钥加密需要自己实现或者使用第三方dll
///
///
/// 私钥,格式:PKCS8
///
public static byte[] encryptByPrivateKey(String data, String key)
{
String priKey = key.Trim();
String xmlPrivateKey = RSAPrivateKeyJava2DotNet(priKey);
//加载私钥
RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();
privateRsa.FromXmlString(xmlPrivateKey);
//转换密钥
AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);
IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致
c.Init(true, keyPair.Private); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
byte[] DataToEncrypt = Encoding.UTF8.GetBytes(data);
byte[] outBytes = c.DoFinal(DataToEncrypt);//加密
return outBytes;
}
///
/// 私钥加密
///
/// 明文
/// 私钥
/// 私钥格式:PKCS1,PKCS8
///
public static byte[] encryptByPrivateKey(String data, String key, string keyFormat)
{
String priKey = key.Trim();
//加载私钥
RSACryptoServiceProvider privateRsa = RsaUtil.LoadPrivateKey(key, keyFormat);
//转换密钥
AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);
IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致
c.Init(true, keyPair.Private); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
byte[] DataToEncrypt = Encoding.UTF8.GetBytes(data);
byte[] outBytes = c.DoFinal(DataToEncrypt);//加密
return outBytes;
}
///
/// RSA私钥格式转换,java->.net
///
///
///
private static string RSAPrivateKeyJava2DotNet(string privateKey)
{
RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
return string.Format("{0} {1} {2}
{3}
{4} {5} {6} {7} ",
Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
}
///
/// 用公钥解密
///
///
///
///
public static byte[] decryptByPublicKey(String data, String key)
{
String pubKey = key.Trim();
String xmlPublicKey = RSAPublicKeyJava2DotNet(pubKey);
RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
publicRsa.FromXmlString(xmlPublicKey);
AsymmetricKeyParameter keyPair = DotNetUtilities.GetRsaPublicKey(publicRsa);
//转换密钥
// AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetRsaKeyPair(publicRsa);
IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致
c.Init(false, keyPair); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥
byte[] DataToEncrypt = Convert.FromBase64String(data);
byte[] outBytes = c.DoFinal(DataToEncrypt);//解密
return outBytes;
}
///
/// RSA公钥格式转换,java->.net
///
///
///
private static string RSAPublicKeyJava2DotNet(string publicKey)
{
RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
return string.Format("{0} {1} ",
Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
}
#endregion
#region 标准的-公钥加密-私钥解密
/** 默认编码字符集 */
private static string DEFAULT_CHARSET = "UTF-8";
///
/// 公钥加密(超过 私钥长度 / 8 - 11,分段加密)
///
/// 明文
/// 编码
/// 公钥
///
///
public static string RSAEncrypt(string content, string charset, string publicKeyPem)
{
try
{
//假设私钥长度为1024, 1024/8-11=117。
//如果明文的长度小于117,直接全加密,然后转base64。(data.Length <= maxBlockSize)
//如果明文长度大于117,则每117分一段加密,写入到另一个Stream中,最后转base64。while (blockSize > 0)
RSACryptoServiceProvider rsa = RsaUtil.LoadPublicKey(publicKeyPem);
//string sPublicKeyPEM = File.ReadAllText(publicKeyPem);
//RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
//rsa.PersistKeyInCsp = false;
//RSACryptoServiceProviderExtension.LoadPublicKeyPEM(rsa, sPublicKeyPEM);
if (string.IsNullOrEmpty(charset))
{
charset = DEFAULT_CHARSET;
}
byte[] data = Encoding.GetEncoding(charset).GetBytes(content);
int maxBlockSize = rsa.KeySize / 8 - 11; //加密块最大长度限制
if (data.Length <= maxBlockSize)
{
byte[] cipherbytes = rsa.Encrypt(data, false);
return Convert.ToBase64String(cipherbytes);
}
MemoryStream plaiStream = new MemoryStream(data);
MemoryStream crypStream = new MemoryStream();
Byte[] buffer = new Byte[maxBlockSize];
int blockSize = plaiStream.Read(buffer, 0, maxBlockSize);
while (blockSize > 0)
{
Byte[] toEncrypt = new Byte[blockSize];
Array.Copy(buffer, 0, toEncrypt, 0, blockSize);
Byte[] cryptograph = rsa.Encrypt(toEncrypt, false);
crypStream.Write(cryptograph, 0, cryptograph.Length);
blockSize = plaiStream.Read(buffer, 0, maxBlockSize);
}
return Convert.ToBase64String(crypStream.ToArray(), Base64FormattingOptions.None);
}
catch (Exception ex)
{
throw new Exception("EncryptContent = " + content + ",charset = " + charset, ex);
}
}
///
/// 私钥解密(超过 私钥长度 / 8 - 11,分段加密)
///
/// 密文
/// 编码
/// 私钥
/// 私钥格式 PKCS1,PKCS8
///
///
public static string RSADecrypt(string content, string charset, string privateKeyPem, string keyFormat)
{
try
{
//假设私钥长度为1024, 1024/8 =128。
//如果明文的长度小于 128,直接全解密。(data.Length <= maxBlockSize)
//如果明文长度大于 128,则每 128 分一段解密,写入到另一个Stream中,最后 GetString。while (blockSize > 0)
RSACryptoServiceProvider rsaCsp = RsaUtil.LoadPrivateKey(privateKeyPem, keyFormat);
//RSACryptoServiceProvider rsaCsp = LoadCertificateFile(privateKeyPem, signType);
if (string.IsNullOrEmpty(charset))
{
charset = DEFAULT_CHARSET;
}
byte[] data = Convert.FromBase64String(content);
int maxBlockSize = rsaCsp.KeySize / 8; //解密块最大长度限制
if (data.Length <= maxBlockSize)
{
byte[] cipherbytes = rsaCsp.Decrypt(data, false);
return Encoding.GetEncoding(charset).GetString(cipherbytes);
}
MemoryStream crypStream = new MemoryStream(data);
MemoryStream plaiStream = new MemoryStream();
Byte[] buffer = new Byte[maxBlockSize];
int blockSize = crypStream.Read(buffer, 0, maxBlockSize);
while (blockSize > 0)
{
Byte[] toDecrypt = new Byte[blockSize];
Array.Copy(buffer, 0, toDecrypt, 0, blockSize);
Byte[] cryptograph = rsaCsp.Decrypt(toDecrypt, false);
plaiStream.Write(cryptograph, 0, cryptograph.Length);
blockSize = crypStream.Read(buffer, 0, maxBlockSize);
}
return Encoding.GetEncoding(charset).GetString(plaiStream.ToArray());
}
catch (Exception ex)
{
throw new Exception("DecryptContent = " + content + ",charset = " + charset, ex);
}
}
#endregion
}
}
使用:
支持超出 私钥长度/8 -11 的长度明文,分段加密。
公钥加密:
private void btnPubKeyEncrypt_Click(object sender, EventArgs e)
{
try
{
string rst = RsaEncryptUtil.RSAEncrypt(txtMingWen.Text, "UTF-8", txtPubKey.Text);
txtJiaMiHou.Text = rst;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
私钥解密 :
private void btnPrivateKeyDecrypt_Click(object sender, EventArgs e)
{
try
{
string strRst = RsaEncryptUtil.RSADecrypt(txtJiaMiHou.Text, "UTF-8", txtPrivateKey.Text, cbxPrivateKeyFormat.Text);
txtJieMiHou.Text = strRst;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
END