using System;
using System.Text;
using System.Security.Cryptography;
using System.Web;
using System.IO;
namespace Thinhunan.Cnblogs.Com.RSAUtility
{
/// <summary>
/// Author http://thinhunan.cnblogs.com
/// </summary>
public class PemConverter
{
/// <summary>
/// 将pem格式公钥(1024 or 2048)转换为RSAParameters
/// </summary>
/// <param name="pemFileConent">pem公钥内容</param>
/// <returns>转换得到的RSAParamenters</returns>
public static RSAParameters ConvertFromPemPublicKey(string pemFileConent)
{
if (string.IsNullOrEmpty(pemFileConent))
{
throw new ArgumentNullException("pemFileConent", "This arg cann't be empty.");
}
pemFileConent = pemFileConent.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\n", "").Replace("\r", "");
byte[] keyData = Convert.FromBase64String(pemFileConent);
bool keySize1024 = (keyData.Length == 162);
bool keySize2048 = (keyData.Length == 294);
if (!( keySize1024 || keySize2048 ))
{
throw new ArgumentException("pem file content is incorrect, Only support the key size is 1024 or 2048");
}
byte[] pemModulus = (keySize1024? new byte[128] : new byte[256]);
byte[] pemPublicExponent = new byte[3];
Array.Copy(keyData, (keySize1024? 29:33), pemModulus, 0,(keySize1024? 128:256));
Array.Copy(keyData, (keySize1024? 159:291), pemPublicExponent, 0, 3);
RSAParameters para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
return para;
}
/// <summary>
/// 将pem格式私钥(1024 or 2048)转换为RSAParameters
/// </summary>
/// <param name="pemFileConent">pem私钥内容</param>
/// <returns>转换得到的RSAParamenters</returns>
public static RSAParameters ConvertFromPemPrivateKey(string pemFileConent)
{
if (string.IsNullOrEmpty(pemFileConent))
{
throw new ArgumentNullException("pemFileConent", "This arg cann't be empty.");
}
pemFileConent = pemFileConent.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\n", "").Replace("\r","");
byte[] keyData = Convert.FromBase64String(pemFileConent);
bool keySize1024 = (keyData.Length == 609 || keyData.Length == 610);
bool keySize2048 = (keyData.Length == 1190 || keyData.Length == 1192);
if (!(keySize1024 || keySize2048))
{
throw new ArgumentException("pem file content is incorrect, Only support the key size is 1024 or 2048");
}
int index = ( keySize1024 ? 11 : 12);
byte[] pemModulus = ( keySize1024 ? new byte[128]:new byte[256]);
Array.Copy(keyData, index, pemModulus, 0, pemModulus.Length);
index += pemModulus.Length;
index += 2;
byte[] pemPublicExponent = new byte[3];
Array.Copy(keyData, index, pemPublicExponent, 0, 3);
index += 3;
index += 4;
if ((int)keyData[index] == 0)
{
index++;
}
byte[] pemPrivateExponent = (keySize1024 ? new byte[128] : new byte[256]);
Array.Copy(keyData, index , pemPrivateExponent, 0, pemPrivateExponent.Length);
index += pemPrivateExponent.Length;
index += (keySize1024? ((int)keyData[index+1] == 64?2: 3):((int)keyData[index+2] == 128 ?3:4));
byte[] pemPrime1 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index, pemPrime1, 0, pemPrime1.Length);
index += pemPrime1.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemPrime2 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index , pemPrime2, 0, pemPrime2.Length);
index += pemPrime2.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemExponent1 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData,index, pemExponent1, 0, pemExponent1.Length);
index += pemExponent1.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemExponent2 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index, pemExponent2, 0, pemExponent2.Length);
index += pemExponent2.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemCoefficient = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index, pemCoefficient, 0, pemCoefficient.Length);
RSAParameters para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
para.D = pemPrivateExponent;
para.P = pemPrime1;
para.Q = pemPrime2;
para.DP = pemExponent1;
para.DQ = pemExponent2;
para.InverseQ = pemCoefficient;
return para;
}
}
}
using System.Text;
using System.Security.Cryptography;
using System.Web;
using System.IO;
namespace Thinhunan.Cnblogs.Com.RSAUtility
{
/// <summary>
/// Author http://thinhunan.cnblogs.com
/// </summary>
public class PemConverter
{
/// <summary>
/// 将pem格式公钥(1024 or 2048)转换为RSAParameters
/// </summary>
/// <param name="pemFileConent">pem公钥内容</param>
/// <returns>转换得到的RSAParamenters</returns>
public static RSAParameters ConvertFromPemPublicKey(string pemFileConent)
{
if (string.IsNullOrEmpty(pemFileConent))
{
throw new ArgumentNullException("pemFileConent", "This arg cann't be empty.");
}
pemFileConent = pemFileConent.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\n", "").Replace("\r", "");
byte[] keyData = Convert.FromBase64String(pemFileConent);
bool keySize1024 = (keyData.Length == 162);
bool keySize2048 = (keyData.Length == 294);
if (!( keySize1024 || keySize2048 ))
{
throw new ArgumentException("pem file content is incorrect, Only support the key size is 1024 or 2048");
}
byte[] pemModulus = (keySize1024? new byte[128] : new byte[256]);
byte[] pemPublicExponent = new byte[3];
Array.Copy(keyData, (keySize1024? 29:33), pemModulus, 0,(keySize1024? 128:256));
Array.Copy(keyData, (keySize1024? 159:291), pemPublicExponent, 0, 3);
RSAParameters para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
return para;
}
/// <summary>
/// 将pem格式私钥(1024 or 2048)转换为RSAParameters
/// </summary>
/// <param name="pemFileConent">pem私钥内容</param>
/// <returns>转换得到的RSAParamenters</returns>
public static RSAParameters ConvertFromPemPrivateKey(string pemFileConent)
{
if (string.IsNullOrEmpty(pemFileConent))
{
throw new ArgumentNullException("pemFileConent", "This arg cann't be empty.");
}
pemFileConent = pemFileConent.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\n", "").Replace("\r","");
byte[] keyData = Convert.FromBase64String(pemFileConent);
bool keySize1024 = (keyData.Length == 609 || keyData.Length == 610);
bool keySize2048 = (keyData.Length == 1190 || keyData.Length == 1192);
if (!(keySize1024 || keySize2048))
{
throw new ArgumentException("pem file content is incorrect, Only support the key size is 1024 or 2048");
}
int index = ( keySize1024 ? 11 : 12);
byte[] pemModulus = ( keySize1024 ? new byte[128]:new byte[256]);
Array.Copy(keyData, index, pemModulus, 0, pemModulus.Length);
index += pemModulus.Length;
index += 2;
byte[] pemPublicExponent = new byte[3];
Array.Copy(keyData, index, pemPublicExponent, 0, 3);
index += 3;
index += 4;
if ((int)keyData[index] == 0)
{
index++;
}
byte[] pemPrivateExponent = (keySize1024 ? new byte[128] : new byte[256]);
Array.Copy(keyData, index , pemPrivateExponent, 0, pemPrivateExponent.Length);
index += pemPrivateExponent.Length;
index += (keySize1024? ((int)keyData[index+1] == 64?2: 3):((int)keyData[index+2] == 128 ?3:4));
byte[] pemPrime1 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index, pemPrime1, 0, pemPrime1.Length);
index += pemPrime1.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemPrime2 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index , pemPrime2, 0, pemPrime2.Length);
index += pemPrime2.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemExponent1 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData,index, pemExponent1, 0, pemExponent1.Length);
index += pemExponent1.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemExponent2 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index, pemExponent2, 0, pemExponent2.Length);
index += pemExponent2.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemCoefficient = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index, pemCoefficient, 0, pemCoefficient.Length);
RSAParameters para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
para.D = pemPrivateExponent;
para.P = pemPrime1;
para.Q = pemPrime2;
para.DP = pemExponent1;
para.DQ = pemExponent2;
para.InverseQ = pemCoefficient;
return para;
}
}
}
测试加、解密,签名验证功能通过:
static void Main(string[] args)
{
string privateKey = GetPemContent(@"C:\ftzl\privatekey2048.pem");
string publicKey = GetPemContent(@"c:\ftzl\publickey2048.pem");
//DebugRsaKey(privateKey,true);
TestSignAndEncrypt(privateKey,publicKey);
//TestVerifyOATransferSign();
}
static string GetPemContent(string filePath)
{
string content = File.ReadAllText(filePath, Encoding.ASCII);
return content;
}
public static void TestSignAndEncrypt(string privateKey,string publicKey)
{
//sign
RSAParameters para = PemConverter.ConvertFromPemPrivateKey(privateKey);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(para);
byte[] testData = Encoding.UTF8.GetBytes("hello");
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] signData = rsa.SignData(testData, md5);
//verify
RSAParameters paraPub = PemConverter.ConvertFromPemPublicKey(publicKey);
RSACryptoServiceProvider rsaPub = new RSACryptoServiceProvider();
rsaPub.ImportParameters(paraPub);
if (rsaPub.VerifyData(testData, md5, signData))
{
Console.WriteLine("verify sign successful");
}
else
{
Console.WriteLine("verify sign failed");
}
//encrypt and decrypt data
byte[] encryptedData = rsaPub.Encrypt(testData, false);
byte[] decryptedData = rsa.Decrypt(encryptedData, false);
Console.WriteLine(Encoding.UTF8.GetString(decryptedData));
}
{
string privateKey = GetPemContent(@"C:\ftzl\privatekey2048.pem");
string publicKey = GetPemContent(@"c:\ftzl\publickey2048.pem");
//DebugRsaKey(privateKey,true);
TestSignAndEncrypt(privateKey,publicKey);
//TestVerifyOATransferSign();
}
static string GetPemContent(string filePath)
{
string content = File.ReadAllText(filePath, Encoding.ASCII);
return content;
}
public static void TestSignAndEncrypt(string privateKey,string publicKey)
{
//sign
RSAParameters para = PemConverter.ConvertFromPemPrivateKey(privateKey);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(para);
byte[] testData = Encoding.UTF8.GetBytes("hello");
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] signData = rsa.SignData(testData, md5);
//verify
RSAParameters paraPub = PemConverter.ConvertFromPemPublicKey(publicKey);
RSACryptoServiceProvider rsaPub = new RSACryptoServiceProvider();
rsaPub.ImportParameters(paraPub);
if (rsaPub.VerifyData(testData, md5, signData))
{
Console.WriteLine("verify sign successful");
}
else
{
Console.WriteLine("verify sign failed");
}
//encrypt and decrypt data
byte[] encryptedData = rsaPub.Encrypt(testData, false);
byte[] decryptedData = rsa.Decrypt(encryptedData, false);
Console.WriteLine(Encoding.UTF8.GetString(decryptedData));
}