0

我在我的项目中使用 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 创建哪个主密钥,可以删除/丢失。然后 Tink 的 keyset(key) 将无法使用。有没有办法保留主密钥的备份或从用户输入或任何其他解决方案创建主密钥?

注意:AWS KMS 或 GCP KMS 不是我的解决方案。作为密码学的新手,任何建议/建议将不胜感激。

4

1 回答 1

0

我第一次遇到的 Tink 库是使用我的应用程序来解码我们合资伙伴 IP 的受保护 SNMP SMI 树(我们的密文),然后才能将其用于 SNMP OID 操作。我发现我需要为相同的密文保留相同的主密钥。

因此,KeysetHandle.generateNew()每次打开我的应用程序时执行该方法不再是一种选择,因为它会生成一个新的主密钥,该密钥不再适用于存储在应用程序私有文件夹中的现有密文。

我发现 Tink 库允许我们以我们选择的密钥集文件格式保存主密钥,然后我们可以在我们的应用程序中使用它来为应用程序的密钥集句柄重新加载相同的主密钥。

    String keysetFileName =
        StorageUtils.getPrivateKeyPath()
            + File.separator + "smi.json";

    //write it as a file
    CleartextKeysetHandle
        .write(keysetHandle, JsonKeysetWriter.withFile(new File(keysetFileName)));

要将其重新加载到键集句柄中,我们使用以下代码:

    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对象中。

于 2021-12-05T04:06:14.280 回答