Comprehensive Guide to Message Digest, MAC, and Digital Signature Algorithms in .NET Core with BouncyCastle
This article introduces various cryptographic primitives—including MD, SHA, MAC, and digital signature algorithms such as RSA, DSA, and ECDSA—explains their usage and security considerations, and provides complete .NET Core code examples using the BouncyCastle library for implementation.
Introduction
The article explains the background and motivation for implementing encryption, hashing, MAC, and digital signature algorithms in .NET Core, highlighting cross‑platform compatibility, language interoperability, and the limitations of the built‑in .NET libraries.
Message Digest Algorithms
Two main families are covered: the MD family (MD2, MD4, MD5) and the SHA family (SHA‑1, SHA‑2, SHA‑3). Historical development, security weaknesses (e.g., MD5 collisions), and typical application scenarios such as integrity verification and password storage are discussed.
MD5 Example
public static class MD5
{
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;
}
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));
}
}
}SHA1 Example
public static class SHA1
{
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;
}
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));
}
}
}MAC and HMAC
MAC (Message Authentication Code) adds a secret key to a hash function, providing authentication and integrity. HMAC is the most common MAC construction and can be combined with many hash algorithms (MD5, SHA‑1, SHA‑256, etc.). Typical use cases include challenge/response authentication and password protection.
HMAC‑MD5 Example
public static class HMACMD5
{
public static byte[] GeneratorKey()
{
return HMAC.GeneratorKey(Algorithms.HMacMD5);
}
public static byte[] Compute(string data, byte[] key)
{
return HMAC.Compute(data, key, Algorithms.HMacMD5);
}
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));
}
}
}Digital Signature Algorithms
Three standards are covered: RSA, DSA, and ECDSA. Their security properties, historical background, and practical recommendations (e.g., prefer RSA‑2048 or ECC over DSA) are explained.
RSA Signature (SHA1WithRSA) Example
public static class SHA1WithRSA
{
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);
var signature = rsa.SignData(Encoding.UTF8.GetBytes(data), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
return Base64.ToBase64String(signature);
}
}
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);
}
}
}DSA Signature (SHA1/DSA) Example
public static class SHA1DSA
{
public static string GenerateSignature(string data, AsymmetricKeyParameter privateKey)
{
var bytes = Encoding.UTF8.GetBytes(data);
var signer = SignerUtilities.GetSigner("SHA1/DSA");
signer.Init(true, privateKey);
signer.BlockUpdate(bytes, 0, bytes.Length);
return Base64.ToBase64String(signer.GenerateSignature());
}
public static bool VerifySignature(string data, string sign, AsymmetricKeyParameter publicKey)
{
var signBytes = Base64.Decode(sign);
var bytes = Encoding.UTF8.GetBytes(data);
var verifier = SignerUtilities.GetSigner("SHA1/DSA");
verifier.Init(false, publicKey);
verifier.BlockUpdate(bytes, 0, bytes.Length);
return verifier.VerifySignature(signBytes);
}
}ECDSA Signature (SHA256/ECDSA) Example
public static class SHA256WithECDSA
{
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());
}
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));
}
}Conclusion
The article provides a practical reference for developers needing to integrate hashing, MAC, and digital signature functionality into .NET Core applications, offering both BouncyCastle‑based and native .NET implementations and highlighting security best practices.
Fulu Network R&D Team
Providing technical literature sharing for Fulu Holdings' tech elite, promoting its technologies through experience summaries, technology consolidation, and innovation sharing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.