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)
创建主密钥并返回密钥别名字符串,然后逐级返回上层调用方法。