Skip to content

Unable to load pem pkcs8 encrypted private key which worked in v44 #12958

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
deivse opened this issue May 20, 2025 · 3 comments · May be fixed by #12959
Open

Unable to load pem pkcs8 encrypted private key which worked in v44 #12958

deivse opened this issue May 20, 2025 · 3 comments · May be fixed by #12959
Labels

Comments

@deivse
Copy link
Contributor

deivse commented May 20, 2025

Hi, I've encountered a possible regression with v45 with loading encrypted PEM private keys.
I confirmed that this works on v44, on v45 I'm getting the following exception from load_pem_private_key:

ValueError: Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters). Details: ASN.1 parsing error: invalid value

Here's a private key for replication (this is of course not used anywhere 😄): test_pkey.pem.txt, the password is "password".

The key is generated, encrypted and serialized with the following java code, using bouncycastle 1.70

public static KeyPair generateRsaKeyPair() throws NoSuchAlgorithmException {
    KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
    keyGenerator.initialize(4096);
    return keyGenerator.generateKeyPair();
}

public static String serializePem(PemObjectGenerator generator) {
    StringWriter pemOut = new StringWriter();
    PemWriter pw = new PemWriter(pemOut);

    try {
        pw.writeObject(generator);
        pw.flush();
    } catch (IOException e) {
        throw new RuntimeException("Unable to write Key to PEM.", e);
    }

    return pemOut.toString();
}

public static String toPemPkcs8(PrivateKey privateKey, char[] password) {
    JceOpenSSLPKCS8EncryptorBuilder encryptorBuilder = new JceOpenSSLPKCS8EncryptorBuilder(PKCS8Generator.PBE_SHA1_3DES);
    encryptorBuilder.setPassword(password);
    OutputEncryptor outputEncryptor;
    try {
        outputEncryptor = encryptorBuilder.build();
    } catch (OperatorCreationException e) {
        throw new RuntimeException(e);
    }

    try {
        return serializePem(new JcaPKCS8Generator(privateKey, outputEncryptor));
    } catch (PemGenerationException e) {
        throw new RuntimeException(e);
    }
}
@deivse
Copy link
Contributor Author

deivse commented May 20, 2025

PS: Loading a non-encrypted key, generated with serializePem(new JcaPKCS8Generator(privateKey, null)) (using the above java functions) works as expected. I don't really have the time to test with encrypted keys generated with openssl etc unfortunately, so not sure if this is specific to bouncycastle or the used encryption algorithm.

@reaperhulk
Copy link
Member

Thanks for the report. This key loads fine if I unwrap the encryption first, so we appear to have some incompatibility in the PBES1 pbeWithSHAAnd3-KeyTripleDES-CBC path.

@reaperhulk
Copy link
Member

The issue here is that the salt length of this key is 20 bytes, where we assume it will be 8. We made this assumption because the RFC states

   PBEParameter ::= SEQUENCE {
       salt OCTET STRING (SIZE(8)),
       iterationCount INTEGER
   }

but clearly that does not hold in practice.

@reaperhulk reaperhulk linked a pull request May 20, 2025 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging a pull request may close this issue.

2 participants