Skip to content

Instantly share code, notes, and snippets.

@akorobov
Created October 9, 2013 23:46
Show Gist options
  • Save akorobov/6910564 to your computer and use it in GitHub Desktop.
Save akorobov/6910564 to your computer and use it in GitHub Desktop.
Example of reading and writing x509 certificate and RSA private keys encoded in PEM format using BouncyCastle 1.48 (new api)
public class PkiUtils {
public static final int MinPassPhraseLength = 4;
public static List<?> readPemObjects(InputStream is, final String pphrase)
throws IOException {
List<Object> list = new LinkedList<Object>();
PEMParser pr2 = new PEMParser(new InputStreamReader(is));
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
JcaX509CertificateConverter certconv = new JcaX509CertificateConverter().setProvider("BC");
while (true) {
Object o = pr2.readObject();
if (null == o)
break; // done
list.add(parsePemObject(o, pphrase, converter, certconv));
}
return list;
}
private static Object parsePemObject(Object o,
final String pphrase,
JcaPEMKeyConverter converter,
JcaX509CertificateConverter certconv) {
try {
if (o instanceof PEMEncryptedKeyPair) {
o = ((PEMEncryptedKeyPair)o).decryptKeyPair(new JcePEMDecryptorProviderBuilder().build(pphrase.toCharArray()));
} else if(o instanceof PKCS8EncryptedPrivateKeyInfo) {
InputDecryptorProvider pkcs8decoder = new JceOpenSSLPKCS8DecryptorProviderBuilder().build(pphrase.toCharArray());
o = converter.getPrivateKey(
((PKCS8EncryptedPrivateKeyInfo)o).decryptPrivateKeyInfo(pkcs8decoder));
}
} catch (Throwable t) {
throw new RuntimeException("Failed to decode private key", t);
}
if (o instanceof PEMKeyPair) {
try {
return converter.getKeyPair((PEMKeyPair) o);
} catch (PEMException e) {
throw new RuntimeException("Failed to construct public/private key pair", e);
}
} else if(o instanceof RSAPrivateCrtKey){
RSAPrivateCrtKey pk = (RSAPrivateCrtKey) o;
return makeKeyPair(pk);
} else if (o instanceof X509CertificateHolder) {
try {
return certconv.getCertificate((X509CertificateHolder) o);
} catch (Exception e) {
throw new RuntimeException("Failed to read X509 certificate", e);
}
} else {
// catchsink, should check for certs and reject rest?
System.out.println("generic case type " + o.getClass().getName());
return o;
}
}
/**
* Writes certificate or private key in PEM format into given stream Private
* key will be encrypted using 3des cipher with given password(password must
* be 4+ long).
*
* @param w {@link Writer}
* @param obj instance of {@link PrivateKey} or {@link Certificate}
* @param password password
* @throws IOException
*/
public static void writePem(Writer w, Object obj, String password)
throws IOException {
writePem(w, obj, password, true);
}
static void writePem(Writer w, Object obj, String password, boolean closeStream)
throws IOException {
PEMWriter pw = null;
try {
pw = new PEMWriter(w);
if (obj instanceof PrivateKey) {
if (null == password ||
password.length() < MinPassPhraseLength)
throw new IllegalArgumentException(
"Private key encryption password must be no less than " +
MinPassPhraseLength + " characters");
pw.writeObject(obj, "DES-EDE3-CBC", password.toCharArray(),
SecureRandom.getInstance("SHA1PRNG"));
} else
pw.writeObject(obj);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} finally {
if (null != pw && closeStream)
pw.close();
}
}
}
@davesmith10
Copy link

You've not elected to put the import statements into the gist, which makes it much harder to use. there's even a static method imported and I have no idea where from.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment