📄 simplersaprovider.cs
字号:
using System;
using System.Security.Cryptography;
#region 版权声明
///
/// 版权所有(C)2005,2006 作者:漆巧林。保留所有权利, davidqql@gmail.com, davidqql@hotmail.com
///
/// 作者不对本代码提供任何保证,因此,对于使用该代码带来的损害或者潜在的损害,作者不承担责任。
/// 在满足如下的条件下,你可以自由使用该代码:
/// 1. 非商业应用
/// 2. 保留本版权声明
/// 要进行商业应用,必须得到作者的书面许可。
/// 你可以修改和自由发布本代码,条件是保留前述的版权声明。
///
#endregion
namespace BizSecurity
{
/// <summary>
/// SimpleRSAProvider:简单实现的RSA类
/// </summary>
/// <remarks>有关RSA加密之类的信息请参看RFC2437</remarks>
public class SimpleRSAProvider
{
private UBigInteger exponent; // a prime(一个素数)
private UBigInteger modulus; // modulus = p * q
private UBigInteger d; // exponent * d % ((p - 1) * (q - 1)) = 1
private UBigInteger p; // prime
private UBigInteger q; // prime
private UBigInteger dp; // e * dp % (p - 1) = 1
private UBigInteger dq; // e * dq % (q - 1) = 1
private UBigInteger qInv; // q * qInv % p = 1
private int keySize;
/// <summary>
/// 默认构造512位密钥
/// </summary>
public SimpleRSAProvider()
:this(512)
{
}
public SimpleRSAProvider(UBigInteger modulus, UBigInteger exponent)
{
this.modulus = modulus;
this.exponent = exponent;
}
/// <summary>
/// 使用指定的密钥大小初始化新实例,使用.NET的RSACryptoServiceProvider
/// 创建P和Q,Exponent自动获取随机素数
/// </summary>
/// <param name="keySize">密钥大小,以位为单位</param>
public SimpleRSAProvider(int keySize)
{
InitializeByCryptoServiceProvider(keySize);
}
private void InitializeByCryptoServiceProvider(int keySize)
{
this.keySize = keySize;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(keySize);
RSAParameters param = rsa.ExportParameters(true);
p = UBigInteger.Parse(param.P);
q = UBigInteger.Parse(param.Q);
ConstructByPQ();
}
private void ConstructByPQ()
{
modulus = p * q;
exponent = p.SmallerRandomPrime(); // Let the exponent < p
UBigInteger leastP = p - 1;
UBigInteger leastQ = q - 1;
d = UBigInteger.Euclidean(exponent, leastP * leastQ);
dp = UBigInteger.Euclidean(exponent, leastP);
dq = UBigInteger.Euclidean(exponent, leastQ);
qInv = UBigInteger.Euclidean(q, p);
}
/// <summary>
/// 指示是否按内建CSP構造RSA
/// </summary>
/// <param name="fNative">指示是否使用系統内建的CSP,若為真,使用CSP,否則使用UBigInteger大數</param>
/// <param name="keySize">密鈅大小,以Bit(位)為單位</param>
public SimpleRSAProvider(bool fNative, int keySize)
{
if(fNative)
{
this.InitializeByCryptoServiceProvider(keySize);
}
else
{
p = UBigInteger.RandomPrime(keySize / 32 / 2);
q = UBigInteger.RandomPrime(keySize / 32 / 2);
ConstructByPQ();
}
}
/// <summary>
/// 导入RSA参数
/// </summary>
/// <param name="param">要导入的参数,其允许情况如下:
/// 1. 包含Modulus and Exponent
/// 2. 包含Modulus and d
/// 3. 包含p, q, dp, dq, InversQ
/// 4. 全部参数
/// 5. p, q, 和/或exponent,如果实例的exponent未定义且没有导入exponent,将出现异常
/// 6. exponent,如果实例的p, q未定义,将引发异常
/// </param>
public void ImportParameters(RSAParameters param)
{
// Condition allowed:
// 1. Modulus and Exmponent
// 2. Modulus and d
// 3. p, q, dp, dq, qInv
// 4. all the fields
// 5. p, q, exponent
if(param.D != null && param.P != null && param.Q != null && param.DP != null
&& param.DQ != null && param.InverseQ != null && param.Exponent != null && param.Modulus != null)
{
// validate the data imported
ImportFullParameters(param);
}
else if(param.P != null && param.Q != null && param.DP != null && param.DQ != null && param.InverseQ != null
&& param.Exponent == null && param.Modulus == null && param.D == null)
{
ImportFullPrivateParameters(param);
}
else if(param.Modulus != null)
{
ImportModulusParameter(param);
}
else if(param.P != null && param.Q != null)
{
ImportPQParameter(param);
}
else if(param.Exponent != null)
{
ImportExponentOnly(param);
}
else
{
throw new CryptographicException("Parameter error");
}
}
/// <summary>
/// 导出密钥参数
/// </summary>
/// <param name="includedPrivateParameters">如果为真,私钥参数也会导出</param>
/// <returns>返回RSA的参数</returns>
public RSAParameters ExportParameters(bool includedPrivateParameters)
{
RSAParameters param = new RSAParameters();
if(exponent != null)
param.Exponent = exponent.ToByteArray();
if(modulus != null)
param.Modulus = modulus.ToByteArray();
if(includedPrivateParameters)
{
if(p != null) param.P = p.ToByteArray();
if(q != null) param.Q = q.ToByteArray();
if(d != null) param.D = d.ToByteArray();
if(dp != null) param.DP = dp.ToByteArray();
if(dq != null) param.DQ = dq.ToByteArray();
if(qInv != null) param.InverseQ = qInv.ToByteArray();
}
return param;
}
/// <summary>
/// 使用私钥进行解密
/// </summary>
/// <param name="rgb">密文</param>
/// <returns>如果解密成功返回明文</returns>
public byte[] Decrypt(byte[] rgb)
{
UBigInteger cipher = UBigInteger.Parse(rgb);
if(d != null && modulus != null)
{
if(cipher >= modulus)
throw new CryptographicException("The data rgb is invalid, it should be less than modulus!");
cipher.RSATranslate(d, modulus);
return cipher.ToByteArray();
}
else if(p != null && q != null && dp != null && dq != null)
{
// TO this method, it can only handle the condition that m1 > m2
if(qInv == null)
qInv = UBigInteger.Euclidean(q, p);
UBigInteger m1 = UBigInteger.RSATranslate(cipher, dp, p);
UBigInteger m2 = UBigInteger.RSATranslate(cipher, dq, q);
m1.Subtraction(m2);
UBigInteger h = qInv * m1 % p;
m2.Addition(h);
return m2.ToByteArray();
}
else
{
throw new CryptographicException("There's no private key, can not decrypt!");
}
}
// /// <summary>
// /// 使用私钥进行解密
// /// </summary>
// /// <param name="rgb">密文</param>
// /// <returns>如果解密成功返回明文</returns>
// public string Decrypt(string rgb)
// {
// byte[] decrypt = UBigInteger.ToASCIIByteArray(rgb);
// // 解密
// byte[] m = Decrypt(decrypt);
// return UBigInteger.FromASCIIByteArray(m);
// }
/// <summary>
/// 使用公钥进行加密
/// </summary>
/// <param name="rgb">明文</param>
/// <returns>如果加密成功返回密文</returns>
public byte[] Encrypt(byte[] rgb)
{
UBigInteger biPlainText = UBigInteger.Parse(rgb);
if(exponent != null && modulus != null)
{
if(biPlainText >= modulus)
throw new CryptographicException("The data rgb is invalid, it should be less than modulus!");
biPlainText.RSATranslate(exponent, modulus);
return biPlainText.ToByteArray();
}
else
{
throw new CryptographicException("There's no public key, can not encrypt data!");
}
}
// /// <summary>
// /// 使用公钥进行加密
// /// </summary>
// /// <param name="rgb">明文</param>
// /// <returns>如果加密成功返回密文</returns>
// public string Encrypt(string rgb)
// {
// byte[] decrypt = UBigInteger.ToASCIIByteArray(rgb);
// // 解密
// byte[] m = Encrypt(decrypt);
// return UBigInteger.FromASCIIByteArray(m);
// }
private UBigInteger ParsePrime(byte[] byteArray, string name)
{
UBigInteger prime = UBigInteger.Parse(byteArray);
if(!prime.PrimalityRabTest())
throw new CryptographicException(name + " should be a prime");
return prime;
}
private void ImportFullParameters( RSAParameters param )
{
UBigInteger pImp = ParsePrime(param.P, "P");
UBigInteger qImp = ParsePrime(param.Q, "Q");
UBigInteger exponentImp = ParsePrime(param.Exponent, "Exponent");
UBigInteger modulusImp = UBigInteger.Parse(param.Modulus);
if(modulusImp != pImp * qImp)
{
throw new CryptographicException("Modulus mismatch p and q param");
}
UBigInteger leastP = pImp - 1;
UBigInteger leastQ = qImp - 1;
UBigInteger dImp = UBigInteger.Parse(param.D);
if(dImp != UBigInteger.Euclidean(exponentImp, leastP * leastQ))
throw new CryptographicException("Import private exponent d error!");
UBigInteger dpImp = UBigInteger.Parse(param.DP);
if(dpImp != UBigInteger.Euclidean(exponentImp, leastP))
throw new CryptographicException("Imported dp error!");
UBigInteger dqImp = UBigInteger.Parse(param.DQ);
if(dqImp != UBigInteger.Euclidean(exponentImp, leastQ))
throw new CryptographicException("Imported dq error!");
UBigInteger qInvImp = UBigInteger.Parse(param.InverseQ);
if(qInvImp != UBigInteger.Euclidean(qImp, pImp))
throw new CryptographicException("Imported InversQ error!");
p = pImp;
q = qImp;
modulus = modulusImp;
exponent = exponentImp;
d = dImp;
dp = dpImp;
dq = dqImp;
qInv = qInvImp;
}
private void ImportFullPrivateParameters( RSAParameters param )
{
UBigInteger pImp = ParsePrime(param.P, "P");
UBigInteger qImp = ParsePrime(param.Q, "Q");
UBigInteger dpImp = UBigInteger.Parse(param.DP);
UBigInteger dqImp = UBigInteger.Parse(param.DQ);
UBigInteger leastP = pImp - 1;
UBigInteger leastQ = qImp - 1;
UBigInteger exponentImp = UBigInteger.Euclidean(dpImp, leastP);
UBigInteger exponentFromDQ = UBigInteger.Euclidean(dqImp, leastQ);
UBigInteger qInvImp = UBigInteger.Parse(param.InverseQ);
if(exponentFromDQ != exponentImp || !exponentImp.PrimalityRabTest()
|| qInvImp != UBigInteger.Euclidean(qImp, pImp))
throw new CryptographicException("Error in DP or DQ parameter");
p = pImp;
q = qImp;
dp = dpImp;
dq = dqImp;
exponent = exponentImp;
//d = null;
d = UBigInteger.Euclidean(exponent, leastP * leastQ);
qInv = qInvImp;
modulus = p * q;
}
private void RegenerateByPQE( )
{
modulus = p * q;
UBigInteger leastP = p - 1;
UBigInteger leastQ = q - 1;
dp = UBigInteger.Euclidean(exponent, leastP);
dq = UBigInteger.Euclidean(exponent, leastQ);
d = UBigInteger.Euclidean(exponent, leastP * leastQ);
qInv = UBigInteger.Euclidean(q, p);
}
private void ImportPQParameter( RSAParameters param )
{
UBigInteger pImp = ParsePrime(param.P, "P");
UBigInteger qImp = ParsePrime(param.Q, "Q");
UBigInteger exponentImp = null;
if(param.Exponent != null)
{
exponentImp = ParsePrime(param.Exponent, "Exponent");
}
if(exponent == null && exponentImp == null)
throw new CryptographicException("Lack of Exponent parameter error!");
if(exponentImp != null)
exponent = exponentImp;
p = pImp;
q = qImp;
RegenerateByPQE();
}
private void ImportExponentOnly( RSAParameters param )
{
UBigInteger exponentImp = ParsePrime(param.Exponent, "Exponent");
if(p == null || q == null)
throw new CryptographicException("Import parameter error!");
RegenerateByPQE();
}
private void ImportModulusParameter( RSAParameters param )
{
modulus = UBigInteger.Parse(param.Modulus);
if(param.D != null)
d = UBigInteger.Parse(param.D);
else
d = null;
if(param.Exponent != null)
exponent = ParsePrime(param.Exponent, "Exponent");
else
exponent = null;
if(d == null && exponent == null)
throw new CryptographicException("Incomplete parameter");
p = null;
q = null;
dp = null;
dq = null;
qInv = null;
}
}
public class BigIntegerException : Exception
{
public BigIntegerException()
: base()
{
}
public BigIntegerException(string s)
: base(s)
{
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -