本文译自Encrypting Shared Preferences with the AndroidX Security Library,介绍了AndroidX安全库中EncryptedSharedPreferences的使用。备注:仅支持minSdkVersion 23及以上。
本文首发:http://yuweiguocn.github.io/
《离思五首·其四》
曾经沧海难为水,除却巫山不是云。
取次花丛懒回顾,半缘修道半缘君。
-唐代,元稹
Android框架给我们提供了SharedPreferences,它是一个用于存储小量键值数据很好的工具。当存储一些敏感数据,重要的是SharedPreferences存储的数据是明文的。我们应该加密敏感的数据不要让它被窥视。我们可以怎样做?
一种方法是我们使用Android密钥库自己写加密包装SharedPreferences。不幸的是这会相当复杂并且涉及大量配置。另一种方法是使用第三方库,这意味着我们需要花时间找到一个合适的。值得庆幸的是AndroidX安全库最近被添加,这让min-sdk为23+的应用存储加密SharedPreferences变得容易和方便。
详细使用
首先在module的build.gradle文件中添加依赖。
implementation "androidx.security:security-crypto:1.0.0-alpha02"
这是在写本文时的最新版本。查看library’s releases page获取最新版本。
需要注意的是这个库当前是alpha阶段。这意味着虽然功能是稳定的,部分API在后续版本可能被修改或移除。
添加了依赖之后,下一步是在Android KeyStore创建一个加密master key和store。安全库提供了一个容易的方法处理这个。将下面的代码添加到你计划创建EncryptedSharedPreferences实例前面。
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
我们指定了一个默认的key,AES256_GCM_SPEC,用于创建master key。虽然推荐使用这个规范,如果你需要对如何生成密钥有更多的控制你也可以自定义KeyGenParameterSpec。
最后我们只需要一个EncryptedSharedPreferences实例,它对SharedPreferences进行了包装并且为我们处理所有的加密。不同于SharedPreferences,我们可以从Context#getSharedPreferences或Activity#getPreferences获取,我们需要创建自己的EncryptedSharedPreferences实例。
val sharedPreferences = EncryptedSharedPreferences.create(
"shared_preferences_filename",
masterKeyAlias,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
我们指定了shared preferences的文件名,之前创建的masterKeyAlias,和一个context。最后两个参数是key和value加密的scheme。它们是库提供的唯一的选项。
创建了EncryptedSharedPreferences实例后,可以使用它像SharedPreferences一样读取和存储值。总而言之,就像下面的代码一样:
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
val sharedPreferences = EncryptedSharedPreferences.create(
"shared_preferences_filename",
masterKeyAlias,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
// storing a value
sharedPreferences
.edit()
.putString("some_key", "some_data")
.apply()
// reading a value
sharedPreferences.getString("some_key", "some_default_value") // -> "some_data"
再次检查结果
我们怎样知道数据被加密了?让我们看下shared preferences文件中的内容。如果你想shared preferences文件中的内容,可以从StackOverflow找到答案。使用正常的SharedPreferences,文件内容如下:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="some_key">some_data</string>
</map>
正如我们看到的,key和value没有被加密。使用EncryptedSharedPreferences,文件内容就像这样:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="ATP1ABa3NIlOap2c7iNkVaUcQmTocrnpkXl0PyI=">AU+p3hwqCgvlDOtIaawFHWVDf4rFsqghM7ivFTEJesrRp19D+zk7tqsqlGZPLAbryHI=</string>
<string name="__androidx_security_crypto_encrypted_prefs_key_keyset__">12a901802f1a5d2fbc5cd3c9b545a89ca8ace8f125f8e601a8ac51929303ead8a2bbdf5428bd054360b97c1727ef93ef63b64f43ceac92156f3aee9402dd247009d9779571c6ceacfcd4e7123665cc9dd94c44c5c2c6241a8de070d365d94010f8affb6097d4b0fec1c628120a8f901c23caa03d32ecc6ce270e3cc3341e6455b87a80474b3818c3ad678faa4199a9a45078b218c89b8c5a8cbd1780a68b4f8196eb5153b6422df2bdfee6541a44089680d49f03123c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e4165735369764b65791001189680d49f032001</string>
<string name="__androidx_security_crypto_encrypted_prefs_value_keyset__">128801da6fdef289b2c6e2933c341b1b3df3b39330671d76df362ba8b0a1d807cdc9d2d4d7bc3062139377e4fa61428f3817c0e368c3196c95fdbcca3c37075e7132abae1fe0f128ceef7278a06a01e0cacf29edc1f3c1c1d37875c27c0cf5d86d0b2bb39efcac84828f664838b77aa4c406028af912e860cad8bff51aca6aaf45167d5ab5c8e57bf05db61a44089cbca7fd04123c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e41657347636d4b65791001189cbca7fd042001</string>
</map>
可以看到key和value被加密了并且存储了两个keysets,一个是shared preference的keys另一个是values。Keysets包含加密和解密shared preference数据的key。之前创建的master key用于加密这些keysets,这样它们就可以和提供的数据一起存储在shared preference文件中。
结语
Android的SharedPreferences对于存储key-value数据是一个很有用的工具,对于敏感数据,这是一个很好的加密它的方法。最近的AndroidX安全库是一个受欢迎的新功能,它为我们提供了一个简单易用的加密方案。
网友评论