简体   繁体   中英

How read a PKCS8 encrypted Private key which is also encoded in DER with bouncycastle?

I have tried answers of these questions:

Bouncy Castle : PEMReader => PEMParser

Read an encrypted private key with bouncycastle/spongycastle

However as my encrypted key is encoded in DER when I call

Object object = pemParser.readObject(); 

object is null.

I can convert it to PEM with this openssl's command (it decrypts the key too)

openssl pkcs8 -inform der -in pkey.key -out pkey.pem 

but I need to read the key in its original file

Both those Qs are about parsing, and decrypting, files using OpenSSL's 'legacy PEM' encryption. You are using PKCS8 encryption which is different though similar, so Reading PKCS8 in PEM format: Cannot find provider is closer. You can use most of the approach there, but skipping the PEM parse:

import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; // NOT the 
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;       // javax ones!
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;

    // args[0] = filename args[1] = password
    FileInputStream fis = new FileInputStream(args[0]);
    byte[] buff = new byte[9999]; int len = fis.read(buff); fis.close();
    // could use File.readAllBytes in j8 but my dev machine is old

    // create what PEMParser would have 
    ASN1Sequence derseq = ASN1Sequence.getInstance (Arrays.copyOf(buff,len));
    PKCS8EncryptedPrivateKeyInfo encobj = new PKCS8EncryptedPrivateKeyInfo(EncryptedPrivateKeyInfo.getInstance(derseq));
    // decrypt and convert key
    JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
    InputDecryptorProvider decryptionProv = new JceOpenSSLPKCS8DecryptorProviderBuilder().build(args[1].toCharArray());
    PrivateKeyInfo keyInfo = encobj.decryptPrivateKeyInfo(decryptionProv);
    PrivateKey key = converter.getPrivateKey(keyInfo);

    // now actually use key, this is just a dummy
    System.out.println (key.getAlgorithm());

By using SpongyCastle we can get good results. I made some code that will get the desired result. SpongyCastle Jars can be downloaded from below:- core , prov , pkix

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.Security;

// need core.jar, prov.jar, bcpkix-jdk15on.jar
import org.spongycastle.asn1.ASN1Sequence;
import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
import org.spongycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.spongycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.spongycastle.operator.InputDecryptorProvider;
import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;

class Decrypt {

    private static void usage() {
        System.err.println(" Usage: encrypted.pk8 password out_decrypted.pk8");
        System.exit(2);
    }

    public static byte[] copyOf(byte[] original, int newLength) {
        byte[] copy = new byte[newLength];
        System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
        return copy;
    }

    public static void loadProvider(String providerClassName)
        throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class providerClass = Class.forName(providerClassName);
        Provider provider = (Provider)providerClass.newInstance();
//        Security.insertProviderAt(provider, 1);
        Security.addProvider(provider);
    }

    public static void main(String[] args) throws Exception {
        if (args.length != 3) usage();

        loadProvider("org.spongycastle.jce.provider.BouncyCastleProvider");

        FileInputStream fis = new FileInputStream(args[0]);
        byte[] buff = new byte[fis.available()];
        int len = fis.read(buff);
        fis.close();

        // create what PEMParser would have
        ASN1Sequence derseq = ASN1Sequence.getInstance(copyOf(buff, len));
        EncryptedPrivateKeyInfo epkInfo = EncryptedPrivateKeyInfo.getInstance(derseq);
        PKCS8EncryptedPrivateKeyInfo encobj = new PKCS8EncryptedPrivateKeyInfo(epkInfo);

        // decrypt and convert key
        InputDecryptorProvider decryptionProv = new JceOpenSSLPKCS8DecryptorProviderBuilder().build(args[1].toCharArray());
        PrivateKeyInfo keyInfo = encobj.decryptPrivateKeyInfo(decryptionProv);
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("SC");
        PrivateKey key = converter.getPrivateKey(keyInfo);

        // now actually use key, this is just a dummy
        System.out.println(key.getAlgorithm());

        FileOutputStream fos = new FileOutputStream(args[2]);
        fos.write(key.getEncoded());
        fos.close();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM