.NET要使用OpenSSL生成的pem密钥文件,网上资料很少(
http://www.faqs.org/rfcs/rfc1421.html,RFC1421文件又老长老长),仅有的资料还是有错误的,所以今天干了件体力活,把PEM密钥文件610个字节一个个看过来,终于搞清了它的格式。(欢迎转载,注明出处:http://thinhunan.cnblogs.com)
增加了2048位密钥支持的类在:
.NET使用OpenSSL生成的pem密钥文件(增加size为2048的密钥转换)【做电子商务的朋友可能需要】
using
System;
using System.Text;
using System.Security.Cryptography;
using System.Web;
using System.IO;
namespace Thinhunan.Cnblogs.Com.RSAUtility
{
public class PemConverter
{
/// <summary>
/// 将pem格式公钥转换为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);
if (keyData.Length < 162 )
{
throw new ArgumentException( " pem file content is incorrect. " );
}
byte [] pemModulus = new byte [ 128 ];
byte [] pemPublicExponent = new byte [ 3 ];
Array.Copy(keyData, 29 , pemModulus, 0 , 128 );
Array.Copy(keyData, 159 , pemPublicExponent, 0 , 3 );
RSAParameters para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
return para;
}
/// <summary>
/// 将pem格式私钥转换为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);
if (keyData.Length < 609 )
{
throw new ArgumentException( " pem file content is incorrect. " );
}
int index = 11 ;
byte [] pemModulus = new byte [ 128 ];
Array.Copy(keyData, index, pemModulus, 0 , 128 );
index += 128 ;
index += 2 ; // 141
byte [] pemPublicExponent = new byte [ 3 ];
Array.Copy(keyData, index, pemPublicExponent, 0 , 3 );
index += 3 ;
index += 4 ; // 148
byte [] pemPrivateExponent = new byte [ 128 ];
Array.Copy(keyData, index , pemPrivateExponent, 0 , 128 );
index += 128 ;
index += (( int )keyData[index + 1 ] == 64 ? 2 : 3 ); // 279
byte [] pemPrime1 = new byte [ 64 ];
Array.Copy(keyData, index, pemPrime1, 0 , 64 );
index += 64 ;
index += (( int )keyData[index + 1 ] == 64 ? 2 : 3 ); // 346
byte [] pemPrime2 = new byte [ 64 ];
Array.Copy(keyData, index , pemPrime2, 0 , 64 );
index += 64 ;
index += (( int )keyData[index + 1 ] == 64 ? 2 : 3 ); // 412/413
byte [] pemExponent1 = new byte [ 64 ];
Array.Copy(keyData,index, pemExponent1, 0 , 64 );
index += 64 ;
index += (( int )keyData[index + 1 ] == 64 ? 2 : 3 ); // 479/480
byte [] pemExponent2 = new byte [ 64 ];
Array.Copy(keyData, index, pemExponent2, 0 , 64 );
index += 64 ;
index += (( int )keyData[index + 1 ] == 64 ? 2 : 3 ); // 545/546
byte [] pemCoefficient = new byte [ 64 ];
Array.Copy(keyData, index, pemCoefficient, 0 , 64 );
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
{
public class PemConverter
{
/// <summary>
/// 将pem格式公钥转换为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);
if (keyData.Length < 162 )
{
throw new ArgumentException( " pem file content is incorrect. " );
}
byte [] pemModulus = new byte [ 128 ];
byte [] pemPublicExponent = new byte [ 3 ];
Array.Copy(keyData, 29 , pemModulus, 0 , 128 );
Array.Copy(keyData, 159 , pemPublicExponent, 0 , 3 );
RSAParameters para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
return para;
}
/// <summary>
/// 将pem格式私钥转换为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);
if (keyData.Length < 609 )
{
throw new ArgumentException( " pem file content is incorrect. " );
}
int index = 11 ;
byte [] pemModulus = new byte [ 128 ];
Array.Copy(keyData, index, pemModulus, 0 , 128 );
index += 128 ;
index += 2 ; // 141
byte [] pemPublicExponent = new byte [ 3 ];
Array.Copy(keyData, index, pemPublicExponent, 0 , 3 );
index += 3 ;
index += 4 ; // 148
byte [] pemPrivateExponent = new byte [ 128 ];
Array.Copy(keyData, index , pemPrivateExponent, 0 , 128 );
index += 128 ;
index += (( int )keyData[index + 1 ] == 64 ? 2 : 3 ); // 279
byte [] pemPrime1 = new byte [ 64 ];
Array.Copy(keyData, index, pemPrime1, 0 , 64 );
index += 64 ;
index += (( int )keyData[index + 1 ] == 64 ? 2 : 3 ); // 346
byte [] pemPrime2 = new byte [ 64 ];
Array.Copy(keyData, index , pemPrime2, 0 , 64 );
index += 64 ;
index += (( int )keyData[index + 1 ] == 64 ? 2 : 3 ); // 412/413
byte [] pemExponent1 = new byte [ 64 ];
Array.Copy(keyData,index, pemExponent1, 0 , 64 );
index += 64 ;
index += (( int )keyData[index + 1 ] == 64 ? 2 : 3 ); // 479/480
byte [] pemExponent2 = new byte [ 64 ];
Array.Copy(keyData, index, pemExponent2, 0 , 64 );
index += 64 ;
index += (( int )keyData[index + 1 ] == 64 ? 2 : 3 ); // 545/546
byte [] pemCoefficient = new byte [ 64 ];
Array.Copy(keyData, index, pemCoefficient, 0 , 64 );
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;
}
}
}
测试pem导成RSAParameters成功,使用通过:
using
System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Web;
namespace Thinhunan.Cnblogs.Com.RSAUtility
{
class Program
{
#region keys
const string PUBLICKEY =
@" -----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpsDr+W45aFHIkvotZaGK/THlF
FpuZfUtghhWkHAm3H7yvL42J4xHrTr6IeUDCl4eKe6qiIgvYSNoL3u4SERGOeYmV
1F+cocu9IMGnNoicbh1zVW6e8/iGT3xaYQizJoVuWA/TC/zdds2ihCJfHDBDsouO
CXecPapyWCGQNsH5sQIDAQAB
-----END PUBLIC KEY----- " ;
const string PRIVATEKEY =
@" -----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDpsDr+W45aFHIkvotZaGK/THlFFpuZfUtghhWkHAm3H7yvL42J
4xHrTr6IeUDCl4eKe6qiIgvYSNoL3u4SERGOeYmV1F+cocu9IMGnNoicbh1zVW6e
8/iGT3xaYQizJoVuWA/TC/zdds2ihCJfHDBDsouOCXecPapyWCGQNsH5sQIDAQAB
AoGBAM/JbFs4y5WbMncrmjpQj+UrOXVOCeLrvrc/4kQ+zgCvTpWywbaGWiuRo+cz
cXrVQ6bGGU362e9hr8f4XFViKemDL4SmJbgSDa1K71i+/LnnzF6sjiDBFQ/jA9SK
4PYrY7a3IkeBQnJmknanykugyQ1xmCjbuh556fOeRPaHnhx1AkEA/flrxJSy1Z+n
Y1RPgDOeDqyG6MhwU1Jl0yJ1sw3Or4qGRXhjTeGsCrKqV0/ajqdkDEM7FNkqnmsB
+vPd116J6wJBAOuNY3oOWvy2fQ32mj6XV+S2vcG1osEUaEuWvEgkGqJ9co6100Qp
j15036AQEEDqbjdqS0ShfeRSwevTJZIap9MCQCeMGDDjKrnDA5CfB0YiQ4FrchJ7
a6o90WdAHW3FP6LsAh59MZFmC6Ea0xWHdLPz8stKCMAlVNKYPRWztZ6ctQMCQQC8
iWbeAy+ApvBhhMjg4HJRdpNbwO6MbLEuD3CUrZFEDfTrlU2MeVdv20xC6ZiY3Qtq
/4FPZZNGdZcSEuc3km5RAkApGkZmWetNwDJMcUJbSBrQMFfrQObqMPBPe+gEniQq
Ttwu1OULHlmUg9eW31wRI2uiXcFCJMHuro6iOQ1VJ4Qs
-----END RSA PRIVATE KEY----- " ;
#endregion
static void Main( string [] args)
{
TestSignAndVerify();
}
public static void TestSignAndVerify()
{
// 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( " ok " );
}
else
{
Console.WriteLine( " no " );
}
}
}
}
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Web;
namespace Thinhunan.Cnblogs.Com.RSAUtility
{
class Program
{
#region keys
const string PUBLICKEY =
@" -----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpsDr+W45aFHIkvotZaGK/THlF
FpuZfUtghhWkHAm3H7yvL42J4xHrTr6IeUDCl4eKe6qiIgvYSNoL3u4SERGOeYmV
1F+cocu9IMGnNoicbh1zVW6e8/iGT3xaYQizJoVuWA/TC/zdds2ihCJfHDBDsouO
CXecPapyWCGQNsH5sQIDAQAB
-----END PUBLIC KEY----- " ;
const string PRIVATEKEY =
@" -----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDpsDr+W45aFHIkvotZaGK/THlFFpuZfUtghhWkHAm3H7yvL42J
4xHrTr6IeUDCl4eKe6qiIgvYSNoL3u4SERGOeYmV1F+cocu9IMGnNoicbh1zVW6e
8/iGT3xaYQizJoVuWA/TC/zdds2ihCJfHDBDsouOCXecPapyWCGQNsH5sQIDAQAB
AoGBAM/JbFs4y5WbMncrmjpQj+UrOXVOCeLrvrc/4kQ+zgCvTpWywbaGWiuRo+cz
cXrVQ6bGGU362e9hr8f4XFViKemDL4SmJbgSDa1K71i+/LnnzF6sjiDBFQ/jA9SK
4PYrY7a3IkeBQnJmknanykugyQ1xmCjbuh556fOeRPaHnhx1AkEA/flrxJSy1Z+n
Y1RPgDOeDqyG6MhwU1Jl0yJ1sw3Or4qGRXhjTeGsCrKqV0/ajqdkDEM7FNkqnmsB
+vPd116J6wJBAOuNY3oOWvy2fQ32mj6XV+S2vcG1osEUaEuWvEgkGqJ9co6100Qp
j15036AQEEDqbjdqS0ShfeRSwevTJZIap9MCQCeMGDDjKrnDA5CfB0YiQ4FrchJ7
a6o90WdAHW3FP6LsAh59MZFmC6Ea0xWHdLPz8stKCMAlVNKYPRWztZ6ctQMCQQC8
iWbeAy+ApvBhhMjg4HJRdpNbwO6MbLEuD3CUrZFEDfTrlU2MeVdv20xC6ZiY3Qtq
/4FPZZNGdZcSEuc3km5RAkApGkZmWetNwDJMcUJbSBrQMFfrQObqMPBPe+gEniQq
Ttwu1OULHlmUg9eW31wRI2uiXcFCJMHuro6iOQ1VJ4Qs
-----END RSA PRIVATE KEY----- " ;
#endregion
static void Main( string [] args)
{
TestSignAndVerify();
}
public static void TestSignAndVerify()
{
// 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( " ok " );
}
else
{
Console.WriteLine( " no " );
}
}
}
}