.NET Core加解密实战系列之——消息摘要与数字签名算法

简介

加解密现状,编写此系列文章的背景:

  • 需要考虑系统环境兼容性问题(Linux、Windows)

  • 语言互通问题(如C#、Java等)(加解密本质上没有语言之分,所以原则上不存在互通性问题)

  • 网上资料版本不一、或不全面

  • .NET官方库密码算法提供不全面,很难针对其他语言(Java)进行适配

本系列文章主要介绍如何在 .NET Core 中使用非对称加密算法、编码算法、消息摘要算法、签名算法、对称加密算法、国密算法等一系列算法,如有错误之处,还请大家批评指正。

本系列文章旨在引导大家能快速、轻松的了解接入加解密,乃至自主组合搭配使用BouncyCastle密码术包中提供的算法。

本文中代码示例仅列举了比较常见的使用方式(BouncyCastle中提供的算法远不止这些),另外算法DSA和ECDSA我们未在项目中使用过,代码组合性非常多,因此文中部分代码仅供参考。

本系列代码项目地址:https://github.com/fuluteam/ICH.BouncyCastle.git

上一篇文章《.NET Core加解密实战系列之——RSA非对称加密算法》:https://www.cnblogs.com/fulu/p/13100471.html

功能依赖

BouncyCastle(https://www.bouncycastle.org/csharp) 是一个开放源码的轻量级密码术包;它支持大量的密码术算法,它提供了很多 .NET Core标准库没有的算法。

支持 .NET 4,.NET Standard 1.0-2.0,WP,Silverlight,MonoAndroid,Xamarin.iOS,.NET Core

功能依赖
Portable.BouncyCastlePortable.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):消息认证码

MD算法

MD消息摘要算法,一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。

家族发展史

  • MD2算法:

    1989年,著名的非对称算法RSA发明人之一麻省理工学院教授罗纳德·李维斯特开发了MD2算法。这个算法首先对信息进行数据补位,使信息的字节长度是16的倍数。再以一个16位的检验和做为补充信息追加到原信息的末尾。最后根据这个新产生的信息计算出一个128位的散列值,MD2算法由此诞生。

  • MD4算法:

    1990年,罗纳德·李维斯特教授开发出较之MD2算法有着更高安全性的MD4算法。MD4算法对后续消息摘要算法起到了推动作用,许多比较有名的消息摘要算法都是在MD4算法的基础上发展而来的,如MD5、SHA-1、RIPE-MD和HAVAL算法等。

  • MD5算法:

    1991年,继MD4算法后,罗纳德·李维斯特教授开发了MD5算法,用以取代MD4算法。这套算法的程序在 RFC 1321 标准中被加以规范。MD5算法经MD2、MD3和MD4算法发展而来,算法复杂程度和安全强度大大提高,MD算法的最终结果都是产生一个128位的信息摘要。这也是MD系列算法的特点。

    1996年,该算法被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA-2。

    2004年,证实MD5算法无法防止碰撞(collision),因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。

应用场景

消息摘要算法是不可逆的,所以信息摘要场景主要被用来验证信息的完整性,防止信息被篡改,主要场景如下:

  • 验签:对要发送的数据做MD5(一般加slat)MD5值和数据一同发送,接收方接受数据做同样的MD5计算,比较MD5值是否一致

  • 密码保护:比如用户密码存储上,一般都是存储MD5值,更高一级的涉及是针对每个用户生成一个随机的slat,然后进MD5(passport + slat)计算,将这个值存储到DB中

代码实现

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转换得到结果:{a1}");var a2 = Hex.ToHexString(resBytes1).ToUpper();Console.WriteLine($"通过Hex.ToHexString转换得到结果:{a2}");var a3 = Hex.ToHexString(resBytes2).ToUpper();Console.WriteLine($"不使用BouncyCastle得到结果:{a3}");Console.WriteLine();}

SHA算法

安全散列算法(英文:Secure Hash Algorithm,缩写为SHA)是一个密码散列函数家族,是FIPS所认证的安全散列算法。

SHA家族的五个算法,分别是SHA-1、SHA-224、SHA-256、SHA-384,和SHA-512,由美国国家安全局(NSA)所设计,并由美国国家标准与技术研究院(NIST)发布;是美国的政府标准。后四者有时并称为SHA-2。SHA-1在许多安全协定中广为使用,包括TLS和SSL、PGP、SSH、S/MIME和IPsec,曾被视为是MD5(更早之前被广为使用的杂凑函数)的后继者。但SHA-1的安全性如今被密码学家严重质疑;虽然至今尚未出现对SHA-2有效的攻击,它的算法跟SHA-1基本上仍然相似;因此有些人开始发展其他替代的杂凑算法。

2017年2月23日,Google公司公告宣称他们与CWI Amsterdam合作共同创建了两个有着相同的SHA-1值但内容不同的PDF文件,这代表SHA-1算法已被正式攻破

应用场景

目前SHA1的应用较为广泛,主要应用于CA和数字证书中,另外在目前互联网中流行的BT软件中,也是使用SHA1来进行文件校验的。

代码实现

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计算结果(转Base64字符串):{Base64.ToBase64String(SHA256.Compute1(s))}");Console.WriteLine($"不使用BouncyCastle计算结果(转Base64字符串):{Base64.ToBase64String(SHA256.Compute2(s))}");}

MAC算法

消息认证码算法(英文:Message Authentication Codes,缩写为MAC) 含有密钥的散列函数算法,兼容了MD和SHA算法的特性,并在此基础上加上了密钥。因此MAC算法也经常被称作HMAC算法。消息的散列值由只有通信双方知道的密钥来控制。此时Hash值称作MAC。

HMAC是密钥相关的散列运算消息认证码(Hash-based Message Authentication Code)的缩写,由H.Krawezyk,M.Bellare,R.Canetti于1996年提出的一种基于Hash函数和密钥进行消息认证的方法,并于1997年作为RFC2104被公布,并在IPSec和其他网络协议(如SSL)中得以广泛应用,现在已经成为事实上的Internet安全标准。它可以与任何迭代散列函数捆绑使用。

HMAC算法的典型应用

HMAC算法的一个典型应用是用在“挑战/响应”(Challenge/Response)身份认证中,认证流程如下:

(1) 先由客户端向服务器发出一个验证请求。(2) 服务器接到此请求后生成一个随机数并通过网络传输给客户端(此为挑战)。(3) 客户端将收到的随机数与自己的密钥进行HMAC-SHA1运算并得到一个结果作为认证证据传给服务器(此为响应)。(4) 与此同时,服务器也使用该随机数与存储在服务器数据库中的该客户密钥进行HMAC-SHA1运算,如果服务器的运算结果与客户端传回的响应结果相同,则认为客户端是一个合法用户 。

HMAC算法的安全性

HMAC算法引入了密钥,其安全性已经不完全依赖于所使用的HASH算法,安全性主要有以下几点保证:

(1) 使用的密钥是双方事先约定的,第三方不可能知道。由上面介绍应用流程可以看出,作为非法截获信息的第三方,能够得到的信息只有作为“挑战”的随机数和作为“响应”的HMAC结果,无法根据这两个数据推算出密钥。由于不知道密钥,所以无法仿造出一致的响应。(2)在HMAC算法的应用中,第三方不可能事先知道输出(如果知道,不用构造输入,直接将输出送给服务器即可)。(3) HMAC算法与一般的加密重要的区别在于它具有“瞬时”性,即认证只在当时有效,而加密算法被破解后,以前的加密结果就可能被解密。

HMAC组合散列函数

与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";......}

代码实现

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计算结果(转Base64字符串):{Base64.ToBase64String(b1)}");Console.WriteLine($"使用BouncyCastle计算结果(转十六进制字符串):{Hex.ToHexString(b1)}");var b2 = HMACSHA256.Compute2(s, k);Console.WriteLine($"不使用BouncyCastle计算结果(转Base64字符串):{Base64.ToBase64String(b2)}");Console.WriteLine($"不使用BouncyCastle计算结果(转十六进制字符串):{Hex.ToHexString(b2)}");}

数字签名算法

数字签名是一个带有密钥的消息摘要算法,这个密钥包括了公钥和私钥,用于验证数据完整性、认证数据来源和抗否认,遵循OSI参考模型、私钥签名和公钥验证。也是非对称加密算法和消息摘要算法的结合体

FIPS 186-4规定了三种可用于数据保护的数字签名生成和验证技术:数字签名算法(DSA),椭圆曲线数字签名算法(ECDSA)和Rivest-Shamir Adelman算法( RSA)。

Rivest-Shamir Adelman算法( RSA)

RSA算法是1977年由罗纳德·里维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。

RSA是目前计算机密码学中最经典算法,也是目前为止使用最广泛的数字签名算法,从提出到现在已近三十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。

代码实现

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("验证结果:");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("验证结果:");Console.WriteLine(verified2 ? "signature verified" : "signature not verified");Console.WriteLine();}

