基本概念
- 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数字签名和签名验证的资料请关注代码网其它相关文章!
发表评论