Showing posts with label keystore. Show all posts
Showing posts with label keystore. Show all posts

Thursday, October 4, 2018

How to sign android app with platform keys using gradle?

Leave a Comment

I saw couple similar questions like:

but I feel my problem is different.

First of all I use:

android:sharedUserId="android.uid.system"

so I need to sign my app with platform key. I'm able to do that in this way:

cd $ANDROID_ROOT/out/host/linux-x86/framework java -Djava.library.path=$ANDROID_ROOT/out/host/linux-x86/lib64 -jar signapk.jar $ANDROID_ROOT/build/target/product/security/platform.x509.pem $ANDROID_ROOT/build/target/product/security/platform.pk8 $APP_DIR/app/build/outputs/apk/debug/app-debug.apk $APP_DIR/MyApp-signed.apk 

However I want to do signing from gradle, so I have generated jks file in this way:

./keytool-importkeypair -k my_keystore.jks -p my_password -pk8 $ANDROID_ROOT/build/target/product/security/platform.pk8 -cert $ANDROID_ROOT/build/target/product/security/platform.x509.pem -alias platform 

and I've modified app/build.gradle to have:

 signingConfigs {      release {          storeFile file("my_keystore.jks")          storePassword "my_password"          keyAlias "platform"          keyPassword "my_password"      }  }   buildTypes {      release {          minifyEnabled false          proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'           signingConfig signingConfigs.release      }  } 

I've checked that my_keystore.jks has platform alias with:

keytool -list -v -keystore my_keystore.jks | grep Alias Alias name: platform 

but when I try to do:

./gradlew assembleRelease 

or:

./gradlew signingReport 

I get:

Failed to read key platform from store "(...)/my_keystore.jks": Invalid keystore format

Update: I've tried following dr_g tips and I'm able to sign app using Android Studio (Build -> Generate Signed APK), so I guess keystore is ok, but still I get the same error when using assembleRelease. I've also tried generating my own keystore as suggested by deadfish and indeed keystore generated by Android Studio is fine for gradle and assembleRelease works, but it's not platform key, so I can't use it unfortunately.

3 Answers

Answers 1

Please try using the .keystore variant. There could be ways to fix the java keystore (.jks) format but it is likely to take more time.

1) Generate your .keystore file from your separate key files

$ openssl pkcs8 -inform DER -nocrypt -in \   $ANDROID_ROOT/build/target/product/security/platform.pk8 -out platform.key $ openssl pkcs12 -export -in \   $ANDROID_ROOT/build/target/product/security/platform.x509.pem -inkey \   platform.key -name platform -out platform.pem -password pass:password $ keytool -importkeystore -destkeystore platform.keystore -deststorepass \   password -srckeystore platform.pem -srcstoretype PKCS12 -srcstorepass    password 

2) Test your new keystore:

$ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore \   platform.keystore -storepass password your-app.apk platform 

3) Deploy keystore in your gradle build:

signingConfigs {  debug {     storeFile     file('debug.keystore')     storePassword 'android'     keyAlias      'androiddebugkey'     keyPassword   'android'  }  release {     storeFile     file('platform.keystore')     storePassword 'password'     keyAlias      'platform'     keyPassword   'password'  }  } 

The above build.gradle is also showing an example of using the android debug keystore as standard for debug builds.

Answers 2

use the .keystore file not the .jks when you generate you app,Android studio will notice you create a keyStore, try this key.

Answers 3

After chat with deadfish and following his suggestions (thanks for help!) I've come up with following workaround in app/build.gradle (inside android {}):

applicationVariants.all { variant ->     variant.assemble.doLast {         exec {             commandLine 'sh', '../mySigningScript.sh'         }     } } 

This will run my script everytime when assembleDebug or assembleRelease is finished. I will not accept my answer because it's not answering my question and it forces me to remove signingConfigs from gradle but at least it's a workaround which potentially could be used if no better solution is proposed.

Read More

Thursday, May 24, 2018

how to securely store encryption keys in android?

Leave a Comment

I want to know how to securely store encryption key in Android? What is the best scenario to protect encryption and secrete keys?

5 Answers

Answers 1

From your comments, you need to encrypt data using a local key for current Android versions and the old ones

Android Keystore is designed to generate and protect your keys. But it is not available for API level below 18 and it has some limitations until API level 23.

You will need a random symmetric encryption key, for example AES. The AES key is used to encrypt and decrypt you data. I'm going to summarize your options to generate and store it safely depending on Android API level.

  • API Level < 18: Android Keystore not present. Request a password to the user, derive an encryption key from the password, The drawback is that you need to prompt for the password when application starts. The encryption key it is not stored in the device. It is calculated each time when the application is started using the password

  • API Level >=18 <23: Android Keystore available without AES support. Generate a random AES key using the default cryptographic provider (not using AndroidKeystore). Generate a RSA key pair into Android Keystore, and encrypt the AES key using RSA public key. Store encrypted AES key into Android SharedPreferences. When application starts, decrypt the AES key using RSA private key

  • API Level >=23: Android Keystore available with AES support. Generate a random AES key using into Android Keystore. You can use it directly.

