RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。 RSA是被研究得最广泛的公钥算法,从提出到现在已近二十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价。
.NET提供常用的加密算法类,支持RSA的类是RSACryptoServiceProvider(命名空间:System.Security.Cryptography),但只支持公钥加密,私钥解密。RSACryptoServiceProvider类包括:Modulus、Exponent、P、Q、DP、DQ、InverseQ、D等8个属性,其中Modulus和Exponent就是公钥,Modulus和D就是私钥,RSACryptoServiceProvider类提供导出公钥的方法,也提供导出私钥的方法,但导出的私钥包含上面8个属性,显然要用RSACryptoServiceProvider实现私钥加密公钥是不可行的。
从RSA的原理来看,公钥加密私钥解密和私钥加密公钥解密应该是等价的,在某些情况下,比如共享软件加密,我们需要用私钥加密注册码或注册文件,发给用户,用户用公钥解密注册码或注册文件进行合法性验证。
.NET Framework 为不对称加密提供了 RSACryptoServiceProvider 和 DSACryptoServiceProvider 类。这些类在您使用默认构造函数创建新实例时创建一个公钥/私钥对。既可以存储不对称密钥以用在多个会话中,也可以只为一个会话生成不对称密钥。公钥可以被广泛地使用,私钥应被严密地保护起来。
每当创建不对称算法类的新实例时,都生成一个公钥/私钥对。创建该类的新实例后,可以用以下两种方法之一提取密钥信息:
ToXMLString 方法,它返回密钥信息的 XML 表示形式。导出密钥--xml形式的字符串
对应的方法:FromXmlString通过 XML 字符串中的密钥信息初始化RSA 对象。 导入密钥
ExportParameters 方法,它返回RSAParameters 结构以保存密钥信息。导出密钥--参数形式
两个方法都接受布尔值,该值指示是只返回公钥信息还是同时返回公钥和私钥信息。通过使用 ImportParameters 方法,可以将 RSACryptoServiceProvider 类初始化为 RSAParameters 结构的值。
下面的代码示例创建 RSACryptoServiceProvider 类的一个新实例,创建一个公钥/私钥对,并将公钥信息保存在RSAParameters 结构中
//Generate a public/private key pair.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Save the public key information to an RSAParameters structure.
RSAParameters RSAKeyInfo = RSA.ExportParameters(false);
///
/// 公钥加密,私钥解密
///
public class RSAEncryptHelper
{
///
/// 将字符串使用base64算法加密
///
/// 编码类型
/// 待加密的字符串
/// 加密后的字符串
public string EncodeBase64(string code_type, string code)
{
string encode = "";
byte[] bytes = Encoding.GetEncoding(code_type).GetBytes(code); //将一组字符编码为一个字节序列.
try
{
encode = Convert.ToBase64String(bytes); //将8位无符号整数数组的子集转换为其等效的,以64为基的数字编码的字符串形式.
}
catch
{
encode = code;
}
return encode;
}
///
/// 将字符串使用base64算法解密
///
/// 编码类型
/// 已用base64算法加密的字符串
/// 解密后的字符串
public string DecodeBase64(string code_type, string code)
{
string decode = "";
byte[] bytes = Convert.FromBase64String(code); //将2进制编码转换为8位无符号整数数组.
try
{
decode = Encoding.GetEncoding(code_type).GetString(bytes); //将指定字节数组中的一个字节序列解码为一个字符串。
}
catch
{
decode = code;
}
return decode;
}
///
/// 获取本机的MAC地址
///
///
public static string GetLocalMac()
{
string mac = null;
ManagementObjectSearcher query = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration");
ManagementObjectCollection queryCollection = query.Get();
foreach (ManagementObject mo in queryCollection)
{
if (mo["IPEnabled"].ToString() == "True")
mac = mo["MacAddress"].ToString();
}
return (mac);
}
///
/// 得到CPU序列号
///
///
public static string GetCpuID()
{
try
{
//获取CPU序列号代码
string cpuInfo = "";//cpu序列号
ManagementClass mc = new ManagementClass("Win32_Processor");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
cpuInfo = mo.Properties["ProcessorId"].Value.ToString();
}
moc = null;
mc = null;
return cpuInfo;
}
catch
{
return "unknow";
}
finally
{
}
}
///
/// 生成公私钥
///
///
///
public void RSAKey(string PrivateKeyPath, string PublicKeyPath)
{
try
{
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
this.CreatePrivateKeyXML(PrivateKeyPath, provider.ToXmlString(true));
this.CreatePublicKeyXML(PublicKeyPath, provider.ToXmlString(false));
}
catch (Exception exception)
{
throw exception;
}
}
///
/// 对原始数据进行MD5加密
///
/// 待加密数据
/// 返回机密后的数据
public string GetHash(string m_strSource)
{
HashAlgorithm algorithm = HashAlgorithm.Create("MD5");
byte[] bytes = Encoding.GetEncoding("GB2312").GetBytes(m_strSource);
byte[] inArray = algorithm.ComputeHash(bytes);
return Convert.ToBase64String(inArray);
}
///
/// RSA加密
///
/// 公钥
/// MD5加密后的数据
/// RSA公钥加密后的数据
public string RSAEncrypt(string xmlPublicKey, string m_strEncryptString)
{
string str2;
try
{
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
provider.FromXmlString(xmlPublicKey);
byte[] bytes = new UnicodeEncoding().GetBytes(m_strEncryptString);
str2 = Convert.ToBase64String(provider.Encrypt(bytes, false));
}
catch (Exception exception)
{
throw exception;
}
return str2;
}
///
/// RSA解密
///
/// 私钥
/// 待解密的数据
/// 解密后的结果
public string RSADecrypt(string xmlPrivateKey, string m_strDecryptString)
{
string str2;
try
{
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
provider.FromXmlString(xmlPrivateKey);
byte[] rgb = Convert.FromBase64String(m_strDecryptString);
byte[] buffer2 = provider.Decrypt(rgb, false);
str2 = new UnicodeEncoding().GetString(buffer2);
}
catch (Exception exception)
{
throw exception;
}
return str2;
}
///
/// 对MD5加密后的密文进行签名
///
/// 私钥
/// MD5加密后的密文
///
public string SignatureFormatter(string p_strKeyPrivate, string m_strHashbyteSignature)
{
byte[] rgbHash = Convert.FromBase64String(m_strHashbyteSignature);
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.FromXmlString(p_strKeyPrivate);
RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter(key);
formatter.SetHashAlgorithm("MD5");
byte[] inArray = formatter.CreateSignature(rgbHash);
return Convert.ToBase64String(inArray);
}
///
/// 签名验证
///
/// 公钥
/// 待验证的用户名
/// 注册码
///
public bool SignatureDeformatter(string p_strKeyPublic, string p_strHashbyteDeformatter, string p_strDeformatterData)
{
try
{
byte[] rgbHash = Convert.FromBase64String(p_strHashbyteDeformatter);
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.FromXmlString(p_strKeyPublic);
RSAPKCS1SignatureDeformatter deformatter = new RSAPKCS1SignatureDeformatter(key);
deformatter.SetHashAlgorithm("MD5");
byte[] rgbSignature = Convert.FromBase64String(p_strDeformatterData);
if (deformatter.VerifySignature(rgbHash, rgbSignature))
{
return true;
}
return false;
}
catch
{
return false;
}
}
///
/// 获取硬盘ID
///
/// 硬盘ID
public string GetHardID()
{
string HDInfo = "";
ManagementClass cimobject1 = new ManagementClass("Win32_DiskDrive");
ManagementObjectCollection moc1 = cimobject1.GetInstances();
foreach (ManagementObject mo in moc1)
{
HDInfo = (string)mo.Properties["Model"].Value;
}
return HDInfo;
}
///
/// 读注册表中指定键的值
///
/// 键名
/// 返回键值
private string ReadReg(string key)
{
string temp = "";
try
{
RegistryKey myKey = Registry.LocalMachine;
RegistryKey subKey = myKey.OpenSubKey(@"SOFTWARE/JX/Register");
temp = subKey.GetValue(key).ToString();
subKey.Close();
myKey.Close();
return temp;
}
catch (Exception)
{
throw;//可能没有此注册项;
}
}
///
/// 创建注册表中指定的键和值
///
/// 键名
/// 键值
private void WriteReg(string key, string value)
{
try
{
RegistryKey rootKey = Registry.LocalMachine.CreateSubKey(@"SOFTWARE/JX/Register");
rootKey.SetValue(key, value);
rootKey.Close();
}
catch (Exception)
{
throw;
}
}
///
/// 创建公钥文件
///
///
///
public void CreatePublicKeyXML(string path, string publickey)
{
try
{
FileStream publickeyxml = new FileStream(path, FileMode.Create);
StreamWriter sw = new StreamWriter(publickeyxml);
sw.WriteLine(publickey);
sw.Close();
publickeyxml.Close();
}
catch
{
throw;
}
}
///
/// 创建私钥文件
///
///
///
public void CreatePrivateKeyXML(string path, string privatekey)
{
try
{
FileStream privatekeyxml = new FileStream(path, FileMode.Create);
StreamWriter sw = new StreamWriter(privatekeyxml);
sw.WriteLine(privatekey);
sw.Close();
privatekeyxml.Close();
}
catch
{
throw;
}
}
///
/// 读取公钥
///
///
///
public string ReadPublicKey(string path)
{
StreamReader reader = new StreamReader(path);
string publickey = reader.ReadToEnd();
reader.Close();
return publickey;
}
///
/// 读取私钥
///
///
///
public string ReadPrivateKey(string path)
{
StreamReader reader = new StreamReader(path);
string privatekey = reader.ReadToEnd();
reader.Close();
return privatekey;
}
///
/// 初始化注册表,程序运行时调用,在调用之前更新公钥xml
///
/// 公钥路径
public void InitialReg(string path)
{
Registry.LocalMachine.CreateSubKey(@"SOFTWARE/JX/Register");
Random ra = new Random();
string publickey = this.ReadPublicKey(path);
if (Registry.LocalMachine.OpenSubKey(@"SOFTWARE/JX/Register").ValueCount <= 0)
{
this.WriteReg("RegisterRandom", ra.Next(1, 100000).ToString());
this.WriteReg("RegisterPublicKey", publickey);
}
else
{
this.WriteReg("RegisterPublicKey", publickey);
}
}
}
二、私钥加密公钥解密
///
/// 非对称RSA加密类 可以参考
/// http://www.cnblogs.com/hhh/archive/2011/06/03/2070692.html
/// http://blog.csdn.net/zhilunchen/article/details/2943158
/// http://www.cnblogs.com/yyl8781697/archive/2013/04/28/RSA.html
/// 若是私匙加密 则需公钥解密
/// 反正公钥加密 私匙来解密
/// 需要BigInteger类来辅助
///
public static class RSAHelper
{
///
/// RSA的容器 可以解密的源字符串长度为 DWKEYSIZE/8-11
///
public const int DWKEYSIZE = 1024;
///
/// RSA加密的密匙结构 公钥和私匙
///
//public struct RSAKey
//{
// public string PublicKey { get; set; }
// public string PrivateKey { get; set; }
//}
#region 得到RSA的解谜的密匙对
///
/// 得到RSA的解谜的密匙对
///
///
//public static RSAKey GetRASKey()
//{
// RSACryptoServiceProvider.UseMachineKeyStore = true;
// //声明一个指定大小的RSA容器
// RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(DWKEYSIZE);
// //取得RSA容易里的各种参数
// RSAParameters p = rsaProvider.ExportParameters(true);
// return new RSAKey()
// {
// PublicKey = ComponentKey(p.Exponent, p.Modulus),
// PrivateKey = ComponentKey(p.D, p.Modulus)
// };
//}
#endregion
#region 检查明文的有效性 DWKEYSIZE/8-11 长度之内为有效 中英文都算一个字符
///
/// 检查明文的有效性 DWKEYSIZE/8-11 长度之内为有效 中英文都算一个字符
///
///
///
public static bool CheckSourceValidate(string source)
{
return (DWKEYSIZE / 8 - 11) >= source.Length;
}
#endregion
#region 组合解析密匙
///
/// 组合成密匙字符串
///
///
///
///
public static string ComponentKey(byte[] b1, byte[] b2)
{
List list = new List();
//在前端加上第一个数组的长度值 这样今后可以根据这个值分别取出来两个数组
list.Add((byte)b1.Length);
list.AddRange(b1);
list.AddRange(b2);
byte[] b = list.ToArray();
return Convert.ToBase64String(b);
}
///
/// 解析密匙
///
/// 密匙
/// RSA的相应参数1
/// RSA的相应参数2
private static void ResolveKey(string key, out byte[] b1, out byte[] b2)
{
//从base64字符串 解析成原来的字节数组
byte[] b = Convert.FromBase64String(key);
//初始化参数的数组长度
b1 = new byte[b[0]];
b2 = new byte[b.Length - b[0] - 1];
//将相应位置是值放进相应的数组
for (int n = 1, i = 0, j = 0; n < b.Length; n++)
{
if (n <= b[0])
{
b1[i++] = b[n];
}
else
{
b2[j++] = b[n];
}
}
}
#endregion
#region 字符串加密解密 公开方法
///
/// 字符串加密
///
/// 源字符串 明文
/// 密匙
/// 加密遇到错误将会返回原字符串
public static string EncryptString(string source, string key)
{
string encryptString = string.Empty;
byte[] d;
byte[] n;
try
{
if (!CheckSourceValidate(source))
{
throw new Exception("source string too long");
}
//解析这个密钥
ResolveKey(key, out d, out n);
BigInteger biN = new BigInteger(n);
BigInteger biD = new BigInteger(d);
encryptString = EncryptString(source, biD, biN);
}
catch
{
encryptString = source;
}
return encryptString;
}
///
/// 字符串解密
///
/// 密文
/// 密钥
/// 遇到解密失败将会返回空字符串
public static string DecryptString(string encryptString, string key)
{
string source = string.Empty;
byte[] e;
byte[] n;
try
{
//解析这个密钥
ResolveKey(key, out e, out n);
BigInteger biE = new BigInteger(e);
BigInteger biN = new BigInteger(n);
source = DecryptString(encryptString, biE, biN);
}
catch
{
}
return source;
}
#endregion
#region 字符串加密解密 私有 实现加解密的实现方法
///
/// 用指定的密匙加密
///
/// 明文
/// 可以是RSACryptoServiceProvider生成的D
/// 可以是RSACryptoServiceProvider生成的Modulus
/// 返回密文
private static string EncryptString(string source, BigInteger d, BigInteger n)
{
int len = source.Length;
int len1 = 0;
int blockLen = 0;
if ((len % 128) == 0)
len1 = len / 128;
else
len1 = len / 128 + 1;
string block = "";
StringBuilder result = new StringBuilder();
for (int i = 0; i < len1; i++)
{
if (len >= 128)
blockLen = 128;
else
blockLen = len;
block = source.Substring(i * 128, blockLen);
byte[] oText = System.Text.Encoding.Default.GetBytes(block);
BigInteger biText = new BigInteger(oText);
BigInteger biEnText = biText.modPow(d, n);
string temp = biEnText.ToHexString();
result.Append(temp).Append("@");
len -= blockLen;
}
return result.ToString().TrimEnd('@');
}
///
/// 用指定的密匙加密
///
/// 密文
/// 可以是RSACryptoServiceProvider生成的Exponent
/// 可以是RSACryptoServiceProvider生成的Modulus
/// 返回明文
private static string DecryptString(string encryptString, BigInteger e, BigInteger n)
{
StringBuilder result = new StringBuilder();
string[] strarr1 = encryptString.Split(new char[] { '@' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < strarr1.Length; i++)
{
string block = strarr1[i];
BigInteger biText = new BigInteger(block, 16);
BigInteger biEnText = biText.modPow(e, n);
string temp = System.Text.Encoding.Default.GetString(biEnText.getBytes());
result.Append(temp);
}
return result.ToString();
}
#endregion
///
/// 将字符串使用base64算法加密
///
/// 编码类型
/// 待加密的字符串
/// 加密后的字符串
public static string EncodeBase64(string code_type, string code)
{
string encode = "";
byte[] bytes = Encoding.GetEncoding(code_type).GetBytes(code); //将一组字符编码为一个字节序列.
try
{
encode = Convert.ToBase64String(bytes); //将8位无符号整数数组的子集转换为其等效的,以64为基的数字编码的字符串形式.
}
catch
{
encode = code;
}
return encode;
}
///
/// 将字符串使用base64算法解密
///
/// 编码类型
/// 已用base64算法加密的字符串
/// 解密后的字符串
public static string DecodeBase64(string code_type, string code)
{
string decode = "";
byte[] bytes = Convert.FromBase64String(code); //将2进制编码转换为8位无符号整数数组.
try
{
decode = Encoding.GetEncoding(code_type).GetString(bytes); //将指定字节数组中的一个字节序列解码为一个字符串。
}
catch
{
decode = code;
}
return decode;
}
///
/// 读取公钥或私钥
///
/// 为True则包含私钥
/// Xml格式保存的完整公/私钥路径
/// 公钥或私钥参数形式
public static RSAParameters ReadKey(bool includePrivateparameters,string path)
{
using (StreamReader reader = new StreamReader(path))
{
string publickey = reader.ReadToEnd();
RSACryptoServiceProvider rcp = new RSACryptoServiceProvider();
rcp.FromXmlString(publickey);
return rcp.ExportParameters(includePrivateparameters);
}
}
///
/// 获取本机的MAC地址
///
///
public static string GetLocalMac()
{
string mac = null;
ManagementObjectSearcher query = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration");
ManagementObjectCollection queryCollection = query.Get();
foreach (ManagementObject mo in queryCollection)
{
if (mo["IPEnabled"].ToString() == "True")
mac = mo["MacAddress"].ToString();
}
return (mac);
}
///
/// 得到CPU序列号
///
///
public static string GetCpuID()
{
try
{
//获取CPU序列号代码
string cpuInfo = "";//cpu序列号
ManagementClass mc = new ManagementClass("Win32_Processor");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
cpuInfo = mo.Properties["ProcessorId"].Value.ToString();
}
moc = null;
mc = null;
return cpuInfo;
}
catch
{
return "unknow";
}
finally
{
}
}
///
/// 获取硬盘ID
///
/// 硬盘ID
public static string GetHardID()
{
string HDInfo = "";
ManagementClass cimobject1 = new ManagementClass("Win32_DiskDrive");
ManagementObjectCollection moc1 = cimobject1.GetInstances();
foreach (ManagementObject mo in moc1)
{
HDInfo = (string)mo.Properties["Model"].Value;
}
return HDInfo;
}
///
/// 读注册表中指定键的值
///
/// 键名
/// 返回键值
private static string ReadReg(string key)
{
string temp = "";
try
{
RegistryKey myKey = Registry.LocalMachine;
RegistryKey subKey = myKey.OpenSubKey(@"SOFTWARE/JX/Register");
temp = subKey.GetValue(key).ToString();
subKey.Close();
myKey.Close();
return temp;
}
catch (Exception)
{
throw;//可能没有此注册项;
}
}
///
/// 创建注册表中指定的键和值
///
/// 键名
/// 键值
private static void WriteReg(string key, string value)
{
try
{
RegistryKey rootKey = Registry.LocalMachine.CreateSubKey(@"SOFTWARE/JX/Register");
rootKey.SetValue(key, value);
rootKey.Close();
}
catch (Exception)
{
throw;
}
}
}
使用场景:如共享软件加密,我们需要用私钥加密注册码或注册文件,发给用户,用户用公钥解密注册码或注册文件进行合法性验证。
RSA算法实现激活码注册方式的原理如下:
1. 生成一对公钥E和私钥D(供软件注册模板和注册机使用);
2. 用户安装软件后,软件注册模板提取用户机器指纹信息(如:MAC地址、CPU序列号、硬盘序列号等),并通过其它的编码算法(如BASE64)生成一个申请码C;
3. 用户将申请码C发给软件开发商。软件开发商通过注册机采用私钥D加密申请码C后生成激活码F。软件供应商将激活码F发给用户。
4. 用户输入激活码F,软件注册模板采用公钥E对激活码F解码后生成G(即:用户机器特征信息),然后软件注册模板提取用户机器的特定信息后进行编码。将编码的结果与G进行比较,如果相等则用户合法,完成授权,否则授权失败。
//应用程序注册模块
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string cpu = RSAHelper.GetCpuID();
string _申请码C = RSAHelper.EncodeBase64("utf-8", cpu);
textEdit申请码.Text = _申请码C;
}
private void simpleButton注册_Click(object sender, EventArgs e)
{
string publicKeyPath = @"C://PublicKey.xml";
RSAParameters pm = RSAHelper.ReadKey(false, publicKeyPath);
string _PublicKey = RSAHelper.ComponentKey(pm.Exponent, pm.Modulus);
string cpu = RSAHelper.DecryptString(textEdit激活码.Text, _PublicKey);
if (cpu == textEdit申请码.Text)
{
MessageBox.Show("注册成功");
}
else
{
MessageBox.Show("注册失败");
}
}
}
///
/// 注册机
///
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void simpleButton生成激活码_Click(object sender, EventArgs e)
{
string privateKeyPath = @"C://PrivateKey.xml";
RSAParameters pm = RSAHelper.ReadKey(true, privateKeyPath);
string _PrivateKey = RSAHelper.ComponentKey(pm.D, pm.Modulus);
textEdit激活码.Text = RSAHelper.EncryptString(textEdit申请码.Text, _PrivateKey);
}
}