(译)使用AndroidX安全库加密SharedPreferences

本文译自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安全库是一个受欢迎的新功能,它为我们提供了一个简单易用的加密方案。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,192评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,858评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,517评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,148评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,162评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,905评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,537评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,439评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,956评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,083评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,218评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,899评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,565评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,093评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,201评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,539评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,215评论 2 358

推荐阅读更多精彩内容