C# RSA非对称加密、解密及格式转换
前言
本文主要介绍如何使用.Net自带API结合BouncyCastle类库实现RSA加密和解密,密钥生成和密钥格式转换。
一、RSA介绍
RSA加密算法是1977年由Ron Rivest、Adi Shamirh和Len Adleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。
RSA加密算法是一种非对称加密算法,简单来说,就是加密时使用一个钥匙,解密时使用另一个钥匙。因为加密的钥匙是公开的,所又称公钥,解密的钥匙是不公开的,所以称为私钥。
RSA是被研究得最广泛的公钥算法,从提出到现在已近二十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。
RSA的缺点主要有:
产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。
分组长度太大,为保证安全性,
n至少也要600bits以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。目前,SET(Secure Electronic Transaction)协议中要求CA采用2048bits长的密钥,其他实体使用1024bits的密钥。RSA密钥长度随着保密级别提高,增加很快。下表列出了对同一安全级别所对应的密钥长度。保密级别 对称密钥长度(bit) RSA密钥长度(bit) ECC密钥长度(bit) 保密年限 80 80 1024 160 2010 112 112 2048 224 2030 128 128 3072 256 2040 192 192 7680 384 2080 256 256 15360 512 2120
RSA的算法在这里就不赘述了,可以看看下面这张图有利于理解。

二、C#代码实现
2.1 生成公钥/私钥
struct RSASecretKey
{
public RSASecretKey(string privateKey, string publicKey)
{
PrivateKey = privateKey;
PublicKey = publicKey;
}
public string PublicKey { get; set; }
public string PrivateKey { get; set; }
public override string ToString()
{
return string.Format("PrivateKey: {0}\r\nPublicKey: {1}", PrivateKey, PublicKey);
}
}
/// <summary>
/// 生成`RSA`密钥
/// </summary>
/// <param name="keySize">密钥的大小,从384位到16384位,每8位递增 </param>
/// <returns></returns>
RSASecretKey GenerateRSASecretKey(int keySize)
{
RSASecretKey rsaKey = new RSASecretKey();
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(keySize))
{
rsaKey.PrivateKey = rsa.ToXmlString(true);
rsaKey.PublicKey = rsa.ToXmlString(false);
}
return rsaKey;
}

2.2 公钥加密/私钥解密
string RSAEncrypt(string xmlPublicKey, string content)
{
string encryptedContent = string.Empty;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(xmlPublicKey);
byte[] encryptedData = rsa.Encrypt(Encoding.Default.GetBytes(content), false);
encryptedContent = Convert.ToBase64String(encryptedData);
}
return encryptedContent;
}
string RSADecrypt(string xmlPrivateKey, string content)
{
string decryptedContent = string.Empty;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(xmlPrivateKey);
byte[] decryptedData = rsa.Decrypt(Convert.FromBase64String(content), false);
decryptedContent = Encoding.GetEncoding("gb2312").GetString(decryptedData);
}
return decryptedContent;
}