To encrypt to can use AES/CBC/PKCS7Padding algorithm. It requires also a random initialization vector (IV) to encrypt your data, but it can be public.

Alternatives:

  • API level >14: Android Key Chain: KeyChain is a system-wide credential storage. You can install certificates with private keys that can be used by applications. Use a preinstalled key to encrypt/decrypt your AES key as shown in the second case above.

  • External token: The protected keys are not stored in the device. You can use an external token containing a private/public key pair that allows you to encrypt the AES key. The token can be accesed using bluetooth or NFC

Answers 2

You cannot place the encryption key inside your apk file. You may want to keep it in a remote server and decrypt using server. Or you may make it difficult for others by encoding the key and keeping it in non-obvious places. But there's no bullet proof solution for this.

Answers 3

There is no way to securely save your private api keys into code. But you can use NDK to securely save private keys. It is not trivial to get key from NDK. Secue Key With NDK Example

Answers 4

You can use Android Keystore system to store and retrieve sensitive information. Read this 5 minute article to understand how it works. Using the Android Keystore system to store and retrieve sensitive information

Answers 5

You will need a random symmetric encryption key, for example AES. The AES key is used to encrypt and decrypt you data. I'm going to summarize your options to generate and store it safely depending on Android API level

Read More

Sunday, October 29, 2017

How to employ keyed-hash message authentication code (HMAC) with Android Keystore

Leave a Comment

I am investigating the use of the Android KeyStore for Marshmallow and above.

I would like to simultaneously verify both the data integrity and the authentication of my data by employing HMAC's.

How do I go about achieving this?

I am current generating an Encrypt/Decrypt key as follows:-

        mKeyStore = KeyStore.getInstance(keyStoreName);         mKeyStore.load(mKeyStoreLoadStoreParameter);          if (mKeyStore.containsAlias(keyStoreAlias)) {             mSecretKey = (SecretKey) mKeyStore.getKey(keyStoreAlias, KEY_STORE_PASSWORD);         } else {             final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, keyStoreName);             final int keyPurpose = KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT;              keyGenerator.init(                     new KeyGenParameterSpec.Builder(keyStoreAlias, keyPurpose)                             .setKeySize(KEY_STORE_KEY_SIZE)                             .setBlockModes(KeyProperties.BLOCK_MODE_GCM)                             .setRandomizedEncryptionRequired(true)                             .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)                             .build());              mSecretKey = keyGenerator.generateKey(); 

I have found this sample for generating HMAC's

SecretKey key = ...; // HMAC key of algorithm "HmacSHA512".   KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");  keyStore.load(null);  keyStore.setEntry(          "key1",          new KeyStore.SecretKeyEntry(key),          new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN).build());  // Key imported, obtain a reference to it.  SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null);  // The original key can now be discarded.   Mac mac = Mac.getInstance("HmacSHA512");  mac.init(keyStoreKey); 

However, how do I use this when encrypting/decrypting my data?

EXPLANATION

I have a number of choices/decisions to make when implementing security/cryptography within any Android application.

1). Do I implement cryptography of any sort Yes or No? 2). If Yes then... I should attempt to achieve the "most" secure solution possible.

If I am going to employ cryptography then I need to ensure the following.

a). I store passwords/secret keys in a "Safe Place" e.g. Android Key Store. b). I use the "strongest" cryptography available. c). I would like to simultaneously verify both the data integrity and the authentication of my data, e.g. I would like to detect if my encrypted data has been tampered with.

As I understand what I have read about HMAC's, they provide this functionality. I would like to know how I code the use of HMAC's into my Android application to ensure both the data integrity and the authentication of my data.

1 Answers

Answers 1

You can apply HMAC to the plain text HMAC(plain text) before encrypting and recompute the HMAC after decrypting to check that the original message is the same.

It may be redundant because if the cipher text is altered you will not be able to decrypt it.

First generate a HMAC key inside AndroidKeyStore. I found an example here

KeyGenerator keyGenerator = KeyGenerator.getInstance(          KeyProperties.KEY_ALGORITHM_HMAC_SHA256, "AndroidKeyStore"); keyGenerator.initialize(          new KeyGenParameterSpec.Builder(hmacKeyAlias, KeyProperties.PURPOSE_SIGN).build()); SecretKey key = keyGenerator.generateKey(); 

Then Apply HMAC to the original data and store the result somewhere

Mac mac = Mac.getInstance("HmacSHA256"); mac.init(key); byte hmacOriginalData[] = mac.doFinal(dataToEncrypt); //Store hmacOriginalData  

After decrypting, get HMAC key from AndroidKeyStore, recompute HMAC and check both macs are equal

