我在我的项目中使用Google/Tink的确定性对称密钥加密。像这样——
byte[] ciphertext;
Context context = getApplicationContext();
String plainText="Hello World";
try {
DeterministicAeadConfig.register();
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
try {
KeysetHandle keysetHandle = KeysetHandle.generateNew(
KeyTemplates.get("AES256_SIV"));
Log.d("TAG",keysetHandle.toString());
DeterministicAead daead =
keysetHandle.getPrimitive(DeterministicAead.class);
ciphertext = daead.encryptDeterministically(plainText.getBytes(),null);
String c= new String(Base64.getEncoder().encodeToString(ciphertext));
Log.d("TAG",c);
MasterKey mainKey = new MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
Log.d("TAG",mainKey.toString());
String filePath = Environment.getExternalStorageDirectory() + "/my_keyset.json";
String masterKeyUri = "android-keystore://_androidx_security_master_key_";
keysetHandle.write(JsonKeysetWriter.withFile(new File(filePath)),
new AndroidKeystoreKmsClient().getAead(masterKeyUri));
} catch (GeneralSecurityException | IOException e) {
e.printStackTrace();
}
一切正常。现在我为Android keyStore创建的主密钥,如果用户重置手机或发生任何其他事故(其他原因),可能会被删除/丢失。然后叮叮铃的钥匙集(钥匙)将不可用。是否有任何方法可以保留主密钥的备份或从用户输入或任何其他解决方案创建主密钥?
注意:AWS KMS或GCP KMS不是我的解决方案。作为密码学的新手,任何建议/建议都将受到欢迎。
我第一次遇到的Tink库是使用我的应用程序解码我们合资伙伴IP的受保护的SNMP SMI树(我们的密文),然后才能用于SNMP OID操作。我发现我需要为相同的密文保留相同的主密钥。
因此,每次我的应用程序打开时执行KeysetHandle.generateNew()
方法不再是一个选项,因为它生成一个新的主密钥,不再与存储在应用程序私有文件夹中的现有密文一起工作。
我发现Tink库允许我们将主密钥保存为我们选择的keyset文件格式,然后我们可以在我们的应用程序中使用它来为应用程序的keyset句柄重新加载相同的主密钥。
String keysetFileName =
StorageUtils.getPrivateKeyPath()
+ File.separator + "smi.json";
//write it as a file
CleartextKeysetHandle
.write(keysetHandle, JsonKeysetWriter.withFile(new File(keysetFileName)));
要将其重新加载到keyset句柄中,我们使用以下代码:
String keysetFileName =
StorageUtils.getPrivateKeyPath()
+ File.separator + "smi.json";
//read it as a file
keysetHandle =
CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File(keysetFileName)));
请记住,我实际上并没有在设备存储中存储密钥集文件。我使用build.gradle
脚本将密钥集文件的内容复制到应用程序的EncryptedSharedPreferences对象并将其作为字符串检索,如下所示:
// onCreate()
securedSharedPreferences =
StorageUtils.getEncryptedSharedPreferences(context);
securedSharedPreferences.edit()
.putString("key", BuildConfig.SECRET_KEY).apply();
// somewhere else when we need it...
String keysetFileName =
securedSharedPreferences.getString("key", null);
//read it as a string
keysetHandle =
CleartextKeysetHandle.read(JsonKeysetReader.withString(keysetFileName));
上面的方法仍然是不安全的,因为我们可能在我们的代码中暴露BuildConfig.SECRET KEY
。理想的方法来处理这个问题是问我们的用户加载键盘文件并将其保存在安全EncryptedSharedPreferences对象。