1、RSA非对称加密算法
RSA加密算法是最常用的非对称加密算法,由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)于1977年一起提出,RSA就是他们三人姓氏开头字母拼在一起组成的。非对称加密算法的特点就是加密秘钥和解密秘钥不同,秘钥分为公钥和私钥,用私钥加密的明文,只能用公钥解密;用公钥加密的明文,只能用私钥解密。
RSA是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名。这个算法经受住了多年深入的密码分析,虽然密码分析者既不能证明也不能否定RSA的安全性,但这恰恰说明该算法有一定的可信性,目前它已经成为最流行的公开密钥算法。RSA的安全基于大数分解的难度。其公钥和私钥是一对大素数(100到200位十进制数或更大)的函数。从一个公钥和密文恢复出明文的难度,等价于分解两个大素数之积。
2、通过扩展方法写入和读取xml配置文件参数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Xml;
namespace CJavaPy.Encrypt
{
public static class RSACryptoServiceProviderExtensions
{
public static void FromXmlString(this RSACryptoServiceProvider rsa, string xmlString)
{
RSAParameters parameters = new RSAParameters();
XmlDocument 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 = Convert.FromBase64String(node.InnerText); break;
case "Exponent": parameters.Exponent = Convert.FromBase64String(node.InnerText); break;
case "P": parameters.P = Convert.FromBase64String(node.InnerText); break;
case "Q": parameters.Q = Convert.FromBase64String(node.InnerText); break;
case "DP": parameters.DP = Convert.FromBase64String(node.InnerText); break;
case "DQ": parameters.DQ = Convert.FromBase64String(node.InnerText); break;
case "InverseQ": parameters.InverseQ = Convert.FromBase64String(node.InnerText); break;
case "D": parameters.D = Convert.FromBase64String(node.InnerText); break;
}
}
}
else
{
throw new Exception("Invalid XML RSA key.");
}
rsa.ImportParameters(parameters);
}
public static string ToXmlString(this RSACryptoServiceProvider rsa, bool includePrivateParameters)
{
RSAParameters parameters = rsa.ExportParameters(includePrivateParameters);
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
Convert.ToBase64String(parameters.Modulus),
Convert.ToBase64String(parameters.Exponent),
Convert.ToBase64String(parameters.P),
Convert.ToBase64String(parameters.Q),
Convert.ToBase64String(parameters.DP),
Convert.ToBase64String(parameters.DQ),
Convert.ToBase64String(parameters.InverseQ),
Convert.ToBase64String(parameters.D));
}
}
}
3、实现公钥和私钥加解密工具类
using System;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Hosting;
namespace CJavaPy.Encrypt
{
public class EncryptService
{
private const string Path = "Encrypt/";
private const string PrivateKeyFile = "Private.config";
private const string PublicKeyFile = "Public.config";
private readonly string _folder;
private readonly string _privateKeyFileName;
private readonly string _publicKeyFileName;
public EncryptService(IWebHostEnvironment hostingEnvironment)
{
_folder = System.IO.Path.Combine(hostingEnvironment.ContentRootPath, Path);
_privateKeyFileName = System.IO.Path.Combine(_folder, PrivateKeyFile);
_publicKeyFileName = System.IO.Path.Combine(_folder, PublicKeyFile);
}
public byte[] Encrypt(byte[] source)
{
Func<byte[], byte[]> encrypt = sou =>
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
if (!Directory.Exists(_folder))
{
Directory.CreateDirectory(_folder);
}
if (!File.Exists(_privateKeyFileName))
{
File.WriteAllText(_privateKeyFileName, rsa.ToXmlString(true));
File.WriteAllText(_publicKeyFileName, rsa.ToXmlString(false));
}
rsa.FromXmlString(File.ReadAllText(_publicKeyFileName));
int maxBlockSize = rsa.KeySize / 8 - 11;
if (sou.Length <= maxBlockSize)
return rsa.Encrypt(sou, false);
using (MemoryStream plaiStream = new MemoryStream(sou))
{
using (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 crypStream.ToArray();
}
}
}
};
return MarkData(encrypt(source));
}
public byte[] Decrypt(byte[] source)
{
if (IsEncrypt(source))
{
Func<byte[], byte[]> decrypt = sou =>
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
if (File.Exists(_folder + PrivateKeyFile))
{
rsa.FromXmlString(File.ReadAllText(_privateKeyFileName));
}
int maxBlockSize = rsa.KeySize / 8;
if (sou.Length <= maxBlockSize)
return rsa.Decrypt(sou, false);
using (MemoryStream crypStream = new MemoryStream(sou))
{
using (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[] plaintext = rsa.Decrypt(toDecrypt, false);
plaiStream.Write(plaintext, 0, plaintext.Length);
blockSize = crypStream.Read(buffer, 0, maxBlockSize);
}
return plaiStream.ToArray();
}
}
}
};
return decrypt(ClearDataMark(source));
}
return source;
}
private byte[] MarkData(byte[] source)
{
byte[] newBytes = new byte[source.Length + 200];
for (int i = 0; i < newBytes.Length; i++)
{
if (i < 100 || i > newBytes.Length - 100 - 1)
{
newBytes[i] = 0;
}
else
{
newBytes[i] = source[i - 100];
}
}
return newBytes;
}
private byte[] ClearDataMark(byte[] source)
{
byte[] newBytes = new byte[source.Length - 200];
for (int i = 100; i < source.Length - 100; i++)
{
newBytes[i - 100] = source[i];
}
return newBytes;
}
private bool IsEncrypt(byte[] source)
{
for (int i = 0; i < 100; i++)
{
if (source[i] != 0 || source[source.Length - i - 1] != 0)
{
return false;
}
}
return true;
}
}
}
4、使用方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using CJavaPy.Encrypt;
namespace CJavaPy.Encrypt
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
//调用示例代码
EncryptService encryptService = new EncryptService(env);
//配置文件不存在会自动生成
byte[] data= encryptService.Encrypt(System.Text.Encoding.UTF8.GetBytes("www.cjavapy.com"));
string val = System.Text.Encoding.UTF8.GetString(encryptService.Decrypt(data));
string valOrigin = System.Text.Encoding.UTF8.GetString(data);
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}
}