.NET Core加解密实战系列之——RSA非对称加密算法
簡(jiǎn)介
加解密現(xiàn)狀,編寫此項(xiàng)目的背景:
需要考慮系統(tǒng)環(huán)境兼容性問(wèn)題(Linux、Windows)
語(yǔ)言互通問(wèn)題(如C#、Java)
網(wǎng)上資料版本不一、不全面
.NET官方庫(kù)密碼算法提供不全面,很難針對(duì)其他語(yǔ)言(Java)進(jìn)行適配
本系列文章主要介紹如何結(jié)合BouncyCastle在 .NET Core 中使用非對(duì)稱加密算法、編碼算法、哈希算法、對(duì)稱加密算法、國(guó)密算法等一系列算法,內(nèi)容篇幅代碼居多(加解密算法相關(guān)的原理知識(shí)網(wǎng)上有很多,因此不過(guò)多介紹)。如有錯(cuò)誤之處,還請(qǐng)大家批評(píng)指正。
本系列代碼項(xiàng)目地址:https://github.com/fuluteam/ICH.BouncyCastle.git
功能依賴
BouncyCastle(https://www.bouncycastle.org/csharp) 是一個(gè)開(kāi)放源碼的輕量級(jí)密碼術(shù)包;它支持大量的密碼術(shù)算法,它提供了很多.NET Core標(biāo)準(zhǔn)庫(kù)沒(méi)有的算法。
支持.NET 4,.NET Standard 1.0-2.0,WP,Silverlight,MonoAndroid,Xamarin.iOS,.NET Core
| 功能 | 依賴 |
| Portable.BouncyCastle | Portable.BouncyCastle ? 1.8.5 |
生成RSA秘鑰
PKCS1格式
/// <summary>/// PKCS1(非Java適用)/// </summary>/// <param name="keySize">密鑰長(zhǎng)度”一般只是指模值的位長(zhǎng)度。目前主流可選值:1024、2048、3072、4096...</param>/// <param name="format">PEM格式</param>/// <returns></returns>public RSAKeyParameter Pkcs1(int keySize, bool format=false){var keyGenerator = GeneratorUtilities.GetKeyPairGenerator("RSA");keyGenerator.Init(new KeyGenerationParameters(new SecureRandom(), keySize));var keyPair = keyGenerator.GenerateKeyPair();var subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);if (!format){return new RSAKeyParameter{PrivateKey = Base64.ToBase64String(privateKeyInfo.ParsePrivateKey().GetEncoded()),PublicKey = Base64.ToBase64String(subjectPublicKeyInfo.GetEncoded())};}var rsaKey = new RSAKeyParameter();using (var sw = new StringWriter()){var pWrt = new PemWriter(sw);pWrt.WriteObject(keyPair.Private);pWrt.Writer.Close();rsaKey.PrivateKey = sw.ToString();}using (var sw = new StringWriter()){var pWrt = new PemWriter(sw);pWrt.WriteObject(keyPair.Public);pWrt.Writer.Close();rsaKey.PublicKey = sw.ToString();}return rsaKey;}PKCS8格式
/// <summary>/// PKCS8(JAVA適用)/// </summary>/// <param name="keySize">密鑰長(zhǎng)度”一般只是指模值的位長(zhǎng)度。目前主流可選值:1024、2048、3072、4096...</param>/// <param name="format">PEM格式</param>/// <returns></returns>public RSAKeyParameter Pkcs8(int keySize, bool format=false){var keyGenerator = GeneratorUtilities.GetKeyPairGenerator("RSA");keyGenerator.Init(new KeyGenerationParameters(new SecureRandom(), keySize));var keyPair = keyGenerator.GenerateKeyPair();var subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);if (!format){return new RSAKeyParameter{PrivateKey = Base64.ToBase64String(privateKeyInfo.GetEncoded()),PublicKey = Base64.ToBase64String(subjectPublicKeyInfo.GetEncoded())};}var rsaKey = new RSAKeyParameter();using (var sw = new StringWriter()){var pWrt = new PemWriter(sw);var pkcs8 = new Pkcs8Generator(keyPair.Private);pWrt.WriteObject(pkcs8);pWrt.Writer.Close();rsaKey.PrivateKey = sw.ToString();}using (var sw = new StringWriter()){var pWrt = new PemWriter(sw);pWrt.WriteObject(keyPair.Public);pWrt.Writer.Close();rsaKey.PublicKey = sw.ToString();}return rsaKey;}私鑰操作
PKCS1與PKCS8格式互轉(zhuǎn)
僅私鑰有PKCS1和PKCS8之分,公鑰無(wú)格式區(qū)別。
/// <summary>/// Pkcs1>>Pkcs8/// </summary>/// <param name="privateKey">Pkcs1私鑰</param>/// <param name="format">是否轉(zhuǎn)PEM格式</param>/// <returns></returns>public static string PrivateKeyPkcs1ToPkcs8(string privateKey, bool format = false){var akp = RSAUtilities.GetAsymmetricKeyParameterFormPrivateKey(privateKey);if (format){var sw = new StringWriter();var pWrt = new PemWriter(sw);var pkcs8 = new Pkcs8Generator(akp);pWrt.WriteObject(pkcs8);pWrt.Writer.Close();return sw.ToString();}else{var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(akp);return Base64.ToBase64String(privateKeyInfo.GetEncoded());}}/// <summary>/// Pkcs8>>Pkcs1/// </summary>/// <param name="privateKey">Pkcs8私鑰</param>/// <param name="format">是否轉(zhuǎn)PEM格式</param>/// <returns></returns>public static string PrivateKeyPkcs8ToPkcs1(string privateKey, bool format = false){var akp = RSAUtilities.GetAsymmetricKeyParameterFormAsn1PrivateKey(privateKey);if (format){var sw = new StringWriter();var pWrt = new PemWriter(sw);pWrt.WriteObject(akp);pWrt.Writer.Close();return sw.ToString();}else{var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(akp);return Base64.ToBase64String(privateKeyInfo.ParsePrivateKey().GetEncoded());}}PKCS1與PKCS8私鑰中提取公鑰
/// <summary>/// 從Pkcs1私鑰中提取公鑰/// </summary>/// <param name="privateKey">Pkcs1私鑰</param>/// <returns></returns>public static string GetPublicKeyFromPrivateKeyPkcs1(string privateKey){var instance = RsaPrivateKeyStructure.GetInstance(Base64.Decode(privateKey));var publicParameter = (AsymmetricKeyParameter)new RsaKeyParameters(false, instance.Modulus,instance.PublicExponent);var privateParameter = (AsymmetricKeyParameter)new RsaPrivateCrtKeyParameters(instance.Modulus,instance.PublicExponent, instance.PrivateExponent, instance.Prime1, instance.Prime2, instance.Exponent1,instance.Exponent2, instance.Coefficient);var keyPair = new AsymmetricCipherKeyPair(publicParameter, privateParameter);var subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);return Base64.ToBase64String(subjectPublicKeyInfo.GetEncoded());}/// <summary>/// 從Pkcs8私鑰中提取公鑰/// </summary>/// <param name="privateKey">Pkcs8私鑰</param>/// <returns></returns>public static string GetPublicKeyFromPrivateKeyPkcs8(string privateKey){var privateKeyInfo = PrivateKeyInfo.GetInstance(Asn1Object.FromByteArray(Base64.Decode(privateKey)));privateKey = Base64.ToBase64String(privateKeyInfo.ParsePrivateKey().GetEncoded());var instance = RsaPrivateKeyStructure.GetInstance(Base64.Decode(privateKey));var publicParameter = (AsymmetricKeyParameter)new RsaKeyParameters(false, instance.Modulus,instance.PublicExponent);var privateParameter = (AsymmetricKeyParameter)new RsaPrivateCrtKeyParameters(instance.Modulus,instance.PublicExponent, instance.PrivateExponent, instance.Prime1, instance.Prime2, instance.Exponent1,instance.Exponent2, instance.Coefficient);var keyPair = new AsymmetricCipherKeyPair(publicParameter, privateParameter);var subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);return Base64.ToBase64String(subjectPublicKeyInfo.GetEncoded());}PEM操作
PEM格式密鑰讀取
public static string ReadPkcs1PrivateKey(string text){if (!text.StartsWith("-----BEGIN RSA PRIVATE KEY-----")){return text;}using (var reader = new StringReader(text)){var pr = new PemReader(reader);var keyPair = pr.ReadObject() as AsymmetricCipherKeyPair;pr.Reader.Close();var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair?.Private);return Base64.ToBase64String(privateKeyInfo.ParsePrivateKey().GetEncoded());}}public static string ReadPkcs8PrivateKey(string text){if (!text.StartsWith("-----BEGIN PRIVATE KEY-----")){return text;}using (var reader = new StringReader(text)){var pr = new PemReader(reader);var akp = pr.ReadObject() as AsymmetricKeyParameter; ;pr.Reader.Close();return Base64.ToBase64String(PrivateKeyInfoFactory.CreatePrivateKeyInfo(akp).GetEncoded());}}public static string ReadPublicKey(string text){if (!text.StartsWith("-----BEGIN PUBLIC KEY-----")){return text;}using (var reader = new StringReader(text)){var pr = new PemReader(reader);var keyPair = pr.ReadObject() as AsymmetricCipherKeyPair;pr.Reader.Close();var subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair?.Public);returnBase64.ToBase64String(subjectPublicKeyIno.GetEncoded());}}PEM格式密鑰寫入
public static string WritePkcs1PrivateKey(string privateKey){if (privateKey.StartsWith("-----BEGIN RSA PRIVATE KEY-----")){return privateKey;}var akp = RSAUtilities.GetAsymmetricKeyParameterFormPrivateKey(privateKey);using (var sw = new StringWriter()){var pWrt = new PemWriter(sw);pWrt.WriteObject(akp);pWrt.Writer.Close();return sw.ToString();}}public static string WritePkcs8PrivateKey(string privateKey){if (privateKey.StartsWith("-----BEGIN PRIVATE KEY-----")){return privateKey;}var akp = RSAUtilities.GetAsymmetricKeyParameterFormAsn1PrivateKey(privateKey);using (var sw = new StringWriter()){var pWrt = new PemWriter(sw);var pkcs8 = new Pkcs8Generator(akp);pWrt.WriteObject(pkcs8);pWrt.Writer.Close();return sw.ToString();}}public static string WritePublicKey(string publicKey){if (publicKey.StartsWith("-----BEGIN PUBLIC KEY-----")){return publicKey;}var akp = RSAUtilities.GetAsymmetricKeyParameterFormPublicKey(publicKey);using (var sw = new StringWriter()){var pWrt = new PemWriter(sw);pWrt.WriteObject(akp);pWrt.Writer.Close();return sw.ToString();}}RSA加解密
獲取非對(duì)稱秘鑰參數(shù)(AsymmetricKeyParameter)
/// <summary>/// -----BEGIN RSA PRIVATE KEY-----/// .../// -----END RSA PRIVATE KEY-----/// </summary>/// <param name="privateKey">Pkcs1格式私鑰</param>/// <returns></returns>public static AsymmetricKeyParameter GetAsymmetricKeyParameterFormPrivateKey(string privateKey){if (string.IsNullOrEmpty(privateKey)){throw new ArgumentNullException(nameof(privateKey));}var instance = RsaPrivateKeyStructure.GetInstance(Base64.Decode(privateKey));return new RsaPrivateCrtKeyParameters(instance.Modulus, instance.PublicExponent, instance.PrivateExponent,instance.Prime1, instance.Prime2, instance.Exponent1, instance.Exponent2, instance.Coefficient);}/// <summary>/// -----BEGIN PRIVATE KEY-----/// .../// -----END PRIVATE KEY-----/// </summary>/// <param name="privateKey">Pkcs8格式私鑰</param>/// <returns></returns>public static AsymmetricKeyParameter GetAsymmetricKeyParameterFormAsn1PrivateKey(string privateKey){return PrivateKeyFactory.CreateKey(Base64.Decode(privateKey));}/// <summary>/// -----BEGIN PUBLIC KEY-----/// .../// -----END PUBLIC KEY-----/// </summary>/// <param name="publicKey">公鑰</param>/// <returns></returns>public static AsymmetricKeyParameter GetAsymmetricKeyParameterFormPublicKey(string publicKey){if (string.IsNullOrEmpty(publicKey)){throw new ArgumentNullException(nameof(publicKey));}return PublicKeyFactory.CreateKey(Base64.Decode(publicKey));}RSA加解與解密
/// <summary>/// RSA加密/// </summary>/// <param name="data">未加密數(shù)據(jù)字節(jié)數(shù)組</param>/// <param name="parameters">非對(duì)稱密鑰參數(shù)</param>/// <param name="algorithm">密文算法</param>/// <returns>已加密數(shù)據(jù)字節(jié)數(shù)組</returns>public static byte[] Encrypt(byte[] data, AsymmetricKeyParameter parameters, string algorithm){if (data == null){throw new ArgumentNullException(nameof(data));}if (parameters == null){throw new ArgumentNullException(nameof(parameters));}if (string.IsNullOrEmpty(algorithm)){throw new ArgumentNullException(nameof(algorithm));}var bufferedCipher = CipherUtilities.GetCipher(algorithm);bufferedCipher.Init(true, parameters);return bufferedCipher.DoFinal(data);}/// <summary>/// RSA解密/// </summary>/// <param name="data">已加密數(shù)據(jù)字節(jié)數(shù)組</param>/// <param name="parameters">非對(duì)稱密鑰參數(shù)</param>/// <param name="algorithm">密文算法</param>/// <returns>未加密數(shù)據(jù)字節(jié)數(shù)組</returns>public static byte[] Decrypt(byte[] data, AsymmetricKeyParameter parameters, string algorithm){if (data == null){throw new ArgumentNullException(nameof(data));}if (parameters == null){throw new ArgumentNullException(nameof(parameters));}if (string.IsNullOrEmpty(algorithm)){throw new ArgumentNullException(nameof(algorithm));}var bufferedCipher = CipherUtilities.GetCipher(algorithm);bufferedCipher.Init(false, parameters);return bufferedCipher.DoFinal(data);}/// <summary>/// RSA加密——Base64/// </summary>/// <param name="data">未加密字符串</param>/// <param name="parameters">非對(duì)稱密鑰參數(shù)</param>/// <param name="algorithm">密文算法</param>/// <returns>已加密Base64字符串</returns>public static string EncryptToBase64(string data, AsymmetricKeyParameter parameters, string algorithm){return Base64.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(data), parameters, algorithm));}/// <summary>/// RSA解密——Base64/// </summary>/// <param name="data">已加密Base64字符串</param>/// <param name="parameters">非對(duì)稱密鑰參數(shù)</param>/// <param name="algorithm">密文算法</param>/// <returns>未加密字符串</returns>public static string DecryptFromBase64(string data, AsymmetricKeyParameter parameters, string algorithm){return Encoding.UTF8.GetString(Decrypt(Base64.Decode(data), parameters, algorithm));}/// <summary>/// RSA加密——十六進(jìn)制/// </summary>/// <param name="data">未加密字符串</param>/// <param name="parameters">非對(duì)稱密鑰參數(shù)</param>/// <param name="algorithm">密文算法</param>/// <returns>已加密十六進(jìn)制字符串</returns>public static string EncryptToHex(string data, AsymmetricKeyParameter parameters, string algorithm){return Hex.ToHexString(Encrypt(Encoding.UTF8.GetBytes(data), parameters, algorithm));}/// <summary>/// RSA解密——十六進(jìn)制/// </summary>/// <param name="data">已加密十六進(jìn)制字符串</param>/// <param name="parameters">非對(duì)稱密鑰參數(shù)</param>/// <param name="algorithm">密文算法</param>/// <returns>未加密字符串</returns>public static string DecryptFromHex(string data, AsymmetricKeyParameter parameters, string algorithm){return Encoding.UTF8.GetString(Decrypt(Hex.Decode(data), parameters, algorithm));}RSA密文算法
public const string RSA_NONE_NoPadding = "RSA/NONE/NoPadding";public const string RSA_NONE_PKCS1Padding = "RSA/NONE/PKCS1Padding";public const string RSA_NONE_OAEPPadding = "RSA/NONE/OAEPPadding";public const string RSA_NONE_OAEPWithSHA1AndMGF1Padding = "RSA/NONE/OAEPWithSHA1AndMGF1Padding";public const string RSA_NONE_OAEPWithSHA224AndMGF1Padding = "RSA/NONE/OAEPWithSHA224AndMGF1Padding";public const string RSA_NONE_OAEPWithSHA256AndMGF1Padding = "RSA/NONE/OAEPWithSHA256AndMGF1Padding";public const string RSA_NONE_OAEPWithSHA384AndMGF1Padding = "RSA/NONE/OAEPWithSHA384AndMGF1Padding";public const string RSA_NONE_OAEPWithMD5AndMGF1Padding = "RSA/NONE/OAEPWithMD5AndMGF1Padding";public const string RSA_ECB_NoPadding = "RSA/ECB/NoPadding";public const string RSA_ECB_PKCS1Padding = "RSA/ECB/PKCS1Padding";public const string RSA_ECB_OAEPPadding = "RSA/ECB/OAEPPadding";public const string RSA_ECB_OAEPWithSHA1AndMGF1Padding = "RSA/ECB/OAEPWithSHA1AndMGF1Padding";public const string RSA_ECB_OAEPWithSHA224AndMGF1Padding = "RSA/ECB/OAEPWithSHA224AndMGF1Padding";public const string RSA_ECB_OAEPWithSHA256AndMGF1Padding = "RSA/ECB/OAEPWithSHA256AndMGF1Padding";public const string RSA_ECB_OAEPWithSHA384AndMGF1Padding = "RSA/ECB/OAEPWithSHA384AndMGF1Padding";public const string RSA_ECB_OAEPWithMD5AndMGF1Padding = "RSA/ECB/OAEPWithMD5AndMGF1Padding";......編碼算法
大家要明白,不管是對(duì)稱算法還是非對(duì)稱算法,其輸入與輸出均是字節(jié)數(shù)組,通常我們要結(jié)合編碼算法對(duì)加密之后或解密之前的數(shù)據(jù),進(jìn)行編碼操作。
BouncyCastle提供的Base64編碼算法
namespace Org.BouncyCastle.Utilities.Encoders{public sealed class Base64{//public static byte[] Decode(byte[] data);//public static byte[] Decode(string data);//public static int Decode(string data, Stream outStream);//public static byte[] Encode(byte[] data);//public static byte[] Encode(byte[] data, int off, int length);//public static int Encode(byte[] data, Stream outStream);//public static int Encode(byte[] data, int off, int length, Stream outStream);public static string ToBase64String(byte[] data);public static string ToBase64String(byte[] data, int off, int length);}}BouncyCastle提供的Hex十六進(jìn)制編碼算法
namespace Org.BouncyCastle.Utilities.Encoders{//// 摘要:// Class to decode and encode Hex.public sealed class Hex{//public static byte[] Decode(byte[] data);//public static byte[] Decode(string data);//public static int Decode(string data, Stream outStream);//public static byte[] Encode(byte[] data);//public static byte[] Encode(byte[] data, int off, int length);//public static int Encode(byte[] data, Stream outStream);//public static int Encode(byte[] data, int off, int length, Stream outStream);public static string ToHexString(byte[] data);public static string ToHexString(byte[] data, int off, int length);}}RSA加解密示例
private static void RSA_ECB_PKCS1Padding(){var data = "hello rsa";Console.WriteLine($"加密原文:{data}");// rsa pkcs8 private key encrypt//algorithm rsa/ecb/pkcs1paddingvar pkcs8data = RSA.EncryptToBase64(data, RSAUtilities.GetAsymmetricKeyParameterFormAsn1PrivateKey(pkcs8_1024_private_key),CipherAlgorithms.RSA_ECB_PKCS1Padding);Console.WriteLine("密鑰格式:pkcs8,密文算法:rsa/ecb/pkcs1padding,加密結(jié)果");Console.WriteLine(pkcs8data);//rsa pkcs1 private key encrypt//algorithm rsa/ecb/pkcs1paddingvar pkcs1data = RSA.EncryptToBase64(data, RSAUtilities.GetAsymmetricKeyParameterFormPrivateKey(pkcs1_1024_private_key),CipherAlgorithms.RSA_ECB_PKCS1Padding);Console.WriteLine($"密鑰格式:pkcs1,密文算法:rsa/ecb/pkcs1padding");Console.WriteLine(pkcs1data);Console.WriteLine($"加密結(jié)果比對(duì)是否一致:{pkcs8data.Equals(pkcs1data)}");var _1024_public_key = RSAKeyConverter.GetPublicKeyFromPrivateKeyPkcs1(pkcs1_1024_private_key);Console.WriteLine($"從pkcs1私鑰中提取公鑰:");Console.WriteLine(_1024_public_key);Console.WriteLine("使用公鑰解密數(shù)據(jù):");//rsa public key decrypt//algorithm rsa/ecb/pkcs1paddingConsole.WriteLine(RSA.DecryptFromBase64(pkcs1data, RSAUtilities.GetAsymmetricKeyParameterFormPublicKey(_1024_public_key),CipherAlgorithms.RSA_ECB_PKCS1Padding));Console.WriteLine();}下期預(yù)告
下一篇將介紹哈希算法(HMACSHA1、HMACSHA256、SHA1、SHA1WithRSA、SHA256、SHA256WithRSA),敬請(qǐng)期待…
總結(jié)
以上是生活随笔為你收集整理的.NET Core加解密实战系列之——RSA非对称加密算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: docker registry 镜像同步
- 下一篇: .Net Core实战之基于角色的访问控