C#使用应用RSA和ECC进行数字签名和签名验证的示例详解

 更新时间:2025年09月29日 09:23:59   作者:Humbunklung  
开发中需要用到数字签名和验签,这篇博客提供使用RSA和ECDSA(椭圆曲线数字签名算法,也是椭圆曲线加密的常见应用)进行数字签名和签名验证的C#程序示例,同时,也会包含密钥生成和保存的例程,需要的朋友可以参考下

基本概念

  1. RSA 通常用于加密少量数据(如对称密钥)和数字签名。直接使用RSA加密大量数据效率较低,更常见的是使用RSA加密一个随机生成的对称密钥,然后用对称密钥加密实际数据。
  2. 椭圆曲线算法 (ECC) 在相同的安全级别下,密钥长度比RSA短得多,因此在性能和存储方面有优势。它主要用于数字签名 (ECDSA)密钥协商 (ECDH),也可以进行加密(通过结合ECDH和对称加密)。
  3. 密钥保存:在实际应用中,私钥的保存至关重要。通常会使用更安全的方式,如Windows证书存储、硬件安全模块 (HSM) 或加密存储在文件中。这里提供的文件保存示例仅用于演示目的,不应直接用于生产环境。
  4. 异常处理:为了代码简洁,示例中的异常处理可能不够完善,实际应用中应加强。

RSA 算法示例

RSA算法在.NET中主要通过RSACryptoServiceProvider (旧版) 或 RSA (推荐,跨平台) 类实现。这里我们使用 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())
            {
                // 设置密钥长度 (例如,2048位)
                rsa.KeySize = 2048;

                // 导出私钥 (包含所有参数)
                string privateKeyXml = rsa.ToXmlString(true);
                File.WriteAllText(privateKeyPath, privateKeyXml);
                
                // 导出公钥 (只包含模数和指数)
                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公钥加密数据
        public static byte[] Encrypt(byte[] data, RSA publicKeyRsa)
        {
            // OEAP填充模式推荐用于加密,提供更好的安全性
            return publicKeyRsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
        }

        // 使用RSA私钥解密数据
        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. 数字签名与验证

RSA签名通常使用私钥签名,公钥验证。

using System.Security.Cryptography;
using System.Text;

public class RsaSignature
{
    // 使用RSA私钥对数据进行签名
    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 = "这是一段要进行数字签名的消息。";
        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($"签名验证结果: {(isValid ? "有效" : "无效")}");

        // 尝试篡改数据后验证签名
        Console.WriteLine("\n尝试篡改数据后验证签名...");
        byte[] tamperedMessageBytes = Encoding.UTF8.GetBytes("这是一段被篡改的消息。");
        bool isTamperedValid = VerifySignature(tamperedMessageBytes, signature, publicKey);
        Console.WriteLine($"篡改后签名验证结果: {(isTamperedValid ? "有效" : "无效")}");
    }
}

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

ECDSA在.NET中主要通过 ECDsa 类实现。

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))
        {
            // 导出私钥(PKCS#8格式,PEM编码)
            string privateKeyPem = ecdsa.ExportPkcs8PrivateKeyPem();
            File.WriteAllText(privateKeyPath, privateKeyPem);

            // 导出公钥(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. 数字签名与验证

ECDSA主要用于签名,不支持直接的加密/解密操作(需要结合ECDH和对称加密才能实现)。

using System.Security.Cryptography;
using System.Text;

public class EcdsaSignature
{
    // 使用ECDSA私钥对数据进行签名
    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进行数字签名的消息。";
        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($"签名验证结果: {(isValid ? "有效" : "无效")}");

        // 尝试篡改数据后验证签名
        Console.WriteLine("\n尝试篡改数据后验证签名...");
        byte[] tamperedMessageBytes = Encoding.UTF8.GetBytes("这是一段被篡改的消息。");
        bool isTamperedValid = VerifySignature(tamperedMessageBytes, signature, publicKey);
        Console.WriteLine($"篡改后签名验证结果: {(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 数字签名与验证
        RsaSignature.RunSignatureExample(rsaPublicKey, rsaPrivateKey);

        Console.WriteLine("\n--- ECDSA 示例 ---");

        // ECDSA 密钥生成与保存
        EcdsaHelper.GenerateAndSaveEcdsaKeys(ecdsaPrivateKeyPath, ecdsaPublicKeyPath);
        ECDsa ecdsaPublicKey = EcdsaHelper.LoadEcdsaPublicKey(ecdsaPublicKeyPath);
        ECDsa ecdsaPrivateKey = EcdsaHelper.LoadEcdsaPrivateKey(ecdsaPrivateKeyPath);

        // ECDSA 数字签名与验证
        EcdsaSignature.RunSignatureExample(ecdsaPublicKey, ecdsaPrivateKey);

        // 清理生成的密钥文件 (可选)
        // File.Delete(rsaPrivateKeyPath);
        // File.Delete(rsaPublicKeyPath);
        // File.Delete(ecdsaPrivateKeyPath);
        // File.Delete(ecdsaPublicKeyPath);

        Console.WriteLine("\n所有示例运行完毕。");
        Console.ReadKey();
    }
}

运行环境要求

  • .NET Core 3.1 或更高版本 / .NET 5.0 或更高版本RSA.Create(), ECDsa.Create(ECCurve.NamedCurves.nistP256), ExportPkcs8PrivateKeyPem(), ExportSubjectPublicKeyInfoPem(), ImportFromPem() 等方法需要较新的.NET版本支持。如果您使用的是较旧的.NET Framework,可能需要调整为 RSACryptoServiceProviderECDiffieHellmanCng/ECDsaCng,但它们的使用方式有所不同,且通常更推荐使用新的API。

关于数字证书

数字证书是公钥基础设施 (PKI) 的核心组成部分,它将公钥与实体的身份绑定在一起,并由可信的第三方(证书颁发机构 C A)进行签名。上述示例只是生成了原始的公钥和私钥文件,并没有涉及证书的生成和使用。

如果需要处理数字证书,C# 提供了 X509Certificate2 类来加载、创建和管理证书。通常涉及:

  1. 加载证书:从文件 (.pfx, .cer) 或证书存储区加载。
  2. 提取公钥:从 X509Certificate2 对象中获取 RSAECDsa 公钥。
  3. 使用私钥:如果证书包含私钥,可以直接用它进行签名或解密。

示例:

// 假设你有一个带有私钥的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#使用应用RSA和ECC进行数字签名和签名验证的示例详解的详细内容,更多关于C# RSA和ECC数字签名和签名验证的资料请关注脚本之家其它相关文章!

相关文章

  • C#中委托用法实例详解

    C#中委托用法实例详解

    这篇文章主要介绍了C#中委托用法,以实例形式较为详细的分析了C#中委托的概念与使用技巧,需要的朋友可以参考下
    2015-06-06
  • C#绘图基本方法实例总结

    C#绘图基本方法实例总结

    C#要实现简单的画图功能可以利用Graphics这个类,下面这篇文章主要给大家介绍了关于C#绘图基本方法的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • 基于C#实现屏幕桌面截图

    基于C#实现屏幕桌面截图

    这篇文章主要为大家详细介绍了如何利用C#实现屏幕桌面截图以及左上角区域截图功能,文中的示例代码讲解详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以了解一下
    2022-12-12
  • 一个读写csv文件的C#类

    一个读写csv文件的C#类

    这篇文章主要为大家详细介绍了一个读写csv文件的C#类,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • C#将dll打包到程序中的具体实现

    C#将dll打包到程序中的具体实现

    这篇文章介绍了C#将dll打包到程序中的具体实现,有需要的朋友可以参考一下
    2013-10-10
  • C# 实现绘制PDF嵌套表格案例详解

    C# 实现绘制PDF嵌套表格案例详解

    嵌套表格,顾名思义,就是在一张表格中的特定单元格中再插入一个或者多个表格,本文将为大家介绍C#绘制PDF嵌套表格的代码示例,需要的同学可以参考一下
    2021-11-11
  • C#使用ICC配置文件进行图像颜色校正的完整指南

    C#使用ICC配置文件进行图像颜色校正的完整指南

    在C#中使用ICC配置文件进行图像颜色校正,可以确保图像在不同设备(如显示器、打印机)之间保持一致的色彩表现,以下是实现这一目标的完整指南,涵盖 原理、步骤、代码示例和注意事项,需要的朋友可以参考下
    2025-07-07
  • C#利用Free Spire.XLS for .NET复制Excel工作表

    C#利用Free Spire.XLS for .NET复制Excel工作表

    在日常的 .NET 开发中,我们经常需要操作 Excel 文件,本文将详细介绍C#如何使用Free Spire.XLS for .NET 在同一工作簿内或不同工作簿之间复制工作表,有需要的可以了解下
    2025-09-09
  • C#使用Npoi导出Excel并合并行列

    C#使用Npoi导出Excel并合并行列

    这篇文章主要为大家详细介绍了C#使用Npoi导出Excel并合并行列,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • 使用 C# 下载文件的多种方法小结

    使用 C# 下载文件的多种方法小结

    本文从最简单的下载方式开始步步递进,讲述了文件下载过程中的常见问题并给出了解决方案。并展示了如何使用多线程提升 HTTP 的下载速度以及调用 aria2 实现非 HTTP 协议的文件下载,对C# 下载文件相关知识感兴趣的朋友一起看看吧
    2021-08-08

最新评论