Skip to content

Instantly share code, notes, and snippets.

@Bradford1040
Forked from jac18281828/certkeystore.java
Created August 18, 2025 01:21
Show Gist options
  • Select an option

  • Save Bradford1040/defed39237c413f43b993d00d1b84df1 to your computer and use it in GitHub Desktop.

Select an option

Save Bradford1040/defed39237c413f43b993d00d1b84df1 to your computer and use it in GitHub Desktop.
Complete Bouncycastle Certificate and KeyStore example
package com.jcairns;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.cert.X509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.UnrecoverableEntryException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;
public class CertAndKeyStore
{
public static final String HASH_ALGO = "SHA256";
public static final char[] PASSWORD = "1234".toCharArray();
public static final String ALIAS = "EXAMPLE";
public void save(final String path) throws NoSuchAlgorithmException, CertificateException, IOException, OperatorCreationException, KeyStoreException, InvalidKeySpecException, UnrecoverableEntryException {
final var keyStore = loadKeyStore(path);
final var keyPass = "keypass".toCharArray();
final var cert = keyStore.getCertificate(ALIAS);
if(cert != null) {
System.out.println(getPublicKeyAsString(cert.getPublicKey()));
}
final var entry = keyStore.getEntry(ALIAS, new KeyStore.PasswordProtection(keyPass));
if(entry != null) {
final var privKey = (KeyStore.PrivateKeyEntry)entry;
System.out.println(getPrivateKeyAsString(privKey.getPrivateKey()));
} else {
createNewCert(keyStore, path);
}
}
public static String getPublicKeyAsString(final PublicKey pubKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
final var fact = KeyFactory.getInstance("RSA");
final var spec = fact.getKeySpec(pubKey, X509EncodedKeySpec.class);
return new String(Base64.getEncoder().encode(spec.getEncoded()));
}
public static String getPrivateKeyAsString(final PrivateKey privKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
final var fact = KeyFactory.getInstance("RSA");
final var spec = fact.getKeySpec(privKey, PKCS8EncodedKeySpec.class);
final var pkcs8Key = spec.getEncoded();
try {
return new String(Base64.getEncoder().encode(pkcs8Key));
} finally {
Arrays.fill(pkcs8Key, (byte)0);
}
}
private void createNewCert(final KeyStore keyStore, final String path) throws KeyStoreException, CertificateException, IOException, OperatorCreationException, NoSuchAlgorithmException {
final var keyPair = generateKey();
final var cert = createCert(keyPair, HASH_ALGO, "2ad.com", 180);
final var chain = new Certificate[]{cert};
final var keyPass = "keypass".toCharArray();
keyStore.setKeyEntry(ALIAS, keyPair.getPrivate(), keyPass, chain);
final var keyFile = new File(path);
keyStore.store(new FileOutputStream(keyFile), PASSWORD);
}
public static KeyStore loadKeyStore(final String path) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
final var keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
final var keyFile = new File(path);
if(keyFile.exists()) {
System.out.println("Load existing store "+keyFile);
keyStore.load(new FileInputStream(keyFile), PASSWORD);
} else {
System.out.println("Create new store "+keyFile);
keyStore.load(null, null);
keyStore.store(new FileOutputStream(keyFile), PASSWORD);
}
return keyStore;
}
public static KeyPair generateKey() throws NoSuchAlgorithmException {
final int size = 2048;
final var generator = KeyPairGenerator.getInstance("RSA");
final var secureRandom = SecureRandom.getInstance("NativePRNG"/* + "Blocking" */);
// this is expensive!
generator.initialize(size, secureRandom);
return generator.generateKeyPair();
}
public static Certificate createCert(final KeyPair keyPair,
final String hashAlgo,
final String cn,
final int days) throws OperatorCreationException, CertificateException, CertIOException {
final var now = Instant.now();
final var notBefore = Date.from(now);
final var notAfter = Date.from(now.plus(Duration.ofDays(days)));
final var privateKey = keyPair.getPrivate();
final var contentSigner = new JcaContentSignerBuilder(hashAlgo + "with" + privateKey.getAlgorithm()).build(privateKey);
final var x500Name = new X500Name("CN=" + cn);
final var certificateBuilder = new JcaX509v3CertificateBuilder(x500Name,
BigInteger.valueOf(now.toEpochMilli()),
notBefore,
notAfter,
x500Name,
keyPair.getPublic())
.addExtension(Extension.subjectKeyIdentifier, false, createSubjectKeyId(keyPair.getPublic()))
.addExtension(Extension.authorityKeyIdentifier, false, createAuthorityKeyId(keyPair.getPublic()))
.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
return new JcaX509CertificateConverter()
.setProvider(new BouncyCastleProvider()).getCertificate(certificateBuilder.build(contentSigner));
}
public static SubjectKeyIdentifier createSubjectKeyId(final PublicKey publicKey) throws OperatorCreationException {
final var publicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
final var digCalc = new BcDigestCalculatorProvider().get(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1));
return new X509ExtensionUtils(digCalc).createSubjectKeyIdentifier(publicKeyInfo);
}
public static AuthorityKeyIdentifier createAuthorityKeyId(final PublicKey publicKey) throws OperatorCreationException {
final var publicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
final var digCalc = new BcDigestCalculatorProvider().get(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1));
return new X509ExtensionUtils((digCalc)).createAuthorityKeyIdentifier(publicKeyInfo);
}
public static void main( String[] args ) throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException, OperatorCreationException, InvalidKeySpecException, UnrecoverableEntryException {
final var certAndKey = new CertAndKeyStore();
certAndKey.save("keystore.jks");
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jcairns</groupId>
<artifactId>certkeystore</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>certkeystore</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment