我想知道如何在Android中安全地存储加密密钥?保护加密和密钥的最佳方案是什么?
答案 0 :(得分:24)
根据您的评论,您需要使用当前Android版本和旧版本的本地密钥加密数据
Android Keystore旨在生成并保护您的密钥。但它不适用于低于18的API级别,并且在API级别23之前有一些限制。
您需要一个随机对称加密密钥,例如AES。 AES密钥用于加密和解密数据。我将总结您根据Android API级别安全生成和存储它的选项。
API级别< 18:Android Keystore不存在。向用户请求密码,从密码中获取加密密钥,缺点是您需要在应用程序启动时提示输入密码。加密密钥不存储在设备中。每次使用密码
API级别> = 18< 23:不支持AES的Android密钥库。使用默认加密提供程序(不使用AndroidKeystore)生成随机AES密钥。在Android Keystore中生成RSA密钥对,并使用RSA公钥加密AES密钥。将加密的AES密钥存储到Android SharedPreferences中。应用程序启动时,使用RSA私钥解密AES密钥
API级别> = 23:支持AES的Android密钥库。使用Android Keystore生成随机AES密钥。您可以直接使用它。
加密可以使用AES/CBC/PKCS7Padding
算法。它还需要一个随机初始化向量(IV)来加密您的数据,但它可以是公共的。
替代方案:
API级别> 14:Android密钥链:KeyChain是一个系统范围的凭据存储。您可以使用可供应用程序使用的私钥安装证书。使用预安装的密钥加密/解密您的AES密钥,如上面的第二种情况所示。
外部令牌:受保护的密钥未存储在设备中。您可以使用包含私钥/公钥对的外部令牌,该令牌允许您加密AES密钥。可以使用蓝牙或NFC
答案 1 :(得分:3)
您不能将加密密钥放在apk文件中。您可能希望将其保留在远程服务器中并使用服务器进行解密。或者通过对密钥进行编码并将其保存在非显而易见的位置,可能会使其他人难以理解。但是没有针对此的防弹解决方案。
答案 2 :(得分:1)
无法将私人API密钥安全地保存到代码中。但你可以使用 NDK可以安全地保存私钥。从NDK获取密钥并非易事。 Secue Key With NDK Example
答案 3 :(得分:1)
听起来像您想要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();
注释:
主密钥一旦创建,便保持不变。因此,即使在电话重启后,您的应用仍然可以加密/解密文件。
答案 4 :(得分:0)
您可以使用Android Keystore系统存储和检索敏感信息。 阅读这篇5分钟的文章,了解它的工作原理。 Using the Android Keystore system to store and retrieve sensitive information