J'ai une clé privée RSA au format PEM, est-il un moyen simple de lire ça .NET et instancier une RSACryptoServiceProvider pour déchiffrer les données chiffrées avec la clé publique correspondante?
Réponses
Trop de publicités?J'ai résolu, merci. Dans le cas où ça intéresse quelqu'un, bouncycastle a fait le tour, tout m'a fallu un certain temps en raison du manque de connaissances à partir de mon côté et de la documentation. C'est le code:
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));
À l'égard de l'importation de la clé privée RSA, sans l'aide de la 3e partie du code tel que BouncyCastle, je pense que la réponse est "non, pas avec un PEM de la clé privée seul."
Cependant, comme mentionné ci-dessus, par Simone, vous pouvez simplement combiner le PEM de la clé privée (*.la clé) et le fichier de certificat à l'aide de cette touche (*.crt) dans un *.fichier pfx qui peut ensuite être facilement importées.
Pour générer le fichier PFX à partir de la ligne de commande:
openssl pkcs12 -in a.crt -inkey a.key -export -out a.pfx
Ensuite, utilisez normalement avec le .NET certificat de classe tels que:
using System.Security.Cryptography.X509Certificates;
X509Certificate2 combinedCertificate = new X509Certificate2(@"C:\path\to\file.pfx");
Maintenant, vous pouvez suivre l'exemple de MSDN pour le cryptage et le décryptage via RSACryptoServiceProvider: http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.aspx
EDIT: j'ai quitté que pour le déchiffrement vous auriez besoin de les importer à l'aide de la PFX mot de passe et Exportable drapeau. (voir: BouncyCastle RSAPrivateKey pour .NET RSAPrivateKey)
X509KeyStorageFlags flags = X509KeyStorageFlags.Exportable;
X509Certificate2 cert = new X509Certificate2("my.pfx", "somepass", flags);
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
RSAParameters rsaParam = rsa.ExportParameters(true);
Vous pouvez prendre un coup d'oeil à JavaScience de la source pour OpenSSLKey. (OpenSSLKey.cs)
Il y a du code qui fait exactement ce que vous voulez faire.
En fait, ils ont beaucoup de crypto code source disponible ici.
Source de l'extrait de code:
//------- 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();
}
}
Le truc entre les
-----BEGIN RSA PRIVATE KEY----
et
-----END RSA PRIVATE KEY-----
est l'encodage base64 d'un fichier PKCS#8 PrivateKeyInfo (à moins qu'elle indique RSA CHIFFRÉE de la CLÉ PRIVÉE dans ce cas c'est une EncryptedPrivateKeyInfo).
Il n'est pas difficile à décoder manuellement, mais sinon, votre meilleur pari est de P/Invoke pour CryptImportPKCS8.
Mise à jour: Le CryptImportPKCS8 fonction n'est plus disponible pour l'utilisation de Windows Server 2008 et Windows Vista. Au lieu de cela, utilisez la PFXImportCertStore fonction.
Vérifier http://msdn.microsoft.com/en-us/library/dd203099.aspx
en vertu de la Cryptographie Bloc d'Application.
Ne sais pas si vous aurez votre réponse, mais il vaut la peine d'essayer.
Edit après le Commentaire.
Ok puis vérifier ce code.
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);
}