数字签名算法(DSA)

Digital Signature Algorithm (DSA)是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard)。DSA是基于整数有限域离散对数难题的,其安全性与RSA相比差不多。

DSA(用于数字签名算法)的签名生成速度很快,验证速度很慢,加密时更慢,但解密时速度很快

目前,最好使用RSA 2048位密钥(也可以用4096位的RSA密钥),商业RSA证书比DSA证书被更广泛地部署。

OpenSSH 7.0及以上版本默认禁用了ssh-dss(DSA)公钥算法。官方没有给出具体的解释,但其中可能有OpenSSH,DSA密钥位数生成的原因,同时生成签名时随机性差,可能会泄漏私钥,且以现在机算机的算力,DSA 1024-bit已经实际上可破解,建议不使用。

一般来说,还是推荐大家使用RSA算法。

代码实现

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("验证结果:");Console.WriteLine(verified ? "signature verified" : "signature not verified");}

椭圆曲线数字签名算法(ECDSA)

椭圆曲线数字签名算法(ECDSA)是使用椭圆曲线密码(ECC)对数字签名算法(DSA)的模拟。ECDSA于1999年成为ANSI标准,并于2000年成为IEEE和NIST标准。它在1998年既已为ISO所接受,并且包含它的其他一些标准亦在ISO的考虑之中。与普通的离散对数问题(discrete logarithm problem DLP)和大数分解问题(integer factorization problem IFP)不同,椭圆曲线离散对数问题(elliptic curve discrete logarithm problem ECDLP)没有亚指数时间的解决方法。因此椭圆曲线密码的单位比特强度要高于其他公钥体制。

