本文譯自Encrypting Shared Preferences with the AndroidX Security Library,介紹了AndroidX安全庫中EncryptedSharedPreferences的使用。備注:僅支持minSdkVersion 23及以上。
本文首發(fā):http://yuweiguocn.github.io/
《離思五首·其四》
曾經(jīng)滄海難為水,除卻巫山不是云。
取次花叢懶回顧,半緣修道半緣君。
-唐代,元稹
Android框架給我們提供了SharedPreferences,它是一個(gè)用于存儲小量鍵值數(shù)據(jù)很好的工具。當(dāng)存儲一些敏感數(shù)據(jù),重要的是SharedPreferences存儲的數(shù)據(jù)是明文的。我們應(yīng)該加密敏感的數(shù)據(jù)不要讓它被窺視。我們可以怎樣做?
一種方法是我們使用Android密鑰庫自己寫加密包裝SharedPreferences。不幸的是這會相當(dāng)復(fù)雜并且涉及大量配置。另一種方法是使用第三方庫,這意味著我們需要花時(shí)間找到一個(gè)合適的。值得慶幸的是AndroidX安全庫最近被添加,這讓min-sdk為23+的應(yīng)用存儲加密SharedPreferences變得容易和方便。
詳細(xì)使用
首先在module的build.gradle文件中添加依賴。
implementation "androidx.security:security-crypto:1.0.0-alpha02"
這是在寫本文時(shí)的最新版本。查看library’s releases page獲取最新版本。
需要注意的是這個(gè)庫當(dāng)前是alpha階段。這意味著雖然功能是穩(wěn)定的,部分API在后續(xù)版本可能被修改或移除。
添加了依賴之后,下一步是在Android KeyStore創(chuàng)建一個(gè)加密master key和store。安全庫提供了一個(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ī)范,如果你需要對如何生成密鑰有更多的控制你也可以自定義KeyGenParameterSpec。
最后我們只需要一個(gè)EncryptedSharedPreferences實(shí)例,它對SharedPreferences進(jìn)行了包裝并且為我們處理所有的加密。不同于SharedPreferences,我們可以從Context#getSharedPreferences或Activity#getPreferences獲取,我們需要創(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。它們是庫提供的唯一的選項(xiàng)。
創(chuàng)建了EncryptedSharedPreferences實(shí)例后,可以使用它像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"
再次檢查結(jié)果
我們怎樣知道數(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被加密了并且存儲了兩個(gè)keysets,一個(gè)是shared preference的keys另一個(gè)是values。Keysets包含加密和解密shared preference數(shù)據(jù)的key。之前創(chuàng)建的master key用于加密這些keysets,這樣它們就可以和提供的數(shù)據(jù)一起存儲在shared preference文件中。
結(jié)語
Android的SharedPreferences對于存儲key-value數(shù)據(jù)是一個(gè)很有用的工具,對于敏感數(shù)據(jù),這是一個(gè)很好的加密它的方法。最近的AndroidX安全庫是一個(gè)受歡迎的新功能,它為我們提供了一個(gè)簡單易用的加密方案。