简体   繁体   中英

Java load encrypted private key

I have spent too long looking for a solution that can load an encrypted private key generated automatically by openssl cert creation.

Generate certificate and new private key with pass-phrase: password

openssl req -newkey rsa:2048 -x509 -keyout test.key -out test.crt -days 365

I have extracted the important part of the code

package test;

import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.bouncycastle.util.encoders.Base64;
import org.junit.jupiter.api.BeforeEach;

import javax.crypto.Cipher;
import javax.crypto.EncryptedPrivateKeyInfo;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.KeySpec;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Log4j2
class pkShould {
    
    private static final String PASS_PHRASE = "password";

    @SneakyThrows
    @BeforeEach
    public void setup() {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        Path pKPath = Paths.get(cl.getResource("keystore/test.key").toURI());
        try(Stream<String> lines = Files.lines(pKPath)) {
            String encrypted = lines.collect(Collectors.joining("\n"));
            encrypted = encrypted.replace("-----BEGIN ENCRYPTED PRIVATE KEY-----", "");
            encrypted = encrypted.replace("-----END ENCRYPTED PRIVATE KEY-----", "");
            byte[] content = Base64.decode(encrypted);

            EncryptedPrivateKeyInfo encryptPKInfo = new EncryptedPrivateKeyInfo(content);
            Cipher cipher = Cipher.getInstance(encryptPKInfo.getAlgName());
            PBEKeySpec pbeKeySpec = new PBEKeySpec(PASS_PHRASE.toCharArray());
            SecretKeyFactory secFac = SecretKeyFactory.getInstance(encryptPKInfo.getAlgName());
            Key pbeKey = secFac.generateSecret(pbeKeySpec);
            AlgorithmParameters algParams = encryptPKInfo.getAlgParameters();
            cipher.init(Cipher.DECRYPT_MODE, pbeKey, algParams);
            KeySpec pkcs8KeySpec = encryptPKInfo.getKeySpec(cipher);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            PrivateKey expectedPrivateKey = kf.generatePrivate(pkcs8KeySpec);
        }
    }
}

Never makes it past EncryptedPrivateKeyInfo , as far as I can tell the private key formed correctly and it is working fine used in a keyStore.

Stacktrace

java.io.IOException: ObjectIdentifier() -- data isn't an object ID (tag = 48)

    at sun.security.util.ObjectIdentifier.<init>(ObjectIdentifier.java:285)
    at sun.security.util.DerInputStream.getOID(DerInputStream.java:321)
    at com.sun.crypto.provider.PBES2Parameters.engineInit(PBES2Parameters.java:267)
    at java.security.AlgorithmParameters.init(AlgorithmParameters.java:293)
    at sun.security.x509.AlgorithmId.decodeParams(AlgorithmId.java:150)
    at sun.security.x509.AlgorithmId.<init>(AlgorithmId.java:132)
    at sun.security.x509.AlgorithmId.parse(AlgorithmId.java:416)
    at javax.crypto.EncryptedPrivateKeyInfo.<init>(EncryptedPrivateKeyInfo.java:95)

Any help is much appreciated.

That error is extremely useless, unfortunately. All it really means is 'java did not like it'. It can mean almost anything from: The key is protected with a passphrase cipher and/or bitsize that java doesn't like, to the key itself is using a cipher/bitsize java doesn't like, to the key is in a format that isn't PKCS#8.

It sure looks like you generated the key in x509 format, which probably isn't going to work. Perhaps converting it will work; give this a try:

openssl pkcs8 -topk8 \ 
-inform PEM -outform PEM \ 
-in key.pem -out key-pkcs8.pem

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