本文譯自Encrypting Shared Preferences with the AndroidX Security Library算墨,介紹了AndroidX安全庫(kù)中EncryptedSharedPreferences的使用汁雷。備注:僅支持minSdkVersion 23及以上侠讯。
本文首發(fā):http://yuweiguocn.github.io/
《離思五首·其四》
曾經(jīng)滄海難為水,除卻巫山不是云熬苍。
取次花叢懶回顧袁翁,半緣修道半緣君。
-唐代柄驻,元稹
Android框架給我們提供了SharedPreferences焙压,它是一個(gè)用于存儲(chǔ)小量鍵值數(shù)據(jù)很好的工具。當(dāng)存儲(chǔ)一些敏感數(shù)據(jù)野哭,重要的是SharedPreferences存儲(chǔ)的數(shù)據(jù)是明文的幻件。我們應(yīng)該加密敏感的數(shù)據(jù)不要讓它被窺視绰沥。我們可以怎樣做?
一種方法是我們使用Android密鑰庫(kù)自己寫加密包裝SharedPreferences零截。不幸的是這會(huì)相當(dāng)復(fù)雜并且涉及大量配置秃臣。另一種方法是使用第三方庫(kù),這意味著我們需要花時(shí)間找到一個(gè)合適的绍撞。值得慶幸的是AndroidX安全庫(kù)最近被添加,這讓min-sdk為23+的應(yīng)用存儲(chǔ)加密SharedPreferences變得容易和方便章贞。
詳細(xì)使用
首先在module的build.gradle文件中添加依賴非洲。
implementation "androidx.security:security-crypto:1.0.0-alpha02"
這是在寫本文時(shí)的最新版本。查看library’s releases page獲取最新版本败京。
需要注意的是這個(gè)庫(kù)當(dāng)前是alpha階段梦染。這意味著雖然功能是穩(wěn)定的,部分API在后續(xù)版本可能被修改或移除泛粹。
添加了依賴之后肮疗,下一步是在Android KeyStore創(chuàng)建一個(gè)加密master key和store伪货。安全庫(kù)提供了一個(gè)容易的方法處理這個(gè)。將下面的代碼添加到你計(jì)劃創(chuàng)建EncryptedSharedPreferences實(shí)例前面蒙挑。
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
我們指定了一個(gè)默認(rèn)的key巍举,AES256_GCM_SPEC,用于創(chuàng)建master key。雖然推薦使用這個(gè)規(guī)范炭分,如果你需要對(duì)如何生成密鑰有更多的控制你也可以自定義KeyGenParameterSpec剑肯。
最后我們只需要一個(gè)EncryptedSharedPreferences實(shí)例,它對(duì)SharedPreferences進(jìn)行了包裝并且為我們處理所有的加密呀忧。不同于SharedPreferences,我們可以從Context#getSharedPreferences或Activity#getPreferences獲取胰坟,我們需要?jiǎng)?chuàng)建自己的EncryptedSharedPreferences實(shí)例泞辐。
val sharedPreferences = EncryptedSharedPreferences.create(
"shared_preferences_filename",
masterKeyAlias,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
我們指定了shared preferences的文件名咐吼,之前創(chuàng)建的masterKeyAlias,和一個(gè)context厢塘。最后兩個(gè)參數(shù)是key和value加密的scheme肌幽。它們是庫(kù)提供的唯一的選項(xiàng)牍颈。
創(chuàng)建了EncryptedSharedPreferences實(shí)例后煮岁,可以使用它像SharedPreferences一樣讀取和存儲(chǔ)值∫鄙。總而言之步氏,就像下面的代碼一樣:
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"
再次檢查結(jié)果
我們?cè)鯓又罃?shù)據(jù)被加密了荚醒?讓我們看下shared preferences文件中的內(nèi)容。如果你想shared preferences文件中的內(nèi)容侯繁,可以從StackOverflow找到答案泡躯。使用正常的SharedPreferences丽焊,文件內(nèi)容如下:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="some_key">some_data</string>
</map>
正如我們看到的咕别,key和value沒有被加密惰拱。使用EncryptedSharedPreferences,文件內(nèi)容就像這樣:
<?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被加密了并且存儲(chǔ)了兩個(gè)keysets,一個(gè)是shared preference的keys另一個(gè)是values翔冀。Keysets包含加密和解密shared preference數(shù)據(jù)的key纤子。之前創(chuàng)建的master key用于加密這些keysets,這樣它們就可以和提供的數(shù)據(jù)一起存儲(chǔ)在shared preference文件中泽论。
結(jié)語
Android的SharedPreferences對(duì)于存儲(chǔ)key-value數(shù)據(jù)是一個(gè)很有用的工具卡乾,對(duì)于敏感數(shù)據(jù),這是一個(gè)很好的加密它的方法鹦赎。最近的AndroidX安全庫(kù)是一個(gè)受歡迎的新功能误堡,它為我們提供了一個(gè)簡(jiǎn)單易用的加密方案锁施。