2.3 密钥格式转换
C#中RSA公钥和私钥的格式都是XML的,而在其他语言如java中,生成的RSA密钥就是普通的Base64字符串,所以需要将C# xml格式的密钥转换成普通的Base64字符串,同时也要实现Base64密钥字符串生成C# xml格式的密钥。
安装 BouncyCastle 这个Nuget包 PM > Install-Package BouncyCastle
构造一个RSAKeyConventer类
using System;
using System.Security.Cryptography;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Parameters;
namespace RSA
{
public class RSAKeyConverter
{
/// <summary>
/// 转换"私钥"格式
/// </summary>
/// <param name="xmlPrivateKey">xml格式私钥</param>
/// <returns>base64格式私钥</returns>
public static string ToBase64PrivateKey(string xmlPrivateKey)
{
string result = string.Empty;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(xmlPrivateKey);
RSAParameters param = rsa.ExportParameters(true);
RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(
new BigInteger(1, param.Modulus), new BigInteger(1, param.Exponent),
new BigInteger(1, param.D), new BigInteger(1, param.P),
new BigInteger(1, param.Q), new BigInteger(1, param.DP),
new BigInteger(1, param.DQ), new BigInteger(1, param.InverseQ));
PrivateKeyInfo privateKey = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
result = Convert.ToBase64String(privateKey.ToAsn1Object().GetEncoded());
}
return result;
}
/// <summary>
/// 转换"公钥"格式
/// </summary>
/// <param name="xmlPublicKey">xml格式公钥</param>
/// <returns>base64格式公钥</returns>
public static string ToBase64PublicKey(string xmlPublicKey)
{
string result = string.Empty;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(xmlPublicKey);
RSAParameters p = rsa.ExportParameters(false);
RsaKeyParameters keyParams = new RsaKeyParameters(
false, new BigInteger(1, p.Modulus), new BigInteger(1, p.Exponent));
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyParams);
result = Convert.ToBase64String(publicKeyInfo.ToAsn1Object().GetEncoded());
}
return result;
}
/// <summary>
/// 转换"私钥"格式
/// </summary>
/// <param name="privateKey">base64格式私钥</param>
/// <returns>xml格式私钥</returns>
public static string ToXmlPrivateKey(string privateKey)
{
RsaPrivateCrtKeyParameters privateKeyParams =
PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey)) as RsaPrivateCrtKeyParameters;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
RSAParameters rsaParams = new RSAParameters()
{
Modulus = privateKeyParams.Modulus.ToByteArrayUnsigned(),
Exponent = privateKeyParams.PublicExponent.ToByteArrayUnsigned(),
D = privateKeyParams.Exponent.ToByteArrayUnsigned(),
DP = privateKeyParams.DP.ToByteArrayUnsigned(),
DQ = privateKeyParams.DQ.ToByteArrayUnsigned(),
P = privateKeyParams.P.ToByteArrayUnsigned(),
Q = privateKeyParams.Q.ToByteArrayUnsigned(),
InverseQ = privateKeyParams.QInv.ToByteArrayUnsigned()
};
rsa.ImportParameters(rsaParams);
return rsa.ToXmlString(true);
}
}
/// <summary>
/// 转换"公钥"格式
/// </summary>
/// <param name="pubilcKey">base64格式公钥</param>
/// <returns>xml格式公钥</returns>
public static string ToXmlPublicKey(string pubilcKey)
{
RsaKeyParameters p =
PublicKeyFactory.CreateKey(Convert.FromBase64String(pubilcKey)) as RsaKeyParameters;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
RSAParameters rsaParams = new RSAParameters
{
Modulus = p.Modulus.ToByteArrayUnsigned(),
Exponent = p.Exponent.ToByteArrayUnsigned()
};
rsa.ImportParameters(rsaParams);
return rsa.ToXmlString(false);
}
}
}
}
C# RSA非对称加密、解密及格式转换的更多相关文章
- CryptoAPI与openssl RSA非对称加密解密(PKCS1 PADDING)交互
(以下代码中都只做测试用,有些地方没有释放内存...这个自己解决下) 1.RSA非对称的,首先提供一个供测试用的证书和私钥的数据 1)pem格式的证书和私钥(公私钥是对应的)的base64编码 voi ...
- javascript版前端页面RSA非对称加密解密
最近由于项目需要做一个url传参,并在页面显示参数内容的需求,这样就会遇到一个url地址可能会被假冒, 并传递非法内容显示在页面的尴尬情况 比如xxx.shtml?server=xxx是坏人& ...
- ios php RSA 非对称加密解密 der 和pem生成
ios 使用public_key.der加密 php 使用 private_key.pem解密 openssl req -x509 -out public_key.der -outform der - ...
- Java对称与非对称加密解密,AES与RSA
加密技术可以分为对称与非对称两种. 对称加密,解密,即加密与解密用的是同一把秘钥,常用的对称加密技术有DES,AES等 而非对称技术,加密与解密用的是不同的秘钥,常用的非对称加密技术有RSA等 为什么 ...
- 使用java实现对称加密解密(AES),非对称加密解密(RSA)
对称加密:双方采用同样的秘钥进行加密和解密.特点是速度快,但是安全性没有非对称加密高 非对称加密:接收方生成的公有秘钥公布给发送方,发送方使用该公有秘钥加密之后,发送给接收方,然后接收方使用私有秘钥解 ...
- php 非对称加密解密类
<?phpnamespace app\Parentclient\model;header("Content-Type: text/html;charset=utf-8");/ ...
- RSA 非对称加密,私钥转码为pkcs8 错误总结
RSA 非对称加密,私钥转码为pkcs8 错误总结 最近在和某上市公司对接金融方面的业务时,关于RSA对接过程中遇到了一个坑,特来分享下解决方案. 该上市公司简称为A公司,我们简称为B公司.A-B两家 ...
- RSA的密钥把JAVA格式转换成C#的格式(2)
把C#格式转换成Java:RSA的密钥把JAVA格式转换成C#的格式(1) 我已经在第一篇介绍过如何把C#格式转换成Java,现在来看看如何把Java格式转换成C#. /// <summary& ...
- php rsa 非对称加解密类
<?php header("Content-Type: text/html;charset=utf-8"); /* 生成公钥.私钥对,私钥加密的内容能通过公钥解密(反过来亦可 ...
- Atitit RSA非对称加密原理与解决方案
Atitit RSA非对称加密原理与解决方案 1.1. 一.一点历史 1 1.2. 八.加密和解密 2 1.3. 二.基于RSA的消息传递机制 3 1.4. 基于rsa的授权验证机器码 4 1.5. ...
随机推荐
- jquery 给表格添加或删除一行
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- exception EXC_RESOURCE - WAKEUPS 分析(二)
一.问题: 直播助手在使用ReplayKit2 Extension的过程中,ReplayKit2的Upload进程工作在后台模式,苹果对处于后台的进程进行了内存和CPU资源的限制. 对于内存: 每种E ...
- CF1626E
problem 我们可以考虑什么情况下这个点一定可以到黑点. \(c_i = 1\). \(c_{son} = 1\). 儿子可以,并且儿子子树内有两个黑点 请两个不必多说,看最后一个. 假如说考虑他 ...
- windows 命令行调整分辨率
windows 命令行调整分辨率 下载:qres_v1.1 https://abcker.lanzouq.com/i1uzA1a5uo8j 解压出来,如:D:\Soft\QRes,不要使用中文名目录. ...
- Ubuntu安装VMware tools后不起作用
复制和立即适应客户机不起作用. 解决: 1)不需要卸载 2)命令行执行sudo apt-get install open-vm-tools-desktop 3)可能会提示apt-get update或 ...
- SpringBoot启动报错:Parameter 0 of method hmset in com.qcby.rbac.util.RedisUtils required a bean of type
SpringBoot启动报错,报错信息如下: 报错是由于A类中定义了含参数的构造函数,Spring自动构造和注入时未为该Bean传入参数,引起报错. 查了很多资料,最后发现,我是因为注释的时候没有把@ ...
- vue排行榜 加单位
- NumPy 差分、最小公倍数、最大公约数、三角函数详解
NumPy 差分 离散差分意味着相邻元素之间的减法. 例如,对于 [1, 2, 3, 4],离散差分将是 [2-1, 3-2, 4-3] = [1, 1, 1] 要找到离散差分,使用 diff() 函 ...
- Python 导入包失败,提示“most likely due to a circular import”
详细报错信息如下: ImportError: cannot import name 'DoReplace' from partially initialized module 'common.do_r ...
- 【资料分享】Xilinx Zynq-7010/7020工业核心板规格书(双核ARM Cortex-A9 + FPGA,主频766MHz)
1 核心板简介 创龙科技SOM-TLZ7x是一款基于Xilinx Zynq-7000系列XC7Z010/XC7Z020高性能低功耗处理器设计的异构多核SoC工业核心板,处理器集成PS端双核ARM Co ...