开发手册 欢迎您!
软件开发者资料库

ASP.NET Core(C#) 使用RSACryptoServiceProvider实现公钥和私钥加解密工具类

本文主要介绍.NET(C#)中,实现RSA非对称加密算法,使用RSACryptoServiceProvider实现公钥和私钥加解密工具类,以及相关的示例代码。

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("{0}{1}

{2}

{3}{4}{5}{6}{7}
", 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 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 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.wonhero.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();            });        }    }}