简体   繁体   中英

Outputting encrypted PK8 private key from Java BouncyCastle

I am trying to generate an encrypted private key and CSR using Java in Matlab. Matlab adds some minor complexity, but this is mostly a Java problem. I start with a private key:

java.security.Security.addProvider(org.bouncycastle.jce.provider.BouncyCastleProvider());
keyGen = java.security.KeyPairGenerator.getInstance('RSA', 'BC');
keyGen.initialize(2048,  java.security.SecureRandom());
keypair = keyGen.generateKeyPair();
privateKey = keypair.getPrivate();

If I encrypt the key and output it as PEM:

m=org.bouncycastle.openssl.PKCS8Generator.PBE_SHA1_3DES;
encryptorBuilder = org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8EncryptorBuilder(m);
encryptorBuilder.setRandom(java.security.SecureRandom());
encryptorBuilder.setPasssword(password);
oe = encryptorBuilder.build();
gen = org.bouncycastle.openssl.jcajce.JcaPKCS8Generator(privateKey,oe);
privKeyObj = gen.generate();
fos = java.io.FileWriter('private.pem');
pem = org.bouncycastle.openssl.jcajce.JcaPEMWriter(fos);
pem.writeObject(privKeyObj);
pem.flush();
fos.close();

I get a perfectly good key. The problem is that I want to use the key with jdbc, so I need a DER formatted pk8 key. I cannot figure out how to get this out of BouncyCastle. A kludge workaround that succeeds:

textWriter = java.io.StringWriter();
pem = org.bouncycastle.openssl.jcajce.JcaPEMWriter(textWriter);
pem.writeObject(privateKey);
pem.flush();
thekey = char(textWriter.toString());
cmd = ['echo "' thekey '"|openssl pkcs8 -topk8 -out private.pk8 -inform PEM -outform DER -passout pass:' password];
system(cmd);

Now, obviously this exposes both the unencrypted private key and the password. I've tried all manner of things to coerce privKeyObj to DER, but they typically leave me with:

$openssl pkcs8 -inform DER -outform PEM -in private.pk8 -out private.pem
Error decrypting key
140735211835472:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:tasn_dec.c:1201:
140735211835472:error:0D06C03A:asn1 encoding routines:ASN1_D2I_EX_PRIMITIVE:nested asn1 error:tasn_dec.c:765:
140735211835472:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:tasn_dec.c:697:Field=version, Type=PKCS8_PRIV_KEY_INFO

The intent of this code is to generate a CSR on the end user's machine which I then sign, and which is encrypted with MAC address of the machine (and a salt), so that the program will only run on the authorized machine, and only authorized machines will be able to access my PostgreSql database.

Suggestions?

I figured it out. In my original code, I had used BcPKCS12PBEOutputEncryptorBuilder. Wrong! The correct call is to JcePKCSPBEOutputEncryptorBuilder. The correct code (in MATLAB, but converting to Java is simple) is:

    java.security.Security.addProvider(org.bouncycastle.jce.provider.BouncyCastleProvider());
    keyGen = java.security.KeyPairGenerator.getInstance('RSA', 'BC');
    keyGen.initialize(2048,  java.security.SecureRandom());
    keypair = keyGen.generateKeyPair();
    privateKey = keypair.getPrivate();
    builder=org.bouncycastle.pkcs.jcajce.JcaPKCS8EncryptedPrivateKeyInfoBuilder(privateKey);

    m=org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC;
    encryptorBuilder = org.bouncycastle.pkcs.jcajce.JcePKCSPBEOutputEncryptorBuilder(m);
    password = 'test';
    outputBuilder = encryptorBuilder.build(password);
    privKeyObj = builder.build(outputBuilder);
    fos = java.io.FileOutputStream('testkey.pk8');
    fos.write(privKeyObj.getEncoded());
    fos.flush();
    fos.close();

This generates a DER formatted PCS#8 file.

    openssl pkcs8 -inform DER -outform PEM -in testkey.pk8 -out testkey.pem

Now returns the PEM private key. To read the key:

    myPath = java.nio.file.Paths.get(pwd,'testkey.pk8');
    encodedKey = java.nio.file.Files.readAllBytes(myPath);
    privKeyObj =org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo(encodedKey);
    cp=org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter();
    cp.setProvider('BC');

    decryptorBuilder = org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder();
    inputBuilder = decryptorBuilder.build(password);
    info = privKeyObj.decryptPrivateKeyInfo(inputBuilder);
    decodedKey=cp.getPrivateKey(info);

Note that in MATLAB, you don't need to declare the type of the returned object, and you don't need to put "new" in front of a constructor.

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