0
votes

The original goal is:

Generate a https url where one of parameters is PKCS7 detached signature (RSA, SHA-256, UTF-8, BASE64).

What do I have:

  1. private key (.key file begin with "-----BEGIN RSA PRIVATE KEY-----", end like this "kIng0BFt5cjuur81oQqGJgvU+dC4vQio+hVc+eAQTGmNQJV56vAHcq4v -----END RSA PRIVATE KEY-----")
  2. self signed certificate (.cer file begin with "-----BEGIN CERTIFICATE-----", end like this "xwRtGsSkfOFL4ehKn/K7mgQEc1ZVPrxTC7C/g+7grbKufvqNmsYW4w== -----END CERTIFICATE-----")
  3. data to sign

I found a java code that do almost what I need.

Method signature:

 public static String sign(PrivateKey privateKey,
                           X509Certificate certificate,
                           String data);

Now I'm stuck on how to get PrivateKey and X509Certficiate classes from given files.

I looked at many examples and got confused by these moments:

1.

KeyStore ks = KeyStore.getInstance("pkcs12");

or

PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);

Didn't find alternatives for PKCS7 standard.

  1. A snippet of method that builds PrivateKey using bouncycastle library:

        inputStream = Files.newInputStream(privateKeyFile.toPath());
        reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
        pemParser = new PEMParser(reader);
        PEMDecryptorProvider decryptorProvider = new JcePEMDecryptorProviderBuilder()
                .setProvider(PROVIDER)
                .build(privateKeyPassword.toCharArray());
        PEMEncryptedKeyPair encryptedKeyPair = (PEMEncryptedKeyPair) pemParser.readObject();
        PEMKeyPair keyPair = encryptedKeyPair.decryptKeyPair(decryptorProvider);
        ...
    

In this example I have to provide some privateKeyPassword to PEMDecryptorProvider. What is the point of this password and where can I get it?

From keyPair value I can get both privateKey and publicKey.

What is the connection between publicKey from PEMKeyPair and my certificate ? Are they the same?

Any help will be appreciated, thanks!

1
Try Key RSAKey = KeyFactory.getInstance("RSA"). generatePrivate(new X509EncodedKeySpec(keyBytes)); - zhh
@zhh: you can't generate a private key from an X509EncodedKeySpec. - President James K. Polk
The file extensions .key.and .cer are not particularly meaningful. What matters is the format of the contents of these files, not the file extensions themselves. Is the private key encrypted? Is it base-64 encoded? Does the .key file start out like -----BEGIN <something>? Does the .cer file start out that way also? - President James K. Polk
@JamesKPolk, Hey! I updated the post, yes the private key and certificate is base-64 encoded, both start out like ---- BEGING <something>. - Egor Stepanov
@JamesKPolk: >> "Is the private key encrypted?" I don't really know. How to figure it out? I added the last line of the key's body. - Egor Stepanov

1 Answers

3
votes

You don't need bouncycastle to read in the public key as Java's CertificateFactory directly supports the format of your .cer file.

The private key appears to be in a PKCS1 format that openssl can produce. If you wish to keep that format this answer shows how to extract the private key. Combining the two, here is a short snippet to read in a certificate and a private key.

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;

import java.io.FileInputStream;
import java.io.FileReader;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

public class Main {

    private static PrivateKey readPrivateKey(String filename) throws Exception {
        PEMParser pemParser = new PEMParser(new FileReader(filename));
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
        PEMKeyPair pemKeyPair = (PEMKeyPair) pemParser.readObject();
        KeyPair kp = converter.getKeyPair(pemKeyPair);
        return kp.getPrivate();
    }

    private static X509Certificate readCertificate(String filename) throws Exception {
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        return (X509Certificate) certificateFactory.generateCertificate(new FileInputStream(filename));
    }

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        PrivateKey privateKey = readPrivateKey("myKey.priv");
        X509Certificate cert = readCertificate("mycert.cer");
    }
}