C#使用應(yīng)用RSA和ECC進行數(shù)字簽名和簽名驗證的示例詳解
基本概念
- RSA 通常用于加密少量數(shù)據(jù)(如對稱密鑰)和數(shù)字簽名。直接使用RSA加密大量數(shù)據(jù)效率較低,更常見的是使用RSA加密一個隨機生成的對稱密鑰,然后用對稱密鑰加密實際數(shù)據(jù)。
- 橢圓曲線算法 (ECC) 在相同的安全級別下,密鑰長度比RSA短得多,因此在性能和存儲方面有優(yōu)勢。它主要用于數(shù)字簽名 (ECDSA) 和密鑰協(xié)商 (ECDH),也可以進行加密(通過結(jié)合ECDH和對稱加密)。
- 密鑰保存:在實際應(yīng)用中,私鑰的保存至關(guān)重要。通常會使用更安全的方式,如Windows證書存儲、硬件安全模塊 (HSM) 或加密存儲在文件中。這里提供的文件保存示例僅用于演示目的,不應(yīng)直接用于生產(chǎn)環(huán)境。
- 異常處理:為了代碼簡潔,示例中的異常處理可能不夠完善,實際應(yīng)用中應(yīng)加強。
RSA 算法示例
RSA算法在.NET中主要通過RSACryptoServiceProvider (舊版) 或 RSA (推薦,跨平臺) 類實現(xiàn)。這里我們使用 RSA 類。
1. 密鑰生成與保存
using System.Security.Cryptography;
namespace RsaEcdsaCryption
{
public class RsaHelper
{
// 生成RSA密鑰對并保存到文件
public static void GenerateAndSaveRsaKeys(string privateKeyPath, string publicKeyPath)
{
using (RSA rsa = RSA.Create())
{
// 設(shè)置密鑰長度 (例如,2048位)
rsa.KeySize = 2048;
// 導(dǎo)出私鑰 (包含所有參數(shù))
string privateKeyXml = rsa.ToXmlString(true);
File.WriteAllText(privateKeyPath, privateKeyXml);
// 導(dǎo)出公鑰 (只包含模數(shù)和指數(shù))
string publicKeyXml = rsa.ToXmlString(false);
File.WriteAllText(publicKeyPath, publicKeyXml);
Console.WriteLine($"RSA 私鑰已保存到: {privateKeyPath}");
Console.WriteLine($"RSA 公鑰已保存到: {publicKeyPath}");
}
}
// 從文件加載RSA私鑰
public static RSA LoadRsaPrivateKey(string privateKeyPath)
{
RSA rsa = RSA.Create();
string privateKeyXml = File.ReadAllText(privateKeyPath);
rsa.FromXmlString(privateKeyXml);
return rsa;
}
// 從文件加載RSA公鑰
public static RSA LoadRsaPublicKey(string publicKeyPath)
{
RSA rsa = RSA.Create();
string publicKeyXml = File.ReadAllText(publicKeyPath);
rsa.FromXmlString(publicKeyXml);
return rsa;
}
}
}
2. 加密與解密
RSA加密通常是公鑰加密,私鑰解密。
using System.Security.Cryptography;
using System.Text;
namespace RsaEcdsaCryption
{
public class RsaEncryptionDecryption
{
// 使用RSA公鑰加密數(shù)據(jù)
public static byte[] Encrypt(byte[] data, RSA publicKeyRsa)
{
// OEAP填充模式推薦用于加密,提供更好的安全性
return publicKeyRsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
}
// 使用RSA私鑰解密數(shù)據(jù)
public static byte[] Decrypt(byte[] encryptedData, RSA privateKeyRsa)
{
// OEAP填充模式推薦用于解密
return privateKeyRsa.Decrypt(encryptedData, RSAEncryptionPadding.OaepSHA256);
}
public static void RunEncryptionDecryptionExample(RSA publicKey, RSA privateKey)
{
string originalText = "這是一段要使用RSA加密的秘密消息。";
byte[] originalBytes = Encoding.UTF8.GetBytes(originalText);
Console.WriteLine($"\n原始消息: {originalText}");
// 加密
byte[] encryptedBytes = Encrypt(originalBytes, publicKey);
Console.WriteLine($"加密后 (Base64): {Convert.ToBase64String(encryptedBytes)}");
// 解密
byte[] decryptedBytes = Decrypt(encryptedBytes, privateKey);
string decryptedText = Encoding.UTF8.GetString(decryptedBytes);
Console.WriteLine($"解密后: {decryptedText}");
Console.WriteLine($"加密/解密 {(originalText == decryptedText ? "成功" : "失敗")}");
}
}
}
3. 數(shù)字簽名與驗證
RSA簽名通常使用私鑰簽名,公鑰驗證。
using System.Security.Cryptography;
using System.Text;
public class RsaSignature
{
// 使用RSA私鑰對數(shù)據(jù)進行簽名
public static byte[] SignData(byte[] data, RSA privateKeyRsa)
{
// 選擇哈希算法 (例如,SHA256) 和填充模式 (PSS推薦用于簽名)
return privateKeyRsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
}
// 使用RSA公鑰驗證簽名
public static bool VerifySignature(byte[] data, byte[] signature, RSA publicKeyRsa)
{
// 選擇哈希算法和填充模式與簽名時一致
return publicKeyRsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
}
public static void RunSignatureExample(RSA publicKey, RSA privateKey)
{
string messageToSign = "這是一段要進行數(shù)字簽名的消息。";
byte[] messageBytes = Encoding.UTF8.GetBytes(messageToSign);
Console.WriteLine($"\n待簽名消息: {messageToSign}");
// 簽名
byte[] signature = SignData(messageBytes, privateKey);
Console.WriteLine($"生成簽名 (Base64): {Convert.ToBase64String(signature)}");
// 驗證簽名
bool isValid = VerifySignature(messageBytes, signature, publicKey);
Console.WriteLine($"簽名驗證結(jié)果: {(isValid ? "有效" : "無效")}");
// 嘗試篡改數(shù)據(jù)后驗證簽名
Console.WriteLine("\n嘗試篡改數(shù)據(jù)后驗證簽名...");
byte[] tamperedMessageBytes = Encoding.UTF8.GetBytes("這是一段被篡改的消息。");
bool isTamperedValid = VerifySignature(tamperedMessageBytes, signature, publicKey);
Console.WriteLine($"篡改后簽名驗證結(jié)果: {(isTamperedValid ? "有效" : "無效")}");
}
}
橢圓曲線數(shù)字簽名算法 (ECDSA) 示例
ECDSA在.NET中主要通過 ECDsa 類實現(xiàn)。
1. 密鑰生成與保存
ECDSA密鑰通常是公私鑰對,公鑰可以從私鑰派生。
using System.Security.Cryptography;
public class EcdsaHelper
{
// 生成ECDSA密鑰對并保存到文件
public static void GenerateAndSaveEcdsaKeys(string privateKeyPath, string publicKeyPath)
{
// 選擇一個命名曲線,例如 P-256 (secp256r1)
using (ECDsa ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256))
{
// 導(dǎo)出私鑰(PKCS#8格式,PEM編碼)
string privateKeyPem = ecdsa.ExportPkcs8PrivateKeyPem();
File.WriteAllText(privateKeyPath, privateKeyPem);
// 導(dǎo)出公鑰(SubjectPublicKeyInfo格式,PEM編碼)
string publicKeyPem = ecdsa.ExportSubjectPublicKeyInfoPem();
File.WriteAllText(publicKeyPath, publicKeyPem);
Console.WriteLine($"ECDSA 私鑰已保存到: {privateKeyPath}");
Console.WriteLine($"ECDSA 公鑰已保存到: {publicKeyPath}");
}
}
// 從文件加載ECDSA私鑰
public static ECDsa LoadEcdsaPrivateKey(string privateKeyPath)
{
ECDsa ecdsa = ECDsa.Create();
string privateKeyPem = File.ReadAllText(privateKeyPath);
ecdsa.ImportFromPem(privateKeyPem); // 或 ImportPkcs8PrivateKeyPem
return ecdsa;
}
// 從文件加載ECDSA公鑰
public static ECDsa LoadEcdsaPublicKey(string publicKeyPath)
{
ECDsa ecdsa = ECDsa.Create();
string publicKeyPem = File.ReadAllText(publicKeyPath);
ecdsa.ImportFromPem(publicKeyPem); // 或 ImportSubjectPublicKeyInfoPem
return ecdsa;
}
}
2. 數(shù)字簽名與驗證
ECDSA主要用于簽名,不支持直接的加密/解密操作(需要結(jié)合ECDH和對稱加密才能實現(xiàn))。
using System.Security.Cryptography;
using System.Text;
public class EcdsaSignature
{
// 使用ECDSA私鑰對數(shù)據(jù)進行簽名
public static byte[] SignData(byte[] data, ECDsa privateKeyEcdsa)
{
// 選擇哈希算法 (例如,SHA256)
return privateKeyEcdsa.SignData(data, HashAlgorithmName.SHA256);
}
// 使用ECDSA公鑰驗證簽名
public static bool VerifySignature(byte[] data, byte[] signature, ECDsa publicKeyEcdsa)
{
// 選擇哈希算法與簽名時一致
return publicKeyEcdsa.VerifyData(data, signature, HashAlgorithmName.SHA256);
}
public static void RunSignatureExample(ECDsa publicKey, ECDsa privateKey)
{
string messageToSign = "這是一段要使用ECDSA進行數(shù)字簽名的消息。";
byte[] messageBytes = Encoding.UTF8.GetBytes(messageToSign);
Console.WriteLine($"\n待簽名消息: {messageToSign}");
// 簽名
byte[] signature = SignData(messageBytes, privateKey);
Console.WriteLine($"生成簽名 (Base64): {Convert.ToBase64String(signature)}");
// 驗證簽名
bool isValid = VerifySignature(messageBytes, signature, publicKey);
Console.WriteLine($"簽名驗證結(jié)果: {(isValid ? "有效" : "無效")}");
// 嘗試篡改數(shù)據(jù)后驗證簽名
Console.WriteLine("\n嘗試篡改數(shù)據(jù)后驗證簽名...");
byte[] tamperedMessageBytes = Encoding.UTF8.GetBytes("這是一段被篡改的消息。");
bool isTamperedValid = VerifySignature(tamperedMessageBytes, signature, publicKey);
Console.WriteLine($"篡改后簽名驗證結(jié)果: {(isTamperedValid ? "有效" : "無效")}");
}
}
主程序示例 (Program.cs)
將上述類集成到Program.cs中,演示如何使用它們。
using System;
using System.IO;
using System.Security.Cryptography;
public class Program
{
public static void Main(string[] args)
{
// 定義密鑰文件路徑
string rsaPrivateKeyPath = "rsa_private_key.xml";
string rsaPublicKeyPath = "rsa_public_key.xml";
string ecdsaPrivateKeyPath = "ecdsa_private_key.pem";
string ecdsaPublicKeyPath = "ecdsa_public_key.pem";
Console.WriteLine("--- RSA 示例 ---");
// RSA 密鑰生成與保存
RsaHelper.GenerateAndSaveRsaKeys(rsaPrivateKeyPath, rsaPublicKeyPath);
RSA rsaPublicKey = RsaHelper.LoadRsaPublicKey(rsaPublicKeyPath);
RSA rsaPrivateKey = RsaHelper.LoadRsaPrivateKey(rsaPrivateKeyPath);
// RSA 加密與解密
RsaEncryptionDecryption.RunEncryptionDecryptionExample(rsaPublicKey, rsaPrivateKey);
// RSA 數(shù)字簽名與驗證
RsaSignature.RunSignatureExample(rsaPublicKey, rsaPrivateKey);
Console.WriteLine("\n--- ECDSA 示例 ---");
// ECDSA 密鑰生成與保存
EcdsaHelper.GenerateAndSaveEcdsaKeys(ecdsaPrivateKeyPath, ecdsaPublicKeyPath);
ECDsa ecdsaPublicKey = EcdsaHelper.LoadEcdsaPublicKey(ecdsaPublicKeyPath);
ECDsa ecdsaPrivateKey = EcdsaHelper.LoadEcdsaPrivateKey(ecdsaPrivateKeyPath);
// ECDSA 數(shù)字簽名與驗證
EcdsaSignature.RunSignatureExample(ecdsaPublicKey, ecdsaPrivateKey);
// 清理生成的密鑰文件 (可選)
// File.Delete(rsaPrivateKeyPath);
// File.Delete(rsaPublicKeyPath);
// File.Delete(ecdsaPrivateKeyPath);
// File.Delete(ecdsaPublicKeyPath);
Console.WriteLine("\n所有示例運行完畢。");
Console.ReadKey();
}
}
運行環(huán)境要求
- .NET Core 3.1 或更高版本 / .NET 5.0 或更高版本:
RSA.Create(),ECDsa.Create(ECCurve.NamedCurves.nistP256),ExportPkcs8PrivateKeyPem(),ExportSubjectPublicKeyInfoPem(),ImportFromPem()等方法需要較新的.NET版本支持。如果您使用的是較舊的.NET Framework,可能需要調(diào)整為RSACryptoServiceProvider和ECDiffieHellmanCng/ECDsaCng,但它們的使用方式有所不同,且通常更推薦使用新的API。
關(guān)于數(shù)字證書
數(shù)字證書是公鑰基礎(chǔ)設(shè)施 (PKI) 的核心組成部分,它將公鑰與實體的身份綁定在一起,并由可信的第三方(證書頒發(fā)機構(gòu) C A)進行簽名。上述示例只是生成了原始的公鑰和私鑰文件,并沒有涉及證書的生成和使用。
如果需要處理數(shù)字證書,C# 提供了 X509Certificate2 類來加載、創(chuàng)建和管理證書。通常涉及:
- 加載證書:從文件 (
.pfx,.cer) 或證書存儲區(qū)加載。 - 提取公鑰:從
X509Certificate2對象中獲取RSA或ECDsa公鑰。 - 使用私鑰:如果證書包含私鑰,可以直接用它進行簽名或解密。
示例:
// 假設(shè)你有一個帶有私鑰的PFX文件
// string certPath = "myCert.pfx";
// string certPassword = "myPassword";
// using (X509Certificate2 cert = new X509Certificate2(certPath, certPassword))
// {
// // 獲取公鑰用于驗證
// RSA rsaPublicKeyFromCert = cert.GetRSAPublicKey(); // 或 GetECDsaPublicKey()
// // 獲取私鑰用于簽名
// RSA rsaPrivateKeyFromCert = cert.GetRSAPrivateKey(); // 或 GetECDsaPrivateKey()
// // 然后就可以用這些密鑰進行簽名/驗證或加密/解密
// }
程序運行效果如下:

以上就是C#使用應(yīng)用RSA和ECC進行數(shù)字簽名和簽名驗證的示例詳解的詳細內(nèi)容,更多關(guān)于C# RSA和ECC數(shù)字簽名和簽名驗證的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#利用Free Spire.XLS for .NET復(fù)制Excel工作表
在日常的 .NET 開發(fā)中,我們經(jīng)常需要操作 Excel 文件,本文將詳細介紹C#如何使用Free Spire.XLS for .NET 在同一工作簿內(nèi)或不同工作簿之間復(fù)制工作表,有需要的可以了解下2025-09-09

