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!