When storing local data in a mobile application, it is common to use a database that can be encrypted. When encryption of this database is enabled, the encryption key must be protected properly.

## Why is this an issue?

Mobile applications often need to store data (which might be sensitive) locally. For Android, there exist several libraries that simplify this process by offering a feature-rich database system. SQLCipher and Realm are examples of such libraries. These libraries often add support for database encryption, to protect the contents from being read by other apps or by attackers.

When using encryption for such a database, it is important that the encryption key stays secret. If this key is hardcoded in the application, then it should be considered compromised. The key will be known by anyone with access to the application’s binary code or source code. This means that the sensitive encrypted data can be decrypted by anyone having access to the binary of the mobile application.

Furthermore, if the key is hardcoded, it is the same for every user. A compromise of this encryption key implicates every user of the app.

The encryption key is meant to stay secret and should not be hard-coded in the application as it would mean that:

### What is the potential impact?

If an attacker is able to find the encryption key for the mobile database, this can potentially have severe consequences.

#### Theft of sensitive data

If a mobile database is encrypted, it is likely to contain data that is sensitive for the user or the app publisher. For example, it can contain personally identifiable information (PII), financial data, login credentials, or other sensitive user data.

By not protecting the encryption key properly, it becomes very easy for an attacker to recover it and then decrypt the mobile database. At that point, the theft of sensitive data might lead to identity theft, financial fraud, and other forms of malicious activities.

## How to fix it in Realm

### Code examples

In the example below, a local database is opened using a hardcoded key. To fix this, the key is moved to a secure location instead and retrieved using a `getKey()` method.

#### Noncompliant code example

    String key = "gb09ym9ydoolp3w886d0tciczj6ve9kszqd65u7d126040gwy86xqimjpuuc788g";
    RealmConfiguration config = new RealmConfiguration.Builder();
        .encryptionKey(key.toByteArray()) // Noncompliant
        .build();
    Realm realm = Realm.getInstance(config);

#### Compliant solution

    RealmConfiguration config = new RealmConfiguration.Builder()
        .encryptionKey(getKey())
        .build();
    Realm realm = Realm.getInstance(config);

### How does this work?

#### Using Android’s builtin key storage options

The Android Keystore system allows apps to store encryption keys in a container that is protected on a system level. Additionally, it can restrict when and how the keys are used. For example, it allows the app to require user authentication (for example using a fingerprint) before the key is made available. This is the recommended way to store cryptographic keys on Android.

#### Dynamically retrieving encryption keys remotely

As user devices are less trusted than controlled environments such as the application backend, the latter should be preferred for the storage of encryption keys. This requires that a user’s device has an internet connection, which may not be suitable for every use case.

### Going the extra mile

#### Avoid storing sensitive data on user devices

In general, it is always preferable to store as little sensitive data on user devices as possible.

Of course, some sensitive data always has to be stored on client devices, such as the data required for authentication. In this case, consider whether the application logic can also function with a hash (or otherwise non-reversible form) of that data. For example, if an email address is required for authentication, it might be possible to use and store a hashed version of this address instead.

## How to fix it in SQLCipher

### Code examples

In the example below, a local database is opened using a hardcoded key. To fix this, the key is moved to a secure location instead and retrieved using a `getKey()` method.

#### Noncompliant code example

    String key = "gb09ym9ydoolp3w886d0tciczj6ve9kszqd65u7d126040gwy86xqimjpuuc788g";
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase("test.db", key, null); // Noncompliant

#### Compliant solution

    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase("test.db", getKey(), null);

### How does this work?

#### Using Android’s builtin key storage options

The Android Keystore system allows apps to store encryption keys in a container that is protected on a system level. Additionally, it can restrict when and how the keys are used. For example, it allows the app to require user authentication (for example using a fingerprint) before the key is made available. This is the recommended way to store cryptographic keys on Android.

#### Dynamically retrieving encryption keys remotely

As user devices are less trusted than controlled environments such as the application backend, the latter should be preferred for the storage of encryption keys. This requires that a user’s device has an internet connection, which may not be suitable for every use case.

### Going the extra mile

#### Avoid storing sensitive data on user devices

In general, it is always preferable to store as little sensitive data on user devices as possible.

Of course, some sensitive data always has to be stored on client devices, such as the data required for authentication. In this case, consider whether the application logic can also function with a hash (or otherwise non-reversible form) of that data. For example, if an email address is required for authentication, it might be possible to use and store a hashed version of this address instead.

## Resources

### Documentation

- Android Documentation - Android Keystore system
- Android Documentation - Security tips - User data
- OWASP Mobile Application Security Testing Guide - Data Storage on Android

### Standards

- OWASP - Top 10 2021 Category A2 - Cryptographic Failures
- OWASP - Top 10 2021 Category A4 - Insecure Design
- OWASP - Mobile AppSec Verification Standard - Data Storage and Privacy Requirements
- OWASP - Mobile Top 10 2016 Category M2 - Insecure Data Storage
- OWASP - Top 10 2017 Category A3 - Sensitive Data Exposure
- OWASP - Top 10 2017 Category A6 - Security Misconfiguration
- CWE - CWE-311 - Missing Encryption of Sensitive Data
- CWE - CWE-321 - Use of Hard-coded Cryptographic Key