Back to Blog
By AriesZhou · · 4 min read

Understanding EncryptedSharedPreferences: Secure Storage on Android

Android

Storing sensitive data in SharedPreferences is not secure. EncryptedSharedPreferences is Android’s officially recommended secure storage solution. How does it protect data even if the phone is rooted?

In Android development, SharedPreferences is the most commonly used lightweight storage solution, but its plaintext nature makes it unsuitable for sensitive data. Once tokens, user information, or keys are extracted, the consequences are severe. EncryptedSharedPreferences exists to solve this problem.

The developer documentation includes an example that encrypts SharedPreferences key-value pairs using MasterKeys. The MasterKeys documentation marks that class as deprecated and recommends MasterKey.Builder instead. The following example is based on Jetpack Security 1.1.0-alpha01:

 // this is equivalent to using deprecated MasterKeys.AES256_GCM_SPEC
 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
         MASTER_KEY_ALIAS,
         KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
         .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
         .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
         .setKeySize(KEY_SIZE)
         .build();
 MasterKey masterKey = new MasterKey.Builder(MainActivity.this)
         .setKeyGenParameterSpec(spec)
         .build();
 EncryptedSharedPreferences.create(
         MainActivity.this,
         "your-app-preferences-name",
         masterKey, // masterKey created above
         EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
         EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM);

Key management

KeyGenParameterSpec is a class in android.security.keystore used to specify key parameters. It is like defining a specification first. The spec indicates key attributes such as key alias, key purpose, and encryption mode, and then the key is generated directly using that spec. What we need to focus on is the generation and storage of the master key, specifically the MasterKey.Builder method called below.

MasterKey.Builder creates a MasterKey, with build() performing the final construction. The source code shows what happens inside:

/**
* Builds a {@link MasterKey} from this builder.
* @return The master key.
*/
@NonNull
public MasterKey build() throws GeneralSecurityException, IOException {
	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
		return buildOnM();
	} else {
		return new MasterKey(mKeyAlias, null);
	}
}

private MasterKey buildOnM() throws GeneralSecurityException, IOException {
  ...
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && mRequestStrongBoxBacked) {
    if (mContext.getPackageManager().hasSystemFeature(
      PackageManager.FEATURE_STRONGBOX_KEYSTORE)) {
      builder.setIsStrongBoxBacked(true);
    }
  }
  mKeyGenParameterSpec = builder.build();//完成KeyGenParameterSpec的构建
  ...
  @SuppressWarnings("deprecation")
    String keyAlias = MasterKeys.getOrCreate(mKeyGenParameterSpec);//按照Spec指定的参数创建密钥
  return new MasterKey(keyAlias, mKeyGenParameterSpec);
}

Using Android 9.0 as a reference, build() calls buildOnM(). That method checks whether the system supports the hardware-backed StrongBox Keystore and, when available, calls setIsStrongBoxBacked(true) to protect the key with the StrongBox secure chip. The parameter setup ends by building and returning a KeyGenParameterSpec instance:

public KeyGenParameterSpec build() {
	return new KeyGenParameterSpec(
    mKeystoreAlias,
    mNamespace,
    mKeySize,
    ......
    mIsStrongBoxBacked,
    mUserConfirmationRequired,
    mUnlockedDeviceRequired,
    mCriticalToDeviceEncryption);
  }
}

Then it returns to buildOnM(), calls MasterKeys.getOrCreate(mKeyGenParameterSpec) to create the master key and return the key alias string, then returns up the call chain level by level.

graph TB
    subgraph 应用层
        A[EncryptedSharedPreferences]
    end

    subgraph 加密层
        A -->|AES256_SIV| B[PrefKeyEncryption]
        A -->|AES256_GCM| C[PrefValueEncryption]
    end

    subgraph 密钥层
        D[MasterKey.Builder] --> E[KeyGenParameterSpec]
        E --> F[Android Keystore]
        F -->|硬件支持| G[StrongBox Keystore]
    end

    B --> D
    C --> D

Core flow

ComponentRole
MasterKeyManages the master key lifecycle
KeyGenParameterSpecDefines key parameters (algorithm, length, purpose)
Android KeystoreHardware/software module for secure key storage
AES256_SIVKey encryption (deterministic encryption)
AES256_GCMValue encryption (authenticated)

StrongBox Keystore requires hardware support (Android 9+) and provides a higher level of security protection, with keys stored in a dedicated secure chip.


Summary

  • EncryptedSharedPreferences automatically handles key/value encryption, using Android Keystore to protect the master key
  • MasterKey. Builder is the recommended way to manage the master key, with support for StrongBox hardware encryption
  • AES256_SIV is used to encrypt keys (deterministic encryption required to support lookups)
  • AES256_GCM is used to encrypt values (providing confidentiality and integrity)

Even if the device is rooted, as long as the user has set a lock screen password, the key will not be exposed. This is currently the best practice for protecting sensitive data on Android.