如何从.NET读取PEM RSA私钥
我有一个PEM
格式的RSA
私钥,是否有直接的方式从.NET读取这个私钥并实例化一个RSACryptoServiceProvider
来解密使用相应公钥encryption的数据?
我解决了,谢谢。 如果任何人感兴趣, bouncycastle就是这么做的,因为缺乏对我的知识和文档的理解,我花了一些时间。 这是代码:
var bytesToDecrypt = Convert.FromBase64String("la0Cz.....D43g=="); // string to decrypt, base64 encoded AsymmetricCipherKeyPair keyPair; using (var reader = File.OpenText(@"c:\myprivatekey.pem")) // file containing RSA PKCS1 private key keyPair = (AsymmetricCipherKeyPair) new PemReader(reader).ReadObject(); var decryptEngine = new Pkcs1Encoding(new RsaEngine()); decryptEngine.Init(false, keyPair.Private); var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
关于轻松导入RSA私钥,不使用BouncyCastle等第三方代码,我想答案是“不是,只有私钥没有PEM”。
但是,正如上面Simone提到的那样,您可以简单地将私钥(* .key)的PEM和使用该密钥(* .crt)的证书文件组合成* .pfx文件,然后可以轻松导入该文件。
从命令行生成PFX文件:
openssl pkcs12 -in a.crt -inkey a.key -export -out a.pfx
然后通常使用.NET证书类,例如:
using System.Security.Cryptography.X509Certificates; X509Certificate2 combinedCertificate = new X509Certificate2(@"C:\path\to\file.pfx");
现在,您可以按照MSDN中的示例通过RSACryptoServiceProvider进行encryption和解密:
我遗漏了解密您将需要导入使用PFX密码和可导出标志。 (请参阅: BouncyCastle RSAPrivateKey到.NET RSAPrivateKey )
X509KeyStorageFlags flags = X509KeyStorageFlags.Exportable; X509Certificate2 cert = new X509Certificate2("my.pfx", "somepass", flags); RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey; RSAParameters rsaParam = rsa.ExportParameters(true);
您可以看看JavaScience的OpenSSLKey源代码 。 ( OpenSSLKey.cs )
那里有代码就是你想要做的。
事实上,他们有很多可用的encryption源代码。
源代码片段:
//------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider --- public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey) { byte[] MODULUS, E, D, P, Q, DP, DQ, IQ ; // --------- Set up stream to decode the asn.1 encoded RSA private key ------ MemoryStream mem = new MemoryStream(privkey) ; BinaryReader binr = new BinaryReader(mem) ; //wrap Memory Stream with BinaryReader for easy reading byte bt = 0; ushort twobytes = 0; int elems = 0; try { twobytes = binr.ReadUInt16(); if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) binr.ReadByte(); //advance 1 byte else if (twobytes == 0x8230) binr.ReadInt16(); //advance 2 bytes else return null; twobytes = binr.ReadUInt16(); if (twobytes != 0x0102) //version number return null; bt = binr.ReadByte(); if (bt !=0x00) return null; //------ all private key components are Integer sequences ---- elems = GetIntegerSize(binr); MODULUS = binr.ReadBytes(elems); elems = GetIntegerSize(binr); E = binr.ReadBytes(elems) ; elems = GetIntegerSize(binr); D = binr.ReadBytes(elems) ; elems = GetIntegerSize(binr); P = binr.ReadBytes(elems) ; elems = GetIntegerSize(binr); Q = binr.ReadBytes(elems) ; elems = GetIntegerSize(binr); DP = binr.ReadBytes(elems) ; elems = GetIntegerSize(binr); DQ = binr.ReadBytes(elems) ; elems = GetIntegerSize(binr); IQ = binr.ReadBytes(elems) ; Console.WriteLine("showing components .."); if (verbose) { showBytes("\nModulus", MODULUS) ; showBytes("\nExponent", E); showBytes("\nD", D); showBytes("\nP", P); showBytes("\nQ", Q); showBytes("\nDP", DP); showBytes("\nDQ", DQ); showBytes("\nIQ", IQ); } // ------- create RSACryptoServiceProvider instance and initialize with public key ----- RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); RSAParameters RSAparams = new RSAParameters(); RSAparams.Modulus =MODULUS; RSAparams.Exponent = E; RSAparams.D = D; RSAparams.P = P; RSAparams.Q = Q; RSAparams.DP = DP; RSAparams.DQ = DQ; RSAparams.InverseQ = IQ; RSA.ImportParameters(RSAparams); return RSA; } catch (Exception) { return null; } finally { binr.Close(); } }
之间的东西
-----BEGIN RSA PRIVATE KEY----
和
-----END RSA PRIVATE KEY-----
是PKCS#8 PrivateKeyInfo的base64编码(除非它说RSA ENCRYPTED PRIVATE KEY,在这种情况下它是EncryptedPrivateKeyInfo)。
手动解码并不难,但是否则最好的办法就是P / Invoke到CryptImportPKCS8 。
更新:从Windows Server 2008和Windows Vista开始, CryptImportPKCS8function不再可用。 而是使用PFXImportCertStore函数。
检查http://msdn.microsoft.com/en-us/library/dd203099.aspx
在encryption应用程序块下。
不知道你是否会得到你的答案,但值得一试。
在评论之后编辑 。
好,然后检查这个代码。
using System.Security.Cryptography; public static string DecryptEncryptedData(stringBase64EncryptedData, stringPathToPrivateKeyFile) { X509Certificate2 myCertificate; try{ myCertificate = new X509Certificate2(PathToPrivateKeyFile); } catch{ throw new CryptographicException("Unable to open key file."); } RSACryptoServiceProvider rsaObj; if(myCertificate.HasPrivateKey) { rsaObj = (RSACryptoServiceProvider)myCertificate.PrivateKey; } else throw new CryptographicException("Private key not contained within certificate."); if(rsaObj == null) return String.Empty; byte[] decryptedBytes; try{ decryptedBytes = rsaObj.Decrypt(Convert.FromBase64String(Base64EncryptedData), false); } catch { throw new CryptographicException("Unable to decrypt data."); } // Check to make sure we decrpyted the string if(decryptedBytes.Length == 0) return String.Empty; else return System.Text.Encoding.UTF8.GetString(decryptedBytes); }
好吧,我使用mac来生成我自己签名的密钥。 这是我使用的工作方法。
我创build了一个shell脚本来加速我的密钥生成。
genkey.sh
#/bin/sh ssh-keygen -f host.key openssl req -new -key host.key -out request.csr openssl x509 -req -days 99999 -in request.csr -signkey host.key -out server.crt openssl pkcs12 -export -inkey host.key -in server.crt -out private_public.p12 -name "SslCert" openssl base64 -in private_public.p12 -out Base64.key
将+ x执行标志添加到脚本
chmod +x genkey.sh
然后调用genkey.sh
./genkey.sh
我input一个密码(重要的是包括一个密码,至less在输出结束时)
Enter pass phrase for host.key: Enter Export Password: {Important to enter a password here} Verifying - Enter Export Password: { Same password here }
然后,我将所有内容都放在Base64.Key中,并将其放入名为sslKey的string中
private string sslKey = "MIIJiAIBA...................................." + "......................ETC...................." + "......................ETC...................." + "......................ETC...................." + ".............ugICCAA=";
然后,我用一个懒惰的负载属性获得我的X509证书与私钥。
X509Certificate2 _serverCertificate = null; X509Certificate2 serverCertificate{ get { if (_serverCertificate == null){ string pass = "Your Export Password Here"; _serverCertificate = new X509Certificate(Convert.FromBase64String(sslKey), pass, X509KeyStorageFlags.Exportable); } return _serverCertificate; } }
我想走这条路,因为我在mac上使用.net 2.0和Mono,我想使用vanilla Framework代码而没有编译库或依赖项。
我最后使用的是SslStream来确保TCP通信到我的应用程序
SslStream sslStream = new SslStream(serverCertificate, false, SslProtocols.Tls, true);
我希望这有助于其他人。
注意
没有密码,我无法正确解锁导出的私钥。
对于不想使用Bouncy的人来说,并且正在尝试其他答案中包含的一些代码,我发现代码在大多数情况下工作,但在某些RSA私有string上跳转,例如I包括在下面。 通过查看弹性代码,我调整了由wprl提供的代码
RSAparams.D = ConvertRSAParametersField(D, MODULUS.Length); RSAparams.DP = ConvertRSAParametersField(DP, P.Length); RSAparams.DQ = ConvertRSAParametersField(DQ, Q.Length); RSAparams.InverseQ = ConvertRSAParametersField(IQ, Q.Length); private static byte[] ConvertRSAParametersField(byte[] bs, int size) { if (bs.Length == size) return bs; if (bs.Length > size) throw new ArgumentException("Specified size too small", "size"); byte[] padded = new byte[size]; Array.Copy(bs, 0, padded, size - bs.Length, bs.Length); return padded; } -----BEGIN RSA PRIVATE KEY----- MIIEoQIBAAKCAQEAxCgWAYJtfKBVa6Px1Blrj+3Wq7LVXDzx+MiQFrLCHnou2Fvb fxuDeRmd6ERhDWnsY6dxxm981vTlXukvYKpIZQYpiSzL5pyUutoi3yh0+/dVlsHZ UHheVGZjSMgUagUCLX1p/augXltAjgblUsj8GFBoKJBr3TMKuR5TwF7lBNYZlaiR k9MDZTROk6MBGiHEgD5RaPKA/ot02j3CnSGbGNNubN2tyXXAgk8/wBmZ4avT0U4y 5oiO9iwCF/Hj9gK/S/8Q2lRsSppgUSsCioSg1CpdleYzIlCB0li1T0flB51zRIpg JhWRfmK1uTLklU33xfzR8zO2kkfaXoPTHSdOGQIDAQABAoIBAAkhfzoSwttKRgT8 sgUYKdRJU0oqyO5s59aXf3LkX0+L4HexzvCGbK2hGPihi42poJdYSV4zUlxZ31N2 XKjjRFDE41S/Vmklthv8i3hX1G+Q09XGBZekAsAVrrQfRtP957FhD83/GeKf3MwV Bhe/GKezwSV3k43NvRy2N1p9EFa+i7eq1e5i7MyDxgKmja5YgADHb8izGLx8Smdd +v8EhWkFOcaPnQRj/LhSi30v/CjYh9MkxHMdi0pHMMCXleiUK0Du6tnsB8ewoHR3 oBzL4F5WKyNHPvesYplgTlpMiT0uUuN8+9Pq6qsdUiXs0wdFYbs693mUMekLQ4a+ 1FOWvQECgYEA7R+uI1r4oP82sTCOCPqPi+fXMTIOGkN0x/1vyMXUVvTH5zbwPp9E 0lG6XmJ95alMRhjvFGMiCONQiSNOQ9Pec5TZfVn3M/w7QTMZ6QcWd6mjghc+dGGE URmCx8xaJb847vACir7M08AhPEt+s2C7ZokafPCoGe0qw/OD1fLt3NMCgYEA08WK S+G7dbCvFMrBP8SlmrnK4f5CRE3pV4VGneWp/EqJgNnWwaBCvUTIegDlqS955yVp q7nVpolAJCmlUVmwDt4gHJsWXSQLMXy3pwQ25vdnoPe97y3xXsi0KQqEuRjD1vmw K7SXoQqQeSf4z74pFal4CP38U3pivvoE4MQmJeMCfyJFceWqQEUEneL+IYkqrZSK 7Y8urNse5MIC3yUlcose1cWVKyPh4RCEv2rk0U1gKqX29Jb9vO2L7RflAmrLNFuA J+72EcRxsB68RAJqA9VHr1oeAejQL0+JYF2AK4dJG/FsvvFOokv4eNU+FBHY6Tzo k+t63NDidkvb5jIF6lsCgYEAlnQ08f5Y8Z9qdCosq8JpKYkwM+kxaVe1HUIJzqpZ X24RTOL3aa8TW2afy9YRVGbvg6IX9jJcMSo30Llpw2cl5xo21Dv24ot2DF2gGN+s peFF1Z3Naj1Iy99p5/KaIusOUBAq8pImW/qmc/1LD0T56XLyXekcuK4ts6Lrjkit FaMCgYAusOLTsRgKdgdDNI8nMQB9iSliwHAG1TqzB56S11pl+fdv9Mkbo8vrx6g0 NM4DluCGNEqLZb3IkasXXdok9e8kmX1en1lb5GjyPbc/zFda6eZrwIqMX9Y68eNR IWDUM3ckwpw3rcuFXjFfa+w44JZVIsgdoGHiXAdrhtlG/i98Rw== -----END RSA PRIVATE KEY-----