How to Create an Android Keystore with Bouncy Castle

With the help of The Legion of the Bouncy Castle added to your Gradle dependency section:

compile 'org.bouncycastle:bcprov-jdk15on:1.54'
compile 'org.bouncycastle:bcpkix-jdk15on:1.54'

you can try to Sign Your App Manually with Java.

There are a few things to do. Generate a key pair:

private static KeyPair generateKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException {
  KeyPairGenerator keyGen = KeyPairGenerator.getInstance( "RSA" );
  SecureRandom random = SecureRandom.getInstance( "SHA1PRNG", "SUN" );
  keyGen.initialize( 2048, random );
  return keyGen.generateKeyPair();
}

Generate a certificate (which we will use to sign the development app):

private static X509Certificate generateCertificate( KeyPair keyPair )
  throws OperatorCreationException, CertificateException, InvalidKeyException, NoSuchAlgorithmException,
  NoSuchProviderException, SignatureException
{
  String issuerString = "C=DE, O=datenkollektiv, OU=Planets Debug Certificate";
  // subjects name - the same as we are self signed.
  String subjectString = "C=DE, O=datenkollekitv, OU=Planets Debug Certificate";
  X500Name issuer = new X500Name( issuerString );
  BigInteger serial = BigInteger.ONE;
  Date notBefore = new Date();
  Date notAfter = new Date( System.currentTimeMillis() + ( ONE_THOUSAND_DAYS ) );
  X500Name subject = new X500Name( subjectString );
  PublicKey publicKey = keyPair.getPublic();
  JcaX509v3CertificateBuilder v3Bldr = new JcaX509v3CertificateBuilder( issuer,
                                                                      serial,
                                                                      notBefore,
                                                                      notAfter,
                                                                      subject,
                                                                      publicKey );
  X509CertificateHolder certHldr = v3Bldr
    .build( new JcaContentSignerBuilder( "SHA1WithRSA" ).setProvider( "BC" ).build( keyPair.getPrivate() ) );
  X509Certificate cert = new JcaX509CertificateConverter().setProvider( "BC" ).getCertificate( certHldr );
  cert.checkValidity( new Date() );
  cert.verify( keyPair.getPublic() );
  return cert;
}

And package everything into a keystore:

public static byte[] generateDefaultAndroidDebugKeystore() {
  KeyStore ks;
  try {
    ks = loadKeystore( null );
    KeyPair keyPair = generateKeyPair();
    X509Certificate certificate = generateCertificate( keyPair );
    ks.setKeyEntry( "androiddebugkey",
                  keyPair.getPrivate(),
                  "android".toCharArray(),
                  new X509Certificate[]{
                    certificate
    } );
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    ks.store( os, "android".toCharArray() );
    return os.toByteArray();
  } catch( KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException | NoSuchProviderException
      | InvalidKeyException | OperatorCreationException | SignatureException e )
  {
    e.printStackTrace();
  }
  throw new IllegalStateException( "Failed to generate default Android debug keystore." );
}

And as a bonus this is how we can load a keystore:

private static KeyStore loadKeystore( byte[] keystoreBytes )
  throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException
{
  KeyStore ks;
  ks = KeyStore.getInstance( "JKS" );
  if( keystoreBytes != null ) {
    ks.load( new ByteArrayInputStream( keystoreBytes ), "android".toCharArray() );
  } else {
    ks.load( null );
  }
  return ks;
}

Let's go!

Show Comments