基本概念
- rsa 通常用于加密少量数据(如对称密钥)和数字签名。直接使用rsa加密大量数据效率较低,更常见的是使用rsa加密一个随机生成的对称密钥,然后用对称密钥加密实际数据。
- 椭圆曲线算法 (ecc) 在相同的安全级别下,密钥长度比rsa短得多,因此在性能和存储方面有优势。它主要用于数字签名 (ecdsa) 和密钥协商 (ecdh),也可以进行加密(通过结合ecdh和对称加密)。
- 密钥保存:在实际应用中,私钥的保存至关重要。通常会使用更安全的方式,如windows证书存储、硬件安全模块 (hsm) 或加密存储在文件中。这里提供的文件保存示例仅用于演示目的,不应直接用于生产环境。
- 异常处理:为了代码简洁,示例中的异常处理可能不够完善,实际应用中应加强。
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,可能需要调整为rsacryptoserviceprovider
和ecdiffiehellmancng
/ecdsacng
,但它们的使用方式有所不同,且通常更推荐使用新的api。
关于数字证书
数字证书是公钥基础设施 (pki) 的核心组成部分,它将公钥与实体的身份绑定在一起,并由可信的第三方(证书颁发机构 c a)进行签名。上述示例只是生成了原始的公钥和私钥文件,并没有涉及证书的生成和使用。
如果需要处理数字证书,c# 提供了 x509certificate2
类来加载、创建和管理证书。通常涉及:
- 加载证书:从文件 (
.pfx
,.cer
) 或证书存储区加载。 - 提取公钥:从
x509certificate2
对象中获取rsa
或ecdsa
公钥。 - 使用私钥:如果证书包含私钥,可以直接用它进行签名或解密。
示例:
// 假设你有一个带有私钥的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数字签名和签名验证的资料请关注代码网其它相关文章!
发表评论