1

I am using Google/Tink's Deterministic symmetric key encryption in my project. Like this-

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();
                }

Everything is okay. Now which master key I am creating for Android keyStore, can be deleted/lost if the user reset the phone or any other accident occur (other reasons). Then Tink's keyset(key) will be un-usable. Is there any way to keep backup of master key or create the master key from user input or any other solution?

Note: AWS KMS or GCP KMS isn't a solution for me. As a newcomer in cryptography, any suggestion/advice will be appreciated.

Richard Wilson
  • 297
  • 4
  • 17
Tanmoy
  • 11
  • 3

1 Answers1

0

My first Tink library encounter was using my app to decode a protected SNMP SMI tree (our ciphertext) of our JV partner's IP before it could be utilized for SNMP OID operations. I discovered that I needed to keep the same master key for the same ciphertext.

As a result, executing the KeysetHandle.generateNew() method every time my app opens is no longer an option because it generates a new master key that no longer works with the existing ciphertext stored in the app private folder.

I discovered that the Tink library allows us to save the master key in a keyset file format of our choice, which we can then utilize in our app to reload the same master key for the app's keyset handle.

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

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

To reload it into the keyset handle, we use this code:

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

    //read it as a file
    keysetHandle =
        CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File(keysetFileName)));

Please keep in mind that I do not actually store the keyset file in the device storage. I use the build.gradle script to copy the keyset file's content into the app's EncryptedSharedPreferences object and retrieve it as a string as shown below:

    // 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));

The above approach is still insecure because we may expose BuildConfig.SECRET KEY in our code. The ideal method to handle this problem is to ask our user to load the keyset file and save it in the safe EncryptedSharedPreferences object.

ecle
  • 3,952
  • 1
  • 18
  • 22