ECDSA是ECC与DSA的结合,整个签名过程与DSA类似,所不一样的是签名中采取的算法为ECC

ECC与RSA 相比,有以下的优点:

  • 相同密钥长度下,安全性能更高,如160位ECC已经与1024位RSA、DSA有相同的安全强度。

  • 计算量小,处理速度快,在私钥的处理速度上(解密和签名),ECC远 比RSA、DSA快得多。

  • 存储空间占用小 ECC的密钥尺寸和系统参数与RSA、DSA相比要小得多, 所以占用的存储空间小得多。

  • 带宽要求低使得ECC具有广泛得应用前景。

代码实现

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("验证结果:");Console.WriteLine(verified ? "signature verified" : "signature not verified");}

下期预告

下一篇将介绍对称加密算法,敬请期待。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309051.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

造轮子-AgileConfig一个基于.NetCore开发的轻量级配置中心

微服务确实是行业的一个趋势&#xff0c;我自己也在把一些项目往微服务架构迁移。玩微服务架构配置中心是一个绕不过去的东西&#xff0c;有很多大牌的组件可以选&#xff0c;比如spring-cloud-config&#xff0c;apoll&#xff0c;disconf等等。而我为什么还要造一个轮子呢&am…

SQL Server 分页+json分享

1。SQL Server 版本2012 新增SQL分页的写法最近封装一个轻量级的ORM用到了分页&#xff0c;以前只知道使用Row_Number函数&#xff0c;现在发现sqlserver 新增的 {orderBy} offset {start} rows fetch next {pageSize} rows only 也挺好用的。简单回顾下 sqlserver 各个版本支持…

