(譯)使用AndroidX安全庫加密SharedPreferences

本文譯自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è)簡單易用的加密方案。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容