Back to Blog
· 2 min read

EncryptedSharedPreferences 解析:Android 安全存储

Android

敏感数据存在 SharedPreferences 里并不安全。EncryptedSharedPreferences 是 Android 官方推荐的安全存储方案,它如何实现「即使手机被Root也能保护数据」?

在 Android 开发中,SharedPreferences 是最常用的轻量级存储方案,但明文存储的特性让它不适合存放敏感数据—— token、用户信息、密钥等一旦被提取,后果不堪设想。EncryptedSharedPreferences 就是来解决这个问题的。

开发者文档中提供了SharedPreferences加密键值对的实例代码,其中使用MasterKeys来进行密钥管理,而在 MasterKeys 的文档中提示该类已废弃,应使用MasterKey.Builder来管理主密钥(版本说明:基于 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);

密钥管理

KeyGenParameterSpecandroid.security.keystore中的类,用于指定密钥的参数,相当于先制定一个规范,规范中指明密钥别名、密钥用途、加密模式等密钥属性,然后在生成密钥的时候直接使用指定的规范。我们重点需要关注的是,主密钥的生成和存储,也就是下面调用的MasterKey.Builder方法。

MasterKey.Builder就是用于生成MasterKey的构建器,最终生成密钥的方法是构建器里的build(),那么在build()里面做了什么事情,需要深入到源码里面去看看。

/**
* 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);
}

我们以 Android 9.0 为参考,build中调用的是 buildOnM(),而在buildOnM()中会检查系统是否支持基于硬件的 StrongBox Keystore,如果支持,则调用setIsStrongBoxBacked(true)以设置该密钥由 StrongBox 安全芯片保护,至此密钥参数设置的最后一步完成,并返回一个KeyGenParameterSpec的实例,build()内容很简单,直接返回一个KeyGenParameterSpec实例,如下

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

而后返回到buildOnM()中,调用MasterKeys.getOrCreate(mKeyGenParameterSpec)创建主密钥并返回密钥别名字符串,然后逐级返回上层调用方法。

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

核心流程

组件作用
MasterKey管理主密钥生命周期
KeyGenParameterSpec定义密钥参数(算法、长度、用途)
Android Keystore安全存储密钥的硬件/软件模块
AES256_SIV密钥加密(确定性加密)
AES256_GCM值加密(带认证)

StrongBox Keystore 需要硬件支持(Android 9+),提供更高级别的安全保护,密钥存储在独立的安全芯片中。


总结

  • EncryptedSharedPreferences 自动完成 key/value 的加密,使用 Android Keystore 保护主密钥
  • MasterKey.Builder 是推荐的方式管理主密钥,支持 StrongBox 硬件加密
  • AES256_SIV 用于加密 key(需要确定性加密以支持查找)
  • AES256_GCM 用于加密 value(提供机密性和完整性)

即使设备被 Root,只要用户设置了锁屏密码,密钥就不会暴露。这是目前 Android 上保护敏感数据的最佳实践。


相关阅读