I'm trying to extract a private key from a .PFX file to a .PEM file format. I was able to do it using Aes128Cbc
in either .NET or OpenSSL:
.NET:
PbeParameters pbeParams = new PbeParameters(PbeEncryptionAlgorithm.Aes128Cbc, HashAlgorithmName.SHA256, 1);
byte[] privateKey = rsaPrivateKey.ExportEncryptedPkcs8PrivateKey("pass123", pbeParams);
Console.WriteLine("Generating PEM file...\n");
StringWriter stringWriter = new StringWriter();
PemObject pemObject = new PemObject("ENCRYPTED PRIVATE KEY", privateKey);
Pem.PemWriter pemWriter = new PemWriter(stringWriter);
pemWriter.WriteObject(pemObject);
OpenSSL:
openssl pkcs12 -in path/to/pfx -nocerts -out path/to/output
For both output options, I could check the key by using:
openssl rsa -check -noout -in private-key.pem
Now, I'm trying to change the Password-Based Encryption algorithm to use AES-GCM but I don't know how to do it or even if it is possible. I've tried to use AesGcm
on .NET and also searched into the options of openssl pkcs12
command but I couldn't find a way to do it:
byte[] privateKeyBytes = rsaPrivateKey.ExportPkcs8PrivateKey();
byte[] salt = GenerateRandomBytes(16);
byte[] iv = GenerateRandomBytes(12);
int iterations = 100_000;
int keySize = 256;
int tagSize = 128 / 8;
byte[] key = DeriveKey("pass123", salt, iterations, keySize);
byte[] encryptedData, tag;
using (AesGcm aesGcm = new AesGcm(key))
{
encryptedData = new byte[privateKeyBytes.Length];
tag = new byte[tagSize];
aesGcm.Encrypt(iv, privateKeyBytes, encryptedData, tag);
}
StringWriter stringWriter = new StringWriter();
PemObject pemObject = new PemObject("ENCRYPTED PRIVATE KEY", encryptedData);
PemWriter pemWriter = new PemWriter(stringWriter);
pemWriter.WriteObject(pemObject);
// ...
public static byte[] GenerateRandomBytes(int length)
{
byte[] randomBytes = new byte[length];
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
rng.GetBytes(randomBytes);
}
return randomBytes;
}
public static byte[] DeriveKey(string password, byte[] salt, int iterations, int keySize)
{
using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations))
{
return pbkdf2.GetBytes(keySize / 8);
}
}
I had also tried to concatenate all info into the PEM file:
Array.Copy(pemData, salt, 16);
Array.Copy(pemData, 16, iv, 0, 12);
Array.Copy(pemData, 28, encryptedData, 0, privateKeyBytes.Length);
Array.Copy(pemData, 28 + privateKeyBytes.Length, tag, 0, tagSize);
I don't much understand about all PKCS standards but after reading about PKCS #12 and after looking for some answers among the internet I'm wondering if it's possible to do it or if there is some kind of impossibility that I couldn't see yet.