NET uses the pem key file generated by OpenSSL. There is very little information on the Internet (http://www.faqs.org/rfcs/rfc1421.html,rfc1421 ). The only information is wrong, so today I did my work, after reading the 610 bytes of the PEM key file one by one, we finally figured out its format.
Using System;
Using System. Text;
Using System. Security. Cryptography;
Using System. Web;
Using System. IO;
Namespace Thinhunan. Cnblogs. Com. RSAUtility
{
Public class PemConverter
{
/// <Summary>
/// Convert the pem public key to RSAParameters
/// </Summary>
/// <Param name = "pemFileConent"> pem public key content </param>
/// <Returns> RSAParamenters after conversion </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 [1, 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>
/// Convert the private key in pem format to RSAParameters
/// </Summary>
/// <Param name = "pemFileConent"> pem private key content </param>
/// <Returns> RSAParamenters after conversion </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 [1, 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, fig, 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;
}
}
}
The test pem is successfully imported into 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
Fpuzfutghhwkham3policyvl42j4xhrtr6ieudcl4eke6qiigvysnol3u4sergoeymv
1F + cocu9IMGnNoicbh1zVW6e8/iGT3xaYQizJoVuWA/TC/zdds2ihCJfHDBDsouO
CXecPapyWCGQNsH5sQIDAQAB
----- End public key -----";
Const string PRIVATEKEY =
@ "----- Begin rsa private key -----
MIICXQIBAAKBgQDpsDr + W45aFHIkvotZaGK/thlffpuzfutghhwkham3policyvl42j
4xHrTr6IeUDCl4eKe6qiIgvYSNoL3u4SERGOeYmV1F + cocu9IMGnNoicbh1zVW6e
8/iGT3xaYQizJoVuWA/TC/zdds2ihCJfHDBDsouOCXecPapyWCGQNsH5sQIDAQAB
AoGBAM/JbFs4y5WbMncrmjpQj + UrOXVOCeLrvrc/4kQ + zgCvTpWywbaGWiuRo + cz
CXrVQ6bGGU362e9hr8f4XFViKemDL4SmJbgSDa1K71i +/LnnzF6sjiDBFQ/jA9SK
4PYrY7a3IkeBQnJmknanykugyQ1xmCjbuh556fOeRPaHnhx1AkEA/flrxJSy1Z + n
Y1RPgDOeDqyG6MhwU1Jl0yJ1sw3Or4qGRXhjTeGsCrKqV0/ajqdkDEM7FNkqnmsB
+ Vpd1_j6wjbaouny3oowvy2fq32mj6xv + S2vcG1osEUaEuWvEgkGqJ9co6100Qp
Bytes
Bytes
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 ");
}
}
}
}
Author THINK (TAN zhenlin)