Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Realm Encryption with Android

Realm is using AES-256 for encryption and decryption. And, I am trying to use Android KeyStore to generate/store the keys, but as per this page - https://developer.android.com/training/articles/keystore.html#SecurityFeatures, Android supports this only on APIs 23 and above.

Can someone please point me to an example or any other related info on how I can use realm with encryption to support APIs 4.0 and above?

Thanks.

like image 748
user4122421 Avatar asked Dec 18 '22 15:12

user4122421


2 Answers

We recently ran into the same problem and decided to simply store the key in private Shared Preferences, because if the phone is not rooted, you will not be able to get it and if it is rooted, then there are some ways to get data even from secure keyStore.

We use next Realm configuration inside Application subclass:

RealmConfiguration config = new RealmConfiguration.Builder()
            .deleteRealmIfMigrationNeeded()
            .name(DB_NAME)
            .encryptionKey(mKeyProvider.getRealmKey())
            .build();

And mKeyProvider is our helper class that is used to get the key:

public class SharedPrefsKeyProvider implements KeyProvider {

private static final String REALM_KEY = "chats.realm_key";
SharedPreferences mAppSharedPrefs;


public SharedPrefsKeyProvider(SharedPreferences aAppSharedPrefs) {
    mAppSharedPrefs = aAppSharedPrefs;
}

@Override
public byte[] getRealmKey() {
    byte[] key;
    String savedKey = getStringFromPrefs(REALM_KEY);
    if (savedKey.isEmpty()) {
        key = generateKey();
        String keyString = encodeToString(key);
        saveStringToPrefs(keyString);
    } else {
        key = decodeFromString(savedKey);
    }
    return key;
}

@Override
public void removeRealmKey() {
    mAppSharedPrefs.edit().remove(REALM_KEY).apply();
}

@NonNull
private String getStringFromPrefs(String aKey) {
    return mAppSharedPrefs.getString(aKey, "");
}

private void saveStringToPrefs(String aKeyString) {
    mAppSharedPrefs.edit().putString(REALM_KEY, aKeyString).apply();
}

private String encodeToString(byte[] aKey) {
    Timber.d("Encoding Key: %s", Arrays.toString(aKey));
    return Base64.encodeToString(aKey, Base64.DEFAULT);
}

private byte[] decodeFromString(String aSavedKey) {
    byte[] decoded = Base64.decode(aSavedKey, Base64.DEFAULT);
    Timber.d("Decoded Key: %s", Arrays.toString(decoded));
    return decoded;
}

private byte[] generateKey() {
    byte[] key = new byte[64];
    new SecureRandom().nextBytes(key);
    return key;
}
}

A KeyProvider is just a custom interface. An example of KeyProvider can be:

package xxx.com;

interface KeyProvider {
    byte[] getRealmKey();

    void removeRealmKey();
}
like image 113
Gaket Avatar answered Dec 29 '22 10:12

Gaket


AES 256 encryption is symmetric Encryption, try RSA encryption which is asymmetric. And if you are trying to encrypt sensitive user data to store in preferences or sqlite, i would suggest you try Android keystore system.

The Android Keystore system lets you store cryptographic keys in a container to make it more difficult to extract from the device. Once keys are in the keystore, they can be used for cryptographic operations with the key material remaining non-exportable.

check my sample gist to achieve this encryption and decryption here.

And better part is it works on android 18 and above.

like image 22
Shahbaz sultan Avatar answered Dec 29 '22 10:12

Shahbaz sultan