如何在设备上安全地加密数据并使用 Android KeyStore?
我们在 Android 中处理大量数据。来自一个活动的数据用于不同的活动或片段。例如,当某些数据发生变化时,我们可以修改应用程序的 UI。因此,主要概念是在数据和应用程序的 UI 之间进行有效的通信,我们都知道最理想的方式是使用 Android Jetpack 的 LiveData。
Jetpack 中的安全库
我们将使用 Jetpack 安全库,它有良好的支持,值得信赖,它也在 2019 年推出,使其相对较新。它甚至允许保护 shared_prefs 和其他数据。它通过在出色的加密和快速性能之间取得平衡来保持可靠的安全性。所以我们只需要使用 Jetpack Security 库。当 Android 操作系统非常安全并且我们有一个单独的基于文件的加密解决方案时,为什么要使用这个 Android Jetpack 安全库?
造成这种情况的原因有很多,包括:
- 即使你有全盘加密,root Android 设备上的文件系统也会被解锁,攻击者很容易访问数据。
- 另一个论点可能是您甚至不希望您的用户访问您的应用程序的密钥或令牌。
dependencies {
...
implementation 'androidx.security:security-crypto:{latest-version}'
}
管理人员
我们需要跟踪我们在 Android 应用程序中使用的密钥。所以,在 Android 上,我们有一个叫做 Android Keystore System 的东西,它可以保护我们的密钥不被其他人利用。我们在 Jetpack Security 中有一个 MasterKeys 类,它允许我们构造一个私钥(默认情况下,使用 AES256)。本质上,此类提供了用于从 Android Keystore 创建和检索主密钥的易于使用的方法。
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
在这种情况下,我们使用没有填充的块模式 GCM SPEC。如果您希望加密一小段密钥大小的数据,则不需要任何填充或阻塞。当要加密的数据大于密钥的大小时,使用填充和阻塞。
文件加密
您可以使用 Jetpack 安全库加密您的应用程序文件。为了处理任何大小的文件,它采用流式 AES 算法。它就像创建文件然后将其转换为加密文件一样简单。如果要在获取加密文件后将数据写入加密文件,可以使用 openFileOutput() 方法,如果要从加密文件中读取数据,可以使用 openFileInput() 方法。代码如下:
val gfgKeyAlias= MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
val file = File("ANY_FILE_NAME")
val encryptedFile = EncryptedFile.Builder(
file,
applicationContext,
gfgKeyAlias,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()
encryptedFile.openFileOutput().use { outputStream ->
}
SharedPreferences 的加密
我们使用 SharedPreferences 来存储我们的数据,因为它易于使用,但它也使攻击者可以轻松地从 SharedPreferences 获取密钥和值。因此,我们需要加密我们的 SharedPreferences 数据,这可以通过适用于 Android 6.0 及更高版本的 EncryptedSharedPreferences 来实现。只需从 AndroidKeyStore 创建或检索主密钥即可使用 EncryptedSharedPreference:
val gfgKeyAlias= MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
获取主密钥后,创建一个 EncryptedSharedPreferences 实例,如下所示:
val anySharedPrefs= EncryptedSharedPreferences.create(
"your_name_of_shared_prefs",
masterKeyAlias,
applicationContext,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
最后,像往常一样,您可以从 EncryptedSharedPreferences 存储和读取数据:
val KEY_DATA = "SHARED_DATA"
val dataToSave = "Some raw values"
// storing the data
anySharedPrefs.edit()
.putString(SHARED_DATA, someDataBound)
.apply()
// reading
val sharedData = anySharedPrefs.getString(SHARED_DATA, "")