Pablo C. García
Pablo C. García

Reputation: 22404

KeyStore no key found for my alias

Im trying to encrypt some data in my app using this gist.

I have signed my apk with my alias "Pablo". The problem is trying to run this code:

public static String encrypt(String alias, String plaintext) {
    try {
        PublicKey publicKey = getPrivateKeyEntry(alias).getCertificate().getPublicKey();
        Cipher cipher = getCipher();
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return Base64.encodeToString(cipher.doFinal(plaintext.getBytes()), Base64.NO_WRAP);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

private static KeyStore.PrivateKeyEntry getPrivateKeyEntry(String alias) {
    try {
        KeyStore ks = KeyStore
                .getInstance("AndroidKeyStore");
        ks.load(null);
        KeyStore.Entry entry = ks.getEntry(alias, null);

        if (entry == null) {
            Log.w(TAG, "No key found under alias: " + alias);
            Log.w(TAG, "Exiting signData()...");
            return null;
        }

        if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
            Log.w(TAG, "Not an instance of a PrivateKeyEntry");
            Log.w(TAG, "Exiting signData()...");
            return null;
        }
        return (KeyStore.PrivateKeyEntry) entry;
    } catch (Exception e) {
        Log.e(TAG, e.getMessage(), e);
        return null;
    }
}

But im getting the exception : "No key found under alias"

Any idea? I must type the same alias as my jks right?

Thanks!

Upvotes: 0

Views: 4762

Answers (2)

David Rawson
David Rawson

Reputation: 21497

The answer from Sonic is correct in that the Java Key Store that you use to sign the app is different from the KeyStore you use in your app. The former is a file on your dev machine (your laptop) while the latter is only on the handset you install your app to (an Android phone or emulator). Signing your apk so it can be released on the Play Store and encrypting the user's private data on your data are distinct procedures.

In cases where it's not clear, you should try and refer to canonical sources rather than arbitrary gists and tutorials which vary greatly in quality. In this case, the official Android documentation for KeyStore has a complete example for storing keys. Please note that the Android KeyStore referenced in the Gist is only available on API 18+.

Admittedly, the code examples in the official documentation and the Gist are quite complex and it is easy to make a mistake. A better option may be to something like Scytale. It is a wrapper around the KeyStore that will correctly handle the case where API < 18. Here is a code snippet to demonstrate:

Store store = new Store(getApplicationContext());
if (!store.hasKey("test")) {
   SecretKey key = store.generateSymmetricKey("test", null);
}
...

// Get key
SecretKey key = store.getSymmetricKey("test", null);

// Encrypt/Decrypt data
Crypto crypto = new Crypto(Options.TRANSFORMATION_SYMMETRIC);
String text = "Sample text";

String encryptedData = crypto.encrypt(text, key);
Log.i("Scytale", "Encrypted data: " + encryptedData);

String decryptedData = crypto.decrypt(encryptedData, key);
Log.i("Scytale", "Decrypted data: " + decryptedData);

Note that you will still need to create a key in order to encrypt data regardless of the state of your .jks on your host machine. The code in the sample is correct:

if there is no key in the keystore with that alias
    make a new key with that alias
use the key to encrypt and decrypt data.

Upvotes: 2

Sonic
Sonic

Reputation: 815

The keystore you ask for in your app is not the same keystore as your local keystore to sign the app: You can check that by calling ks.containsAlias(alias). You have to provide the alias in your runtime keystore. You have to create an entry for your alias: setEntry(String alias, KeyStore.Entry entry, KeyStore.ProtectionParameter protParam) (Saves a keystore Entry under the specified alias.)

Upvotes: 1

Related Questions