.NET Core加解密实战系列之——消息摘要与数字签名算法
簡介
加解密現(xiàn)狀,編寫此系列文章的背景:
需要考慮系統(tǒng)環(huán)境兼容性問題(Linux、Windows)
語言互通問題(如C#、Java等)(加解密本質(zhì)上沒有語言之分,所以原則上不存在互通性問題)
網(wǎng)上資料版本不一、或不全面
.NET官方庫密碼算法提供不全面,很難針對其他語言(Java)進行適配
本系列文章主要介紹如何在 .NET Core 中使用非對稱加密算法、編碼算法、消息摘要算法、簽名算法、對稱加密算法、國密算法等一系列算法,如有錯誤之處,還請大家批評指正。
本系列文章旨在引導(dǎo)大家能快速、輕松的了解接入加解密,乃至自主組合搭配使用BouncyCastle密碼術(shù)包中提供的算法。
本文中代碼示例僅列舉了比較常見的使用方式(BouncyCastle中提供的算法遠不止這些),另外算法DSA和ECDSA我們未在項目中使用過,代碼組合性非常多,因此文中部分代碼僅供參考。
本系列代碼項目地址:https://github.com/fuluteam/ICH.BouncyCastle.git
上一篇文章《.NET Core加解密實戰(zhàn)系列之——RSA非對稱加密算法》:https://www.cnblogs.com/fulu/p/13100471.html
功能依賴
BouncyCastle(https://www.bouncycastle.org/csharp) 是一個開放源碼的輕量級密碼術(shù)包;它支持大量的密碼術(shù)算法,它提供了很多 .NET Core標(biāo)準(zhǔn)庫沒有的算法。
支持 .NET 4,.NET Standard 1.0-2.0,WP,Silverlight,MonoAndroid,Xamarin.iOS,.NET Core
| 功能 | 依賴 |
| Portable.BouncyCastle | Portable.BouncyCastle ? 1.8.5 |
消息摘要算法
消息摘要算法分為三類:
MD 2/4/5(Message Digest Algorithm 2/4/5):消息摘要算法 MD2、MD4、MD5
SHA(Secure Hash Algorithm):安全散列算法
MAC(Message Authentication Code):消息認(rèn)證碼
MD算法
MD消息摘要算法,一種被廣泛使用的密碼散列函數(shù),可以產(chǎn)生出一個128位(16字節(jié))的散列值(hash value),用于確保信息傳輸完整一致。
家族發(fā)展史
MD2算法:
1989年,著名的非對稱算法RSA發(fā)明人之一麻省理工學(xué)院教授羅納德·李維斯特開發(fā)了MD2算法。這個算法首先對信息進行數(shù)據(jù)補位,使信息的字節(jié)長度是16的倍數(shù)。再以一個16位的檢驗和做為補充信息追加到原信息的末尾。最后根據(jù)這個新產(chǎn)生的信息計算出一個128位的散列值,MD2算法由此誕生。
MD4算法:
1990年,羅納德·李維斯特教授開發(fā)出較之MD2算法有著更高安全性的MD4算法。MD4算法對后續(xù)消息摘要算法起到了推動作用,許多比較有名的消息摘要算法都是在MD4算法的基礎(chǔ)上發(fā)展而來的,如MD5、SHA-1、RIPE-MD和HAVAL算法等。
MD5算法:
1991年,繼MD4算法后,羅納德·李維斯特教授開發(fā)了MD5算法,用以取代MD4算法。這套算法的程序在 RFC 1321 標(biāo)準(zhǔn)中被加以規(guī)范。MD5算法經(jīng)MD2、MD3和MD4算法發(fā)展而來,算法復(fù)雜程度和安全強度大大提高,MD算法的最終結(jié)果都是產(chǎn)生一個128位的信息摘要。這也是MD系列算法的特點。
1996年,該算法被證實存在弱點,可以被加以破解,對于需要高度安全性的數(shù)據(jù),專家一般建議改用其他算法,如SHA-2。
2004年,證實MD5算法無法防止碰撞(collision),因此不適用于安全性認(rèn)證,如SSL公開密鑰認(rèn)證或是數(shù)字簽名等用途。
應(yīng)用場景
消息摘要算法是不可逆的,所以信息摘要場景主要被用來驗證信息的完整性,防止信息被篡改,主要場景如下:
驗簽:對要發(fā)送的數(shù)據(jù)做MD5(一般加slat)MD5值和數(shù)據(jù)一同發(fā)送,接收方接受數(shù)據(jù)做同樣的MD5計算,比較MD5值是否一致
密碼保護:比如用戶密碼存儲上,一般都是存儲MD5值,更高一級的涉及是針對每個用戶生成一個隨機的slat,然后進MD5(passport + slat)計算,將這個值存儲到DB中
代碼實現(xiàn)
MD5
public static class MD5{/// <summary>/// 哈希計算(使用BouncyCastle)/// </summary>/// <param name="s"></param>/// <returns></returns>public static byte[] Compute(string s){if (string.IsNullOrEmpty(s)){throw new ArgumentNullException(nameof(s));}var digest = new MD5Digest();var resBuf = new byte[digest.GetDigestSize()];var input = Encoding.UTF8.GetBytes(s);digest.BlockUpdate(input, 0, input.Length);digest.DoFinal(resBuf, 0);return resBuf;}/// <summary>/// 哈希計算(不使用BouncyCastle)/// </summary>/// <param name="s"></param>/// <returns></returns>public static byte[] Compute2(string s){if (string.IsNullOrEmpty(s)){throw new ArgumentNullException(nameof(s));}using (var md5 = System.Security.Cryptography.MD5.Create()){return md5.ComputeHash(Encoding.UTF8.GetBytes(s));}}}示例代碼
private static void MD5Sample(){var s = "hello md5";Console.WriteLine(s);var resBytes1 = MD5.Compute("hello md5");var resBytes2 = MD5.Compute2("hello md5");var a1 = BitConverter.ToString(resBytes1).Replace("-", "");Console.WriteLine($"通過BitConverter.ToString轉(zhuǎn)換得到結(jié)果:{a1}");var a2 = Hex.ToHexString(resBytes1).ToUpper();Console.WriteLine($"通過Hex.ToHexString轉(zhuǎn)換得到結(jié)果:{a2}");var a3 = Hex.ToHexString(resBytes2).ToUpper();Console.WriteLine($"不使用BouncyCastle得到結(jié)果:{a3}");Console.WriteLine();}SHA算法
安全散列算法(英文:Secure Hash Algorithm,縮寫為SHA)是一個密碼散列函數(shù)家族,是FIPS所認(rèn)證的安全散列算法。
SHA家族的五個算法,分別是SHA-1、SHA-224、SHA-256、SHA-384,和SHA-512,由美國國家安全局(NSA)所設(shè)計,并由美國國家標(biāo)準(zhǔn)與技術(shù)研究院(NIST)發(fā)布;是美國的政府標(biāo)準(zhǔn)。后四者有時并稱為SHA-2。SHA-1在許多安全協(xié)定中廣為使用,包括TLS和SSL、PGP、SSH、S/MIME和IPsec,曾被視為是MD5(更早之前被廣為使用的雜湊函數(shù))的后繼者。但SHA-1的安全性如今被密碼學(xué)家嚴(yán)重質(zhì)疑;雖然至今尚未出現(xiàn)對SHA-2有效的攻擊,它的算法跟SHA-1基本上仍然相似;因此有些人開始發(fā)展其他替代的雜湊算法。
2017年2月23日,Google公司公告宣稱他們與CWI Amsterdam合作共同創(chuàng)建了兩個有著相同的SHA-1值但內(nèi)容不同的PDF文件,這代表SHA-1算法已被正式攻破。
應(yīng)用場景
目前SHA1的應(yīng)用較為廣泛,主要應(yīng)用于CA和數(shù)字證書中,另外在目前互聯(lián)網(wǎng)中流行的BT軟件中,也是使用SHA1來進行文件校驗的。
代碼實現(xiàn)
SHA1
public class SHA1{/// <summary>/// 哈希計算(使用BouncyCastle)/// </summary>public static byte[] Compute(string s){if (string.IsNullOrEmpty(s)){throw new ArgumentNullException(nameof(s));}var digest = new Sha1Digest();var resBuf = new byte[digest.GetDigestSize()];var input = Encoding.UTF8.GetBytes(s);digest.BlockUpdate(input, 0, input.Length);digest.DoFinal(resBuf, 0);return resBuf;}/// <summary>/// 哈希計算(不使用BouncyCastle)/// </summary>public static byte[] Compute2(string s){if (string.IsNullOrEmpty(s)){throw new ArgumentNullException(nameof(s));}using (var sha1 = System.Security.Cryptography.SHA1.Create()){return sha1.ComputeHash(Encoding.UTF8.GetBytes(s));}}}SHA256
public class SHA256{/// <summary>/// 哈希計算(使用BouncyCastle)/// </summary>public static byte[] Compute1(string s){if (string.IsNullOrEmpty(s)){throw new ArgumentNullException(nameof(s));}var digest = new Sha256Digest();var resBuf = new byte[digest.GetDigestSize()];var input = Encoding.UTF8.GetBytes(s);digest.BlockUpdate(input, 0, input.Length);digest.DoFinal(resBuf, 0);return resBuf;}/// <summary>/// 哈希計算(不使用BouncyCastle)/// </summary>public static byte[] Compute2(string s){if (string.IsNullOrEmpty(s)){throw new ArgumentNullException(nameof(s));}using (var sha256 = System.Security.Cryptography.SHA256.Create()){return sha256.ComputeHash(Encoding.UTF8.GetBytes(s));}}}示例代碼
private static void SHA256Sample(){var s = "hello sha-256";Console.WriteLine(s);Console.WriteLine($"使用BouncyCastle計算結(jié)果(轉(zhuǎn)Base64字符串):{Base64.ToBase64String(SHA256.Compute1(s))}");Console.WriteLine($"不使用BouncyCastle計算結(jié)果(轉(zhuǎn)Base64字符串):{Base64.ToBase64String(SHA256.Compute2(s))}");}MAC算法
消息認(rèn)證碼算法(英文:Message Authentication Codes,縮寫為MAC) 含有密鑰的散列函數(shù)算法,兼容了MD和SHA算法的特性,并在此基礎(chǔ)上加上了密鑰。因此MAC算法也經(jīng)常被稱作HMAC算法。消息的散列值由只有通信雙方知道的密鑰來控制。此時Hash值稱作MAC。
HMAC是密鑰相關(guān)的散列運算消息認(rèn)證碼(Hash-based Message Authentication Code)的縮寫,由H.Krawezyk,M.Bellare,R.Canetti于1996年提出的一種基于Hash函數(shù)和密鑰進行消息認(rèn)證的方法,并于1997年作為RFC2104被公布,并在IPSec和其他網(wǎng)絡(luò)協(xié)議(如SSL)中得以廣泛應(yīng)用,現(xiàn)在已經(jīng)成為事實上的Internet安全標(biāo)準(zhǔn)。它可以與任何迭代散列函數(shù)捆綁使用。
HMAC算法的典型應(yīng)用
HMAC算法的一個典型應(yīng)用是用在“挑戰(zhàn)/響應(yīng)”(Challenge/Response)身份認(rèn)證中,認(rèn)證流程如下:
(1) 先由客戶端向服務(wù)器發(fā)出一個驗證請求。(2) 服務(wù)器接到此請求后生成一個隨機數(shù)并通過網(wǎng)絡(luò)傳輸給客戶端(此為挑戰(zhàn))。(3) 客戶端將收到的隨機數(shù)與自己的密鑰進行HMAC-SHA1運算并得到一個結(jié)果作為認(rèn)證證據(jù)傳給服務(wù)器(此為響應(yīng))。(4) 與此同時,服務(wù)器也使用該隨機數(shù)與存儲在服務(wù)器數(shù)據(jù)庫中的該客戶密鑰進行HMAC-SHA1運算,如果服務(wù)器的運算結(jié)果與客戶端傳回的響應(yīng)結(jié)果相同,則認(rèn)為客戶端是一個合法用戶 。HMAC算法的安全性
HMAC算法引入了密鑰,其安全性已經(jīng)不完全依賴于所使用的HASH算法,安全性主要有以下幾點保證:
(1) 使用的密鑰是雙方事先約定的,第三方不可能知道。由上面介紹應(yīng)用流程可以看出,作為非法截獲信息的第三方,能夠得到的信息只有作為“挑戰(zhàn)”的隨機數(shù)和作為“響應(yīng)”的HMAC結(jié)果,無法根據(jù)這兩個數(shù)據(jù)推算出密鑰。由于不知道密鑰,所以無法仿造出一致的響應(yīng)。(2)在HMAC算法的應(yīng)用中,第三方不可能事先知道輸出(如果知道,不用構(gòu)造輸入,直接將輸出送給服務(wù)器即可)。(3) HMAC算法與一般的加密重要的區(qū)別在于它具有“瞬時”性,即認(rèn)證只在當(dāng)時有效,而加密算法被破解后,以前的加密結(jié)果就可能被解密。HMAC組合散列函數(shù)
與HMAC組合使用的算法有HMac-MD5、HMac-SHA1、HMac-SHA256等等:
public class Algorithms{public const string HMacSHA1="HMAC-SHA1";public const string HMacMD5="HMAC-MD5";public const string HMacMD4="HMAC-MD4";public const string HMacMD2="HMAC-MD2";public const string HMacSHA224="HMAC-SHA224";public const string HMacSHA256="HMAC-SHA256";public const string HMacSHA384="HMAC-SHA384";public const string HMacSHA512_224 = "HMAC-SHA512/224";public const string HMacSHA512_256="HMAC-SHA512/256";public const string HMacRIPEMD128="HMAC-RIPEMD128";public const string HMacRIPEMD160="HMAC-RIPEMD160";public const string HMacTIGER="HMAC-TIGER";public const string HMacKECCAK224="HMAC-KECCAK224";public const string HMacKECCAK256="HMAC-KECCAK256";public const string HMacKECCAK288="HMAC-KECCAK288";public const string HMacKECCAK384="HMAC-KECCAK384";public const string HMacSHA3512="HMAC-SHA3-512";public const string HMacGOST3411_2012256="HMAC-GOST3411-2012-256";public const string HMacGOST3411_2012_512="HMAC-GOST3411-2012-512";......}代碼實現(xiàn)
public class HMAC{/// <summary>/// 生成密鑰KEY/// </summary>/// <param name="algorithm">密文算法,參考Algorithms.cs中提供的HMac algorithm</param>/// <returns>密鑰KEY</returns>public static byte[] GeneratorKey(string algorithm){var kGen = GeneratorUtilities.GetKeyGenerator(algorithm);return kGen.GenerateKey();}/// <summary>/// 哈希計算/// </summary>/// <param name="data">輸入字符串</param>/// <param name="key">密鑰KEY</param>/// <param name="algorithm">密文算法,參考Algorithms.cs中提供的HMac algorithm</param>/// <returns>哈希值</returns>public static byte[] Compute(string data, byte[] key, string algorithm){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}var keyParameter = new Org.BouncyCastle.Crypto.Parameters.KeyParameter(key);var input = Encoding.UTF8.GetBytes(data);var mac = MacUtilities.GetMac(algorithm);mac.Init(keyParameter);mac.BlockUpdate(input, 0, input.Length);return MacUtilities.DoFinal(mac);}/// <summary>/// 哈希計算/// </summary>/// <param name="data">輸入字符串</param>/// <param name="key">密鑰KEY</param>/// <param name="digest"></param>/// <returns>哈希值</returns>public static byte[] Compute(string data, byte[] key, IDigest digest){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}var keyParameter = new Org.BouncyCastle.Crypto.Parameters.KeyParameter(key);var input = Encoding.UTF8.GetBytes(data);IMac mac = new Org.BouncyCastle.Crypto.Macs.HMac(digest);mac.Init(keyParameter);mac.BlockUpdate(input, 0, input.Length);return MacUtilities.DoFinal(mac);}}HMAC-MD5
public class HMACMD5{/// <summary>/// 生成密鑰KEY/// </summary>public static byte[] GeneratorKey(){return HMAC.GeneratorKey(Algorithms.HMacMD5);}/// <summary>/// 哈希計算(使用BouncyCastle)/// </summary>public static byte[] Compute(string data, byte[] key){return HMAC.Compute(data, key, Algorithms.HMacMD5);//or//return HMAC.Compute(data, key, new MD5Digest());}/// <summary>/// 哈希計算(不使用BouncyCastle)/// </summary>public static byte[] Compute2(string data, string key){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}if (string.IsNullOrEmpty(key)){throw new ArgumentNullException(nameof(key));}using (var hmacMd5 = new System.Security.Cryptography.HMACMD5(Encoding.UTF8.GetBytes(key))){return hmacMd5.ComputeHash(Encoding.UTF8.GetBytes(data));}}}HMAC-SHA1
public class HMACSHA1{/// <summary>/// 生成密鑰KEY/// </summary>/// <returns></returns>public static byte[] GeneratorKey(){return HMAC.GeneratorKey(Algorithms.HMacSHA1);}/// <summary>/// 哈希計算(使用BouncyCastle)/// </summary>public static byte[] Compute(string data, byte[] key){return HMAC.Compute(data, key, Algorithms.HMacSHA1);//or//return HMAC.Compute(data, key, new Sha1Digest());}/// <summary>/// 哈希計算(不使用BouncyCastle)/// </summary>public static byte[] Compute2(string data, byte[] key){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}using (var hmacSha1 = new System.Security.Cryptography.HMACSHA1(key)){return hmacSha1.ComputeHash(Encoding.UTF8.GetBytes(data));}}}HMAC-SHA256
public class HMACSHA256{/// <summary>/// 生成簽名/// </summary>public static byte[] GeneratorKey(){return HMAC.GeneratorKey(Algorithms.HMacSHA256);}/// <summary>/// 哈希計算(使用BouncyCastle)/// </summary>public static byte[] Compute(string data, byte[] key){return HMAC.Compute(data, key, Algorithms.HMacSHA256);//or//return HMAC.Compute(data, key, new Sha256Digest());}/// <summary>/// 哈希計算(不使用BouncyCastle)/// </summary>public static byte[] Compute2(string data, byte[] key){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}using (var hmacSha256 = new System.Security.Cryptography.HMACSHA256(key)){return hmacSha256.ComputeHash(Encoding.UTF8.GetBytes(data));}}}示例代碼
private static void HMacSha256Sample(){var s = "hello hmac sha256";Console.WriteLine(s);var k = HMACSHA256.GeneratorKey();Console.WriteLine($"密鑰(十六進制字符串):{Hex.ToHexString(k)}");Console.WriteLine($"密鑰(Base64字符串):{Base64.ToBase64String(k)}");var b1 = HMACSHA256.Compute(s, k);Console.WriteLine($"使用BouncyCastle計算結(jié)果(轉(zhuǎn)Base64字符串):{Base64.ToBase64String(b1)}");Console.WriteLine($"使用BouncyCastle計算結(jié)果(轉(zhuǎn)十六進制字符串):{Hex.ToHexString(b1)}");var b2 = HMACSHA256.Compute2(s, k);Console.WriteLine($"不使用BouncyCastle計算結(jié)果(轉(zhuǎn)Base64字符串):{Base64.ToBase64String(b2)}");Console.WriteLine($"不使用BouncyCastle計算結(jié)果(轉(zhuǎn)十六進制字符串):{Hex.ToHexString(b2)}");}數(shù)字簽名算法
數(shù)字簽名是一個帶有密鑰的消息摘要算法,這個密鑰包括了公鑰和私鑰,用于驗證數(shù)據(jù)完整性、認(rèn)證數(shù)據(jù)來源和抗否認(rèn),遵循OSI參考模型、私鑰簽名和公鑰驗證。也是非對稱加密算法和消息摘要算法的結(jié)合體
FIPS 186-4規(guī)定了三種可用于數(shù)據(jù)保護的數(shù)字簽名生成和驗證技術(shù):數(shù)字簽名算法(DSA),橢圓曲線數(shù)字簽名算法(ECDSA)和Rivest-Shamir Adelman算法( RSA)。
Rivest-Shamir Adelman算法( RSA)
RSA算法是1977年由羅納德·里維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一起提出的。當(dāng)時他們?nèi)硕荚诼槭±砉W(xué)院工作。RSA就是他們?nèi)诵帐祥_頭字母拼在一起組成的。
RSA是目前計算機密碼學(xué)中最經(jīng)典算法,也是目前為止使用最廣泛的數(shù)字簽名算法,從提出到現(xiàn)在已近三十年,經(jīng)歷了各種攻擊的考驗,逐漸為人們接受,普遍認(rèn)為是目前最優(yōu)秀的公鑰方案之一。
代碼實現(xiàn)
SHA1WithRSA
public class SHA1WithRSA{/// <summary>/// 生成簽名/// </summary>public static string GenerateSignature(string data, RSAParameters privateKey){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}using (var rsa = System.Security.Cryptography.RSA.Create()){rsa.ImportParameters(privateKey);return Base64.ToBase64String(rsa.SignData(Encoding.UTF8.GetBytes(data), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));}}/// <summary>/// 驗證簽名/// </summary>public static bool VerifySignature(string data, string sign, RSAParameters publicKey){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}if (string.IsNullOrEmpty(sign)){throw new ArgumentNullException(nameof(sign));}using (var rsa = System.Security.Cryptography.RSA.Create()){rsa.ImportParameters(publicKey);return rsa.VerifyData(Encoding.UTF8.GetBytes(data), Base64.Decode(sign), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);}}/// <summary>/// 生成簽名/// </summary>public static string GenerateSignature(string data, AsymmetricKeyParameter privateKey){var byteData = Encoding.UTF8.GetBytes(data);var normalSig = SignerUtilities.GetSigner("SHA1WithRSA");normalSig.Init(true, privateKey);normalSig.BlockUpdate(byteData, 0, data.Length);var normalResult = normalSig.GenerateSignature();return Base64.ToBase64String(normalResult);}/// <summary>/// 驗證簽名/// </summary>public static bool VerifySignature(string data, string sign, AsymmetricKeyParameter publicKey){var signBytes = Base64.Decode(sign);var plainBytes = Encoding.UTF8.GetBytes(data);var verifier = SignerUtilities.GetSigner("SHA1WithRSA");verifier.Init(false, publicKey);verifier.BlockUpdate(plainBytes, 0, plainBytes.Length);return verifier.VerifySignature(signBytes);}}SHA256WithRSA
public class SHA256WithRSA{/// <summary>/// 生成簽名/// </summary>public static string GenerateSignature(string data, RSAParameters privateKey){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}using (var rsa = System.Security.Cryptography.RSA.Create()){rsa.ImportParameters(privateKey);return Base64.ToBase64String(rsa.SignData(Encoding.UTF8.GetBytes(data), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));}}/// <summary>/// 驗證簽名/// </summary>public static bool VerifySignature(string data, string sign, RSAParameters publicKey){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}if (string.IsNullOrEmpty(sign)){throw new ArgumentNullException(nameof(sign));}using (var rsa = System.Security.Cryptography.RSA.Create()){rsa.ImportParameters(publicKey);return rsa.VerifyData(Encoding.UTF8.GetBytes(data), Base64.Decode(sign), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);}}/// <summary>/// 生成簽名/// </summary>public static string GenerateSignature(string data, AsymmetricKeyParameter parameter){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}if (parameter == null){throw new ArgumentNullException(nameof(parameter));}var signer = SignerUtilities.GetSigner("SHA256WithRSA");signer.Init(true, parameter);var bytes = Encoding.UTF8.GetBytes(data);signer.BlockUpdate(bytes, 0, bytes.Length);return Base64.ToBase64String(signer.GenerateSignature());}/// <summary>/// 驗證簽名/// </summary>public static bool VerifySignature(string data, string sign, AsymmetricKeyParameter parameter){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}if (string.IsNullOrEmpty(sign)){throw new ArgumentNullException(nameof(sign));}if (parameter == null){throw new ArgumentNullException(nameof(parameter));}var verifier = SignerUtilities.GetSigner("SHA256WithRSA");verifier.Init(false, parameter);var bytes = Encoding.UTF8.GetBytes(data);verifier.BlockUpdate(bytes, 0, bytes.Length);return verifier.VerifySignature(Base64.Decode(sign));}}示例代碼
private static void SHA256WithRSA_Sample(){var s = "hello sha256 with rsa";Console.WriteLine(s);var keyParameter = RSAKeyGenerator.Pkcs8(2048);Console.WriteLine("私鑰:");Console.WriteLine(keyParameter.PrivateKey);Console.WriteLine("公鑰:");Console.WriteLine(keyParameter.PublicKey);Console.WriteLine();Console.WriteLine("使用BouncyCastle:");var sign1 = SHA256WithRSA.GenerateSignature(s,RSAUtilities.GetAsymmetricKeyParameterFormAsn1PrivateKey(keyParameter.PrivateKey));Console.WriteLine("sign1:");Console.WriteLine(sign1);var verified1 = SHA256WithRSA.VerifySignature(s, sign1,RSAUtilities.GetAsymmetricKeyParameterFormPublicKey(keyParameter.PublicKey));Console.WriteLine("驗證結(jié)果:");Console.WriteLine(verified1 ? "signature verified" : "signature not verified");Console.WriteLine();Console.WriteLine("不使用BouncyCastle:");var sign2 = SHA256WithRSA.GenerateSignature(s,RSAUtilities.GetRsaParametersFormAsn1PrivateKey(keyParameter.PrivateKey));Console.WriteLine("sign2:");Console.WriteLine(sign2);var verified2 = SHA256WithRSA.VerifySignature(s, sign1,RSAUtilities.GetAsymmetricKeyParameterFormPublicKey(keyParameter.PublicKey));Console.WriteLine("驗證結(jié)果:");Console.WriteLine(verified2 ? "signature verified" : "signature not verified");Console.WriteLine();}數(shù)字簽名算法(DSA)
Digital Signature Algorithm (DSA)是Schnorr和ElGamal簽名算法的變種,被美國NIST作為DSS(DigitalSignature Standard)。DSA是基于整數(shù)有限域離散對數(shù)難題的,其安全性與RSA相比差不多。
DSA(用于數(shù)字簽名算法)的簽名生成速度很快,驗證速度很慢,加密時更慢,但解密時速度很快
目前,最好使用RSA 2048位密鑰(也可以用4096位的RSA密鑰),商業(yè)RSA證書比DSA證書被更廣泛地部署。
OpenSSH 7.0及以上版本默認(rèn)禁用了ssh-dss(DSA)公鑰算法。官方?jīng)]有給出具體的解釋,但其中可能有OpenSSH,DSA密鑰位數(shù)生成的原因,同時生成簽名時隨機性差,可能會泄漏私鑰,且以現(xiàn)在機算機的算力,DSA 1024-bit已經(jīng)實際上可破解,建議不使用。
一般來說,還是推薦大家使用RSA算法。
代碼實現(xiàn)
SHA1/DSA
/// <summary>/// 生成簽名/// </summary>public static string GenerateSignature(string data, AsymmetricKeyParameter privateKey){var byteData = Encoding.UTF8.GetBytes(data);var normalSig = SignerUtilities.GetSigner("SHA1/DSA");normalSig.Init(true, privateKey);normalSig.BlockUpdate(byteData, 0, data.Length);var normalResult = normalSig.GenerateSignature();return Base64.ToBase64String(normalResult);}/// <summary>/// 簽名驗證/// </summary>public static bool VerifySignature(string data, string sign, AsymmetricKeyParameter publicKey){var signBytes = Base64.Decode(sign);var plainBytes = Encoding.UTF8.GetBytes(data);var verifier = SignerUtilities.GetSigner("SHA1/DSA");verifier.Init(false, publicKey);verifier.BlockUpdate(plainBytes, 0, plainBytes.Length);return verifier.VerifySignature(signBytes);}SHA256/DSA
/// <summary>/// 生成簽名/// </summary>public static string GenerateSignature(string data, AsymmetricKeyParameter parameter){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}if (parameter == null){throw new ArgumentNullException(nameof(parameter));}var signer = SignerUtilities.GetSigner("SHA256/DSA");signer.Init(true, parameter);var bytes = Encoding.UTF8.GetBytes(data);signer.BlockUpdate(bytes, 0, bytes.Length);return Base64.ToBase64String(signer.GenerateSignature());}/// <summary>/// 驗證簽名/// </summary>public static bool VerifySignature(string data, string sign, AsymmetricKeyParameter parameter){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}if (string.IsNullOrEmpty(sign)){throw new ArgumentNullException(nameof(sign));}if (parameter == null){throw new ArgumentNullException(nameof(parameter));}var verifier = SignerUtilities.GetSigner("SHA256/DSA");verifier.Init(false, parameter);var bytes = Encoding.UTF8.GetBytes(data);verifier.BlockUpdate(bytes, 0, bytes.Length);return verifier.VerifySignature(Base64.Decode(sign));}示例代碼
private static void SHA256WithDSA_Sample(){var s = "hello dsa";Console.WriteLine(s);var keyParameter = DSAKeyGenerator.Generator();Console.WriteLine("私鑰:");Console.WriteLine(keyParameter.PrivateKey);Console.WriteLine("公鑰:");Console.WriteLine(keyParameter.PublicKey);Console.WriteLine();var sign = SHA256WithDSA.GenerateSignature(s,RSAUtilities.GetAsymmetricKeyParameterFormAsn1PrivateKey(keyParameter.PrivateKey));Console.WriteLine($"sign:{sign}");var verified = SHA256WithDSA.VerifySignature(s, sign,RSAUtilities.GetAsymmetricKeyParameterFormPublicKey(keyParameter.PublicKey));Console.WriteLine("驗證結(jié)果:");Console.WriteLine(verified ? "signature verified" : "signature not verified");}橢圓曲線數(shù)字簽名算法(ECDSA)
橢圓曲線數(shù)字簽名算法(ECDSA)是使用橢圓曲線密碼(ECC)對數(shù)字簽名算法(DSA)的模擬。ECDSA于1999年成為ANSI標(biāo)準(zhǔn),并于2000年成為IEEE和NIST標(biāo)準(zhǔn)。它在1998年既已為ISO所接受,并且包含它的其他一些標(biāo)準(zhǔn)亦在ISO的考慮之中。與普通的離散對數(shù)問題(discrete logarithm problem DLP)和大數(shù)分解問題(integer factorization problem IFP)不同,橢圓曲線離散對數(shù)問題(elliptic curve discrete logarithm problem ECDLP)沒有亞指數(shù)時間的解決方法。因此橢圓曲線密碼的單位比特強度要高于其他公鑰體制。
ECDSA是ECC與DSA的結(jié)合,整個簽名過程與DSA類似,所不一樣的是簽名中采取的算法為ECC
ECC與RSA 相比,有以下的優(yōu)點:
相同密鑰長度下,安全性能更高,如160位ECC已經(jīng)與1024位RSA、DSA有相同的安全強度。
計算量小,處理速度快,在私鑰的處理速度上(解密和簽名),ECC遠 比RSA、DSA快得多。
存儲空間占用小 ECC的密鑰尺寸和系統(tǒng)參數(shù)與RSA、DSA相比要小得多, 所以占用的存儲空間小得多。
帶寬要求低使得ECC具有廣泛得應(yīng)用前景。
代碼實現(xiàn)
SHA1/ECDSA
/// <summary>/// 生成簽名/// </summary>public static string GenerateSignature(string data, AsymmetricKeyParameter parameter){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}if (parameter == null){throw new ArgumentNullException(nameof(parameter));}var signer = SignerUtilities.GetSigner("SHA1/ECDSA");signer.Init(true, parameter);var bytes = Encoding.UTF8.GetBytes(data);signer.BlockUpdate(bytes, 0, bytes.Length);return Base64.ToBase64String(signer.GenerateSignature());}/// <summary>/// 驗證簽名/// </summary>public static bool VerifySignature(string data, string sign, AsymmetricKeyParameter parameter){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}if (string.IsNullOrEmpty(sign)){throw new ArgumentNullException(nameof(sign));}if (parameter == null){throw new ArgumentNullException(nameof(parameter));}var verifier = SignerUtilities.GetSigner("SHA1/ECDSA");verifier.Init(false, parameter);var bytes = Encoding.UTF8.GetBytes(data);verifier.BlockUpdate(bytes, 0, bytes.Length);return verifier.VerifySignature(Base64.Decode(sign));}SHA256/ECDSA
/// <summary>/// 生成簽名/// </summary>public static string GenerateSignature(string data, AsymmetricKeyParameter parameter){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}if (parameter == null){throw new ArgumentNullException(nameof(parameter));}var signer = SignerUtilities.GetSigner("SHA256/ECDSA");signer.Init(true, parameter);var bytes = Encoding.UTF8.GetBytes(data);signer.BlockUpdate(bytes, 0, bytes.Length);return Base64.ToBase64String(signer.GenerateSignature());}/// <summary>/// 驗證簽名/// </summary>public static bool VerifySignature(string data, string sign, AsymmetricKeyParameter parameter){if (string.IsNullOrEmpty(data)){throw new ArgumentNullException(nameof(data));}if (string.IsNullOrEmpty(sign)){throw new ArgumentNullException(nameof(sign));}if (parameter == null){throw new ArgumentNullException(nameof(parameter));}var verifier = SignerUtilities.GetSigner("SHA256/ECDSA");verifier.Init(false, parameter);var bytes = Encoding.UTF8.GetBytes(data);verifier.BlockUpdate(bytes, 0, bytes.Length);return verifier.VerifySignature(Base64.Decode(sign));}示例代碼
private static void SHA256WithECDSA_Sample(){var s = "hello ec dsa";Console.WriteLine(s);var keyParameter = ECDSAKeyGenerator.Generator();Console.WriteLine("私鑰:");Console.WriteLine(keyParameter.PrivateKey);Console.WriteLine("公鑰:");Console.WriteLine(keyParameter.PublicKey);var sign = SHA256WithECDSA.GenerateSignature(s,RSAUtilities.GetAsymmetricKeyParameterFormAsn1PrivateKey(keyParameter.PrivateKey));Console.WriteLine($"sign:{sign}");var verified = SHA256WithECDSA.VerifySignature(s, sign,RSAUtilities.GetAsymmetricKeyParameterFormPublicKey(keyParameter.PublicKey));Console.WriteLine("驗證結(jié)果:");Console.WriteLine(verified ? "signature verified" : "signature not verified");}下期預(yù)告
下一篇將介紹對稱加密算法,敬請期待。。。
總結(jié)
以上是生活随笔為你收集整理的.NET Core加解密实战系列之——消息摘要与数字签名算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入探究ASP.NET Core异常处理
- 下一篇: 造轮子-AgileConfig一个基于.