如何解决使用AndroidKeysetManager
我正在android项目中使用 'androidx.security:security-crypto:1.1.0-alpha02 '。它适用于文件加密/解密。我已经在需要使用身份验证的硬件密钥库中设置了一个主密钥。
private static MasterKey getOrCreateMasterKey(final Application application)
throws IOException,GeneralSecurityException {
return new MasterKey.Builder(application)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.setUserAuthenticationRequired(true,3600)
.setRequestStrongBoxBacked(true)
.build();
}
安全性API 自动生成了我认为是 Tink 密钥集文件,适用于Android共享首选项
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="__androidx_security_crypto_encrypted_file_keyset__">129c0157ebfb4adffbd04e3ad4cd44336c5e89c3fe455d949031436c63789092960d8b93053de8e1fd855b61047a1d496ff26006958982e6a90f950746dbc7afc6b252bf51149b8404e5ff8616f9911ad54e153bf2c2c21eb571ca11223c77edd01b488465f7ab286ffd9054d7e396d1b2a187152dd9bf76ee5df9a5faefd5e5b7ec159fa04a860f9d237f833763f6c42acbcdedfb06a575264f948049b3841a4f08c094920612480a3d747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e41657347636d486b646653747265616d696e674b6579100118c09492062003</string>
</map>
如果我理解正确,那就是用于加密文件的实际DEK。
现在的问题是,如果我要导出加密文件,将无法在其他设备上解密,因为硬件密钥库中的主密钥不可导出。
最好的解决方案是使用PBKDF2将密钥集内的 DEK 导出,并将其解密为另一个设备密钥集。
一个可选的解决方案是在密钥库之外创建主密钥材料,用另一个KeyStore密钥对其进行保护,并在需要时使用PBKDF2导出它。这将打破jetpack安全性库的逻辑流程。
我尝试导入 Tink 库 'com.google.crypto.tink:tink-android:1.5.0' ,因为安全API没有针对该用例的实现,因此我可以直接开始管理密钥集。
AndroidKeysetManager manager = new AndroidKeysetManager.Builder()
.withSharedPref(getApplicationContext(),"my_keyset_name","my_pref_file_name")
.withKeyTemplate(AesGcmKeyManager.aes256GcmTemplate())
.withMasterKeyUri(masterKeyUri)
.build();
无论如何,我找不到使用此管理器解密密钥集中的密钥的方法,以便能够使用密码对其进行加密并正确导出。
您知道如何面对这个问题吗?
解决方法
我在官方的“ Tink HOW-TO”上找到了解决方案: https://github.com/google/tink/blob/master/docs/JAVA-HOWTO.md
有点违反直觉。
因此,这是一个可能的功能,用于导出先前使用AndroidKeyStore在harware安全元素内部生成的主密钥加密的特定密钥集:
public byte[] exportKeyset(final String keysetName,final String password) throws
IOException,GeneralSecurityException {
AndroidKeysetManager backupKeySetManager = new AndroidKeysetManager.Builder()
.withSharedPref(application,keysetName,"my_pref_file_name")
.withKeyTemplate(AesGcmHkdfStreamingKeyManager.aes256GcmHkdf4KBTemplate())
.withMasterKeyUri(MASTER_KEY_URI)
.build();
try(final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()){
final byte[] saltBytes = new byte[16];
new SecureRandom().nextBytes(saltBytes);
final byte[] encryptionKeyMaterial =
SecretKeyFactory.getInstance("PBKDF2withHmacSHA512")
.generateSecret(new PBEKeySpec(password.toCharArray(),saltBytes,3000000,256)).getEncoded();
final AesGcmJce aesGcmJce = new AesGcmJce(encryptionKeyMaterial);
CleartextKeysetHandle.write(backupKeySetManager.getKeysetHandle(),BinaryKeysetWriter.withOutputStream(byteArrayOutputStream));
final byte[] clearKeyset = byteArrayOutputStream.toByteArray();
byteArrayOutputStream.reset();
byteArrayOutputStream.write(aesGcmJce.encrypt(clearKeyset,saltBytes));
byteArrayOutputStream.write(saltBytes);
return byteArrayOutputStream.toByteArray();
}catch (IOException e){
throw e;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。