Score:0

How to extract a private key from .PFX file to .PEM file using AES-GCM as a password-based encryption?

cx flag

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.

dave_thompson_085 avatar
cn flag
You don't say which PEM format you want of the many that exist, but your first code sample suggests you want the one in [rfc7468 section 11](https://www.rfc-editor.org/rfc/rfc7468#section-11). Note this is not just "any kind of encryption of PKCS8 that I invented", it is a specific format defined in rfc5208 and rfc5958 and neither your second or third samples are anything like it. I'm not aware of any AES-GCM scheme defined for or compatible with PKCS8 encryption; do you have a reference for what you want? (OpenSSL definitely won't do anything other than CBC.)
Davy Souza avatar
cx flag
@dave_thompson_085 , you're right, I'm trying to generate a PEM file of an Encrypted Private Key Info. It was a request from the security team to replace Aes128Cbc claiming that CBC is a vulnerable cipher that doesn't provide integrity. I read the RFCs and had the same conclusion of you that AES-GCM scheme is not defined for PKCS8, but I'm wondering, is that safe to use Aes128Cbc for PBE? Shouldn't we need integrity to keep a file with a private key info?
Davy Souza avatar
cx flag
I keep going on RFCs, but I'm a little confused on which RFC should I use. The rfc5208 uses pkcs5 for password based encryption which I believe doesn't specifies AEAS-GCM. The rfc5958 that obsoletes rfc5208 says that: "Changed imports from PKCS #5 to [RFC5912] and [RFC5911]", but I still couldn't find a list of algorithms that is recommended to use. Also, I'm not sure if the rfc5912 and rfc5911 are available at OpenSSL or .NET. I mean, is these rfcs a standard?
dave_thompson_085 avatar
cn flag
A privatekey in PKCS8 format (which is what is encrypted in EncryptedPrivateKeyInfo) is a combination of effectively-random and strictly-structured that is hard to effectively tamper, so CBC is _probably_ safe, and certainly is _very_ widely used without any reported problem or attack. However if you want (real, cryptographic) integrity -- and I wouldn't disagree with that goal -- a widely supported way is to put it in PKCS12 (aka PFX) which uses the common PKCS8 encryption (CBC) for the keybag, but also has a password-based MAC on the file. ...
dave_thompson_085 avatar
cn flag
... PKCS12/PFX is _usually_ used for key PLUS cert or cert-chain; the standard allows key-only and e.g. OpenSSL can do that, but some software might not in which case the convention is to provide a dummy self-signed cert which is ignored when the key is used; yes this isn't elegant but it works. There is no registry or comprehensive list of algorithms for PKCS5 -- which is extensible by design -- but I've never seen anything besides PBES2 from 2898/8018 or the schemes in PKCS12/7292 appendix B-C (and to hone my earlier comment, I've never seen an AEAD scheme that fits into PBES2).
dave_thompson_085 avatar
cn flag
... (added) but PKCS12/PFX is almost always handled in binary, not PEM, if that is important. There is no technical reason it _can't_ be PEMized, people just haven't chosen to.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.