EncryptedSharedPreferenes 是 androidx 下安全组件中的加密类,实现SharedPreferences的键值对加密。
开发者文档中提供了SharedPreferences加密键值对的实例代码,其中使用MasterKeys来进行密钥管理,而在 MasterKeys 的文档中提示该类已废弃,应使用MasterKey.Builder来管理主密钥(版本说明:基于 Jetpack Security 1.1.0-alpha01),示例如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// 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);
|
密钥管理
KeyGenParameterSpec是android.security.keystore中的类,用于指定密钥的参数,相当于先制定一个规范,规范中指明密钥别名、密钥用途、加密模式等密钥属性,然后在生成密钥的时候直接使用指定的规范。我们重点需要关注的是,主密钥的生成和存储,也就是下面调用的MasterKey.Builder方法。
MasterKey.Builder就是用于生成MasterKey的构建器,最终生成密钥的方法是构建器里的build(),那么在build()里面做了什么事情,需要深入到源码里面去看看。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/**
* 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实例,如下
1
2
3
4
5
6
7
8
9
10
11
12
|
public KeyGenParameterSpec build() {
return new KeyGenParameterSpec(
mKeystoreAlias,
mNamespace,
mKeySize,
......
mIsStrongBoxBacked,
mUserConfirmationRequired,
mUnlockedDeviceRequired,
mCriticalToDeviceEncryption);
}
}
|
而后返回到buildOnM()中,调用MasterKeys.getOrCreate(mKeyGenParameterSpec)创建主密钥并返回密钥别名字符串,然后逐级返回上层调用方法。