我想知道如何在 Android 中安全地存储加密密钥?保护加密和秘密密钥的最佳方案是什么?
我想知道如何在 Android 中安全地存储加密密钥?保护加密和秘密密钥的最佳方案是什么?
您不能将加密密钥放在您的 apk 文件中。您可能希望将其保存在远程服务器中并使用服务器解密。或者,您可能会通过对密钥进行编码并将其保存在不明显的地方而让其他人感到困难。但是对此没有防弹解决方案。
没有办法将您的私有 api 密钥安全地保存到代码中。但是您可以使用 NDK 来安全地保存私钥。从 NDK 获取密钥并非易事。使用 NDK 示例保护密钥
听起来您想要EncryptedSharedPreferences或EncryptedFile。这两个都使用AndroidKeyStore。下面的代码片段实际上回答了“如何使用 AndroidKeystore 加密文件或存储加密密钥?”的问题。
确保包含implementation "androidx.security:security-crypto:1.0.0-rc02"
在您的应用程序build.gradle
文件中。
加密密钥和值的SharedPreferences的实现。
String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
"secret_shared_prefs",
masterKeyAlias,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
// use the shared preferences and editor as you normally would
SharedPreferences.Editor editor = sharedPreferences.edit();
您可以像这样存储加密密钥:
// generate random symmetric key
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey symkey = keyGen.generateKey();
String alias = "your encryption key";
// store symmetric key
byte[] encodedSymmetricKey = symkey.getEncoded();
SharedPreferences.Editor edit = sharedPreferences.edit();
String base64EncodedSymmetricKey = new String(Base64.getEncoder().encode(encodedSymmetricKey));
edit.putString(alias, base64EncodedSymmetricKey);
edit.commit();
// retrieve symmetric key
String raw = sharedPreferences.getString(alias, null);
byte[] symKey = Base64.getDecoder().decode(raw);
SecretKeySpec spec = new SecretKeySpec(symKey, "AES");
assert(spec.equals(symkey));
// use your encryption key
虽然使用EncryptedFile会好得多。
用于创建和读取加密文件的类。
String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
File file = new File(context.getFilesDir(), "secret_data");
EncryptedFile encryptedFile = EncryptedFile.Builder(
file,
context,
masterKeyAlias,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();
// write to the encrypted file
FileOutputStream encryptedOutputStream = encryptedFile.openFileOutput();
// read the encrypted file
FileInputStream encryptedInputStream = encryptedFile.openFileInput();
注意:
主密钥一旦创建,就是不变的。因此,即使在手机重启后,您的应用程序仍然能够加密/解密文件。
您可以使用 Android Keystore 系统来存储和检索敏感信息。阅读这篇 5 分钟的文章,了解它是如何工作的。 使用Android Keystore系统存储和检索敏感信息
根据您的评论,您需要使用当前 Android 版本和旧版本的本地密钥加密数据
Android Keystore旨在生成和保护您的密钥。但是它不适用于低于 18 的 API 级别,并且在 API 级别 23 之前它有一些限制。
您将需要一个随机对称加密密钥,例如 AES。AES 密钥用于加密和解密您的数据。我将总结您根据 Android API 级别安全生成和存储它的选项。
API 级别 < 18:Android 密钥库不存在。向用户请求密码,从密码推导出加密密钥,缺点是需要在应用程序启动时提示输入密码。加密密钥不存储在设备中。每次启动应用程序时使用密码计算
API 级别 >=18 <23:Android Keystore 可用,无需 AES 支持。使用默认加密提供程序(不使用 AndroidKeystore)生成随机 AES 密钥。生成 RSA 密钥对到 Android Keystore 中,并使用 RSA 公钥加密 AES 密钥。将加密的 AES 密钥存储到 Android SharedPreferences 中。应用程序启动时,使用 RSA 私钥解密 AES 密钥
API 级别 >=23:支持 AES 的 Android 密钥库。使用到 Android Keystore 生成随机 AES 密钥。您可以直接使用它。
加密可以使用
AES/CBC/PKCS7Padding
算法。它还需要一个随机初始化向量 (IV) 来加密您的数据,但它可以是公开的。备择方案:
API 级别 >14:Android Key Chain:KeyChain 是系统范围的凭证存储。您可以使用可由应用程序使用的私钥安装证书。使用预安装的密钥来加密/解密您的 AES 密钥,如上面的第二种情况所示。
外部令牌:受保护的密钥不存储在设备中。您可以使用包含允许您加密 AES 密钥的私有/公共密钥对的外部令牌。可以使用蓝牙或 NFC 访问令牌