用十行代码快速创建权限管理系统

&#xff08;坚持做自己&#xff09;为了防止说是标题党&#xff0c;我先展示下真是就需要十行代码&#xff1a;当然还有appsettings.json配置文件&#xff0c;和种子数据文件&#xff0c;这个不算代码之内。1、项目背景介绍Blog.Core项目开源也两年了&#xff0c;经过了很多许…

ERP的配置管理实践

源宝导读&#xff1a;随着ERP系统的日益复杂&#xff0c;应用部署的方式越来越复杂&#xff0c;应用的配置也变得越来越庞杂&#xff0c;难以维护和管理。本文将介绍配置中心服务通过集中化、可离线的架构设计&#xff0c;解决ERP配置问题的实践经验。一、背景随着ERP业务的日益…

《LIO-SAM阅读笔记》1.IMU预积分模块

前言&#xff1a; LIO-SAM是一个多传感器融合的紧耦合SLAM框架&#xff0c;融合的传感器类型有雷达、IMU和GPS&#xff0c;其中雷达和IMU在LIO-SAM框架中必须使用的。LIO-SAM的优化策略采用了GTSAM库&#xff0c;GTSAM库采用了因子图的优化方法&#xff0c;其提供了一些列C的外…

EntityFramework Core 迁移忽略主外键关系

【导读】本文来源于一位公众号童鞋私信我的问题&#xff0c;在我稍加思索后给出了如下一种方案&#xff0c;在此之前我也思考过这个问题&#xff0c;借此机会我稍微看了下&#xff0c;目前能够想到的也只是本文所述方案。为何要忽略主外键关系我们不仅疑惑为何要忽略主外键关系…

你很可能需要知道这个调试小技巧

缘起 最近在调试的时候&#xff0c;需要观察第三方容器中每一个元素的值。默认情况下&#xff0c;vs 并不知道如何显示第三方容器的内容&#xff0c;只能手动观察容器中的每一个值&#xff0c;超级不方便。我找到一个非常给力的好办法&#xff0c;你还知道其它好办法吗&#xf…

全宇宙首本 VS Code 中文书,来了!

大家好&#xff01;我是韩骏&#xff0c;VS Code 中文社区创始人&#xff0c;VS Code 的代码贡献者。2013 年&#xff0c;毕业于上海交通大学软件学院&#xff0c;现在是微软开发平台事业部的软件工程师。写过 20 多款 VS Code 插件&#xff0c;其中最热门的 Code Runner 插件有…

C# 从1到Core--委托与事件

委托与事件在C#1.0的时候就有了&#xff0c;随着C#版本的不断更新&#xff0c;有些写法和功能也在不断改变。本文温故一下这些改变&#xff0c;以及在NET Core中关于事件的一点改变。一、C#1.0 从委托开始1. 基本方式什么是委托&#xff0c;就不说概念了&#xff0c;用例子说话…

开源导入导出库Magicodes.IE 多sheet导入教程

多Sheet导入教程说明本教程主要说明如何使用Magicodes.IE.Excel完成多个Sheet数据的Excel导入。要点多个相同格式的Sheet数据导入多个不同格式的Sheet数据导入主要步骤1. 多个相同格式的Sheet数据导入1.1 创建导入Sheet的Dto主要代码如下所示&#xff1a;学生数据Dto/// <su…

解决 Azure AD 在 Azure Front Door 下登录失败的问题

点击上方关注“汪宇杰博客” ^_^导语最近我给博客系统加上了 Azure Front Door&#xff0c;集齐了12项 Azure 服务打算召唤神龙。没想到刚上线&#xff0c;Azure AD 的单点登录就爆了。OIDC 跳转错误当我尝试登录博客后台的时候&#xff0c;OIDC的跳转URL突然变成了 https://ed…

《Unit Testing》2.1 经典学派如何做测试隔离

经典学派如何解决隔离问题首先&#xff0c;再回顾一下单元测试的三个重要特性&#xff1a;验证一小段代码&#xff08;或者叫一个单元&#xff09;执行速度快使用隔离的方式进行针对第一个特性就会引出一个问题&#xff1a;多小的一段代码才足够小&#xff1f;如果你采用针对每…

Hacker News热文:请停止学习框架,学习领域驱动设计(DDD)(获500个点赞)

在 Hacker News 上获得接近 500 个点赞的一篇名为《停止学习框架》的文章称&#xff1a;我们是程序员&#xff0c;每天都在了解最新的技术&#xff0c;每天都在学习编程语言、框架和库&#xff0c;因为我们知道的现代编程工具越多越好&#xff0c;对吧&#xff1f;不停地追随 A…

C#跨平台开源项目实战(WPF/Android/IOS/Blazor)

个人介绍由于本人从业WPF开发, 考虑到国内的WPF开发环境并不是很好, 资源少、项目案例少, 所以导致很多初学者就已经断了念头。所以我作为WPF的从业者, 就在2019年,开始了发布自己的WPF相关的免费教学视频。发布开源的项目实践, WPF的基础视频、项目实践视频, 包括WPF UI设计视…

[开源] .Net 使用 ORM 访问 神舟通用数据库(神通)

前言天津神舟通用数据技术有限公司&#xff08;简称“神舟通用公司”&#xff09;&#xff0c;隶属于中国航天科技集团&#xff08;CASC&#xff09;。是国内从事数据库、大数据解决方案和数据挖掘分析产品研发的专业公司。公司获得了国家核高基科技重大专项重点支持&#xff0…

在 Xunit 中使用依赖注入

在 Xunit 中使用依赖注入Intro之前写过一篇 xunit 的依赖注入相关的文章&#xff0c;但是实际使用起来不是那么方便今天介绍一个基于xunit和微软依赖注入框架的“真正”的依赖注入使用方式 ——— Xunit.DependencyInjection, 来自大师的作品&#xff0c;让你在测试代码里使用依…

C#由转换二进制所引起的思考,了解下?

【导读】最近遇到很有意思转换二进制的问题&#xff0c;有部分童鞋俨然已了解&#xff0c;可能也有一部分童鞋没碰到过也就不知情&#xff0c;这里我们来深入学习下转换二进制所带来的问题。在写此篇文章时&#xff0c;非常开心&#xff0c;收到再一次连任MVP的邮件&#xff0c…

.Net Core In Docker 在容器内编译并发布

Docker可以说是现在微服务&#xff0c;DevOps的基础&#xff0c;咱们.Net Core自然也得上Docker。.Net Core发布到Docker容器的教程网上也有不少&#xff0c;但是今天还是想来写一写。你搜.Net core程序发布到Docker网上一般常见的有两种方案&#xff1a;1、在本地编译成Dll文件…

带你深入探究云原生时代的分布式操作系统 Kubernetes

过去几年&#xff0c;以 docker、kubernetes 为代表的容器技术已发展为一项通用技术&#xff0c;BAT、滴滴、京东、头条等大厂&#xff0c;都争相把容器和 k8s 项目作为技术重心&#xff0c;试图“放长线钓大鱼”。就说腾讯吧&#xff0c;目前基本所有业务都跑在云上&#xff0…

C# 9.0 新特性之 Lambda 弃元参数

阅读本文大概需要不到 1 分钟。弃元&#xff08;Discards&#xff09; 是在 C# 7.0 的时候开始支持的&#xff0c;它是一种人为丢弃不使用的临时虚拟变量。语法上它是用来赋值的&#xff0c;但它却不被分配存储空间&#xff0c;即没有值&#xff0c;所以不能从中读取值。弃元用…