Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read PKCS8 file with empty password using BouncyCastle

I can generate a PKCS#8 encrypted file with empty password using OpenSSL:

~ $ openssl pkcs8 -topk8 -in ca_private.pem 
Enter pass phrase for ca_private.pem:
Enter Encryption Password: <ENTER>
Verifying - Enter Encryption Password: <ENTER>
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBvTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIsWq90VBNFMwCAggA
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBCFtKOCdDUeRohccAqQZaDIBIIB
YG+ohLBKQ766BTCXXZ7wyAP1l0grcQPgnzI2XmEj33rBIMogS6l3oAN3Faos2I6n
PcUY+aNLQtDSbvPzF4ozd0oWYBTa60iYGboQQ2RolhRRTzNW6K2tWBWUB35v2rLV
VYu7xJMX+dr/PxzhEgaQ4Nerb7v7/EAn4fLv3zcW9f/tPbljKUAiKc/YYP+GjRjA
GyJThdVpyeK6Jflobc3V8gqL8Gk0MgeHmXuUR1+SthA6ia5havH7D/FMLvXxZtRK
CpWOQ8mJp7g7dbUf+qWTLX+dMPQFPZDEofdkCY2/J4dSkgNnPgp+1oxSVpEAAR9v
gWsRezU2KfFUEMIljYOT+s4ZhkeAGtA8qa8qnr0yv9uz1OkzFtrleNf0WV8wRqI7
azo/7ff9TbecseYlTRgR40nd2l3Z9RLMVhsS09vPffYDw3jt+Zqf3m7iEri6eSug
5bMcZTszaQsVT0HOfCcpQ1Q=
-----END ENCRYPTED PRIVATE KEY-----

When reading this with a PEMParser, it returns an instance of PKCS8EncryptedPrivateKeyInfo (as expected).

Trying to decrypt that with JceOpenSSLPKCS8DecryptorProviderBuilder, however, fails with

org.bouncycastle.pkcs.PKCSException: unable to read encrypted data: password empty

There is a hard coded check for empty password when creating the decryption key. Is there a way around this? OpenSSL surely deals just fine reading the PKCS#8 back...

Sample code:

import com.excelfore.api.lib.util.ApiCrypto;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;

import java.io.FileReader;

class Scratch {
    public static void main(String[] args) throws Exception {

        try (FileReader fr = new FileReader(args[0])) {

            Object whatIsIt = new PEMParser(fr).readObject();
            if (whatIsIt instanceof PKCS8EncryptedPrivateKeyInfo) {
                PKCS8EncryptedPrivateKeyInfo pInfo = (PKCS8EncryptedPrivateKeyInfo) whatIsIt;
                InputDecryptorProvider provider =
                        new JceOpenSSLPKCS8DecryptorProviderBuilder().setProvider(ApiCrypto.bouncyCastleProvider).build(args[1].toCharArray());
                pInfo.decryptPrivateKeyInfo(provider);
                System.out.println("ok");
            } else {
                System.out.println("I don't want "+whatIsIt.getClass().getName());
            }
        }
    }
}
like image 373
Pawel Veselov Avatar asked Nov 24 '25 11:11

Pawel Veselov


1 Answers

Not sure if there is what you expect or not (do not test yet with empty passphrase)

    public static KeyPair parseKeyPair(Path pemFile, String passPhrase) {
        try(PEMParser pemParser = new PEMParser(Files.newBufferedReader(pemFile))) {
            Object object = pemParser.readObject();
            JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BouncyCastleProviderHolder.BC_PROVIDER);
            if(object instanceof PEMEncryptedKeyPair) {
                if(passPhrase == null)
                    throw new IllegalArgumentException("Pass phrase required for parsing RSA private key");

                PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(passPhrase.toCharArray());
                return converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv));
            }
            if(object instanceof PEMKeyPair) {
                return converter.getKeyPair((PEMKeyPair) object);
            }
        } catch(Exception e) {
            throw new PicApplicationException("Couldn't parse pem to keypair", e);
        }

        throw new PicApplicationException("Couldn't parse pem to keypair");
    }

You may pass empty passphrase to this line:

PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build("".toCharArray());
like image 88
SoT Avatar answered Nov 26 '25 01:11

SoT