Key key = keyStore.getKey(hmacKeyAlias, null); Mac mac = Mac.getInstance("HmacSHA256"); mac.init(key); byte hmacDecryptedData[] = mac.doFinal(decryptedData); //Check equals(hmacDecryptedData, hmacOriginalData); 
Read More

Wednesday, February 8, 2017

Java DefaultSslContextFactory keystore update dynamically

Leave a Comment

I have an existing application that uses the org.restlet.engine.ssl.DefaultSslContextFactory and a keystore file that is loaded when the server is started. I have another application that creates certificates that have to be added dynamically to the keystore file while the server is running. To perform this, I created the certificate and the private key in the code and then write it to a directory. The directory is watched by a bash script that checks for new files, and if one appears it will be imported into the existing keystore file.

But when trying to access the server with the newly imported certificate the handshake fails. Only when restarting the server, the access can be completed successfully, which I assume means that the added certificate will not be reloaded by the server.

Is there a way to update the running application with the new entry in the keystore file?

2 Answers

Answers 1

Importing the new certificate into your keystore doesn't refresh your current SSLConext as nothing tells the JVM that the keystore has changed.

To do that you'll have to tell your application that a new certificate was added into your keystore but instead of reloading the keystore -as far as I know it shouldn't be possible- , what is possible by the way is that your can add the new certificate into your current SSLContext See here.

To achieve that, you've to provide a bean aware of the new certificate -maybe the component that call your bash script- in which you injected an SSLContext instance.

It's also interesting if you split your application using a micro service architecture, delegate to one module the fact to deal with certificates and reload it (using proper configure LB) as keystore is updated.

Answers 2

Since this seems to be quite an impossible task to accomplish, I decided to do a workaround. I used nginx as a proxy in front of the application. Nginx is able to perform client authentication with multiple CA root certificates which is exactly what I need. The connection between the application and nginx can simply be done via a HTTP since they are residing on the same host (just different ports).

Read More

Saturday, January 21, 2017

Cannot find Keystore Entry. But I know it's there

Leave a Comment

Android Studio on Windows 10

cannot load key store: unrecognized keystore entry

I have an existing app compiled and signed. I've created a new version of it. The unique id for the app is the same (com.name.appname). I want to sign the new version with the existing key. I have the key. I know the password. I know the alias is correct. All I get back is: cannot load key store: unrecognized keystore entry

More specifially: Error:Execution failed for task ':app:packageRelease'.

com.android.ide.common.signing.KeytoolException: Failed to read key [name] from store "[path]\publishKey": Unrecognized keystore entry

All of the answers I see here are along the lines of "use the command line utility to find the key alias", bla bla bla...

I know this stuff is there and correct. It's just not letting me use it.

What am I missing here? Is there something I need to edit to let it know that I indeed DO want to use that signature?

2 Answers

Answers 1

It appears that somehow, someway, the keystore file got corrupted. Perhaps one of the later entries did it. I do not know. But the way I got around this was by using a KeyStore Explorer, I was able to save the file from there, and remove the last couple of entries.

I was then able to find the alias and sign my app normally. Both from the old machine and the new one.

Just leaving this here in hopes that someone else will find it useful.

Answers 2

You can run this command to list the content of your keystore file:

keytool -list -keystore .keystore

If you are looking for a specific alias, you can also specify it in the command:

keytool -list -keystore .keystore -alias foo

If the alias is not found, it will display an exception:

keytool error: java.lang.Exception: Alias does not exis

// other wise you are used following command in command prompt:

C:\Program Files\Android\Android Studio\jre\bin>keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%.android\debug.keystore | C:\OpenSSL-Win32\bin\openssl.exe sha1 -binary | C:\OpenSSL-Win32\bin\openssl.exe base64

Read More

Wednesday, March 16, 2016

How to embed a keystore certificate only during runtime from classpath?

Leave a Comment

I have an application that should connect to a https webservice.

The webservice offers a zip file containing the following 3 files: *.crt, *.csr, *.key

Question: can I place them into the classpath of the application jar, and then load the cert only on startup (maybe in an own keystore/truststore that is is created on the fly)?

Or do I necessairly have to intall them into the java keystore on each machine, before I can use the my app client?

My preferred way would be to not having install them to the local java keystore, but load them on the fly during application startup.

1 Answers

Answers 1

I found it's actually possible, also from classpath:

//pass a p12 or pfx file (file may be on classpath also) public void initSSL(String keyStoreFile, String pass) {         InputStream keyStoreStream = this.getClass().getClassLoader().getResourceAsStream(keyStoreFile);                        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());             KeyStore keyStore = KeyStore.getInstance("PKCS12");              keyStore.load(keyStoreStream, keyPassword.toCharArray());             kmf.init(keyStore, keyPassword.toCharArray());               KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());             trustStore.load(null, null);              // init the trust manager factory by read certificates             TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());             tmf.init(trustStore);              // 3. init the SSLContext using kmf and tmf above             SSLContext sslContext = SSLContext.getInstance("TLS");             sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);             SSLContext.setDefault(sslContext); } 
Read More