当前位置: 代码网 > it编程>编程语言>Asp.net > C#使用应用RSA和ECC进行数字签名和签名验证的示例详解

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

2025年09月29日 Asp.net 我要评论
基本概念rsa 通常用于加密少量数据(如对称密钥)和数字签名。直接使用rsa加密大量数据效率较低,更常见的是使用rsa加密一个随机生成的对称密钥,然后用对称密钥加密实际数据。椭圆曲线算法 (ecc)

基本概念

  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数字签名和签名验证的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com