javaencryptionjasyptkeyczartink

How to easily encrypt and decrypt a String using Tink?


Until now, I was using jasypt to encrypt a string before storing it on disk on app closing, and later when opening the app for decrypt the string after retrieving it from disk.

It was super easy with jasypt, this was the code:

private static final String JASYPT_PWD = "mypassword";

public static String encryptString(String string) {
    StrongTextEncryptor textEncryptor = new StrongTextEncryptor();
    textEncryptor.setPassword(JASYPT_PWD);
    return textEncryptor.encrypt(string);
}

public static String decryptString(String string) {
    StrongTextEncryptor textEncryptor = new StrongTextEncryptor();
    textEncryptor.setPassword(JASYPT_PWD);
    return textEncryptor.decrypt(string);
}

It worked perfectly, but now, jasypt is deprecated and I'm trying to migrate to the Google Tink library, the problem is that Google Tink seems to be much more complex for just encrypt and decrypt a string as easily as with jasypt.

I can't find in the Tink repo readme the simple way to encrypt and decrypt a string, just can find more complex operations which in fact I can't understand because my knowledge in encryption is totally empty. Because of that I was using a very easy library like jasypt.

This is the Tink repo: https://github.com/Google/tink

Is there an easy way, similar to my jasypt code, to encrypt and decrypt a string with Tink?


Solution

  • Note: The post refers to Tink version 1.2.2. The posted code is partially incompatible with later versions.

    The StrongTextEncryptor-class in your jasypt-example-code uses the PBEWithMD5AndTripleDES-algorithm. This algorithm uses the symmetric-key block cipher Triple DES and derives the key from the password using the MD5 hash function. The latter is called password-based encryption and this isn't supported in Tink (at least as at 08/2018), see How to create symmetric encryption key with Google Tink?. Thus, it's impossible in Tink to encrypt by means of a password and the concept used so far in the jasypt-code couldn't be implemented. If password-based encryption is to be used in any case that is a deal-breaker for Tink.

    Another approach is to directly use a key. Tink has the AesGcmJce-class which uses AES-GCM for encryption. Here the key must have a length of either 128 Bit or 256 bit:

    String plainText = "This is a plain text which needs to be encrypted!";
    String aad = "These are additional authenticated data (optional)";
    String key = "ThisIsThe32ByteKeyForEncryption!"; // 256 bit
        
    // Encryption
    AesGcmJce agjEncryption = new AesGcmJce(key.getBytes());
    byte[] encrypted = agjEncryption.encrypt(plainText.getBytes(), aad.getBytes());
    
    // Decryption
    AesGcmJce agjDecryption = new AesGcmJce(key.getBytes());
    byte[] decrypted = agjDecryption.decrypt(encrypted, aad.getBytes());
    

    The use is simple and furthermore the used cipher (AES-GCM) is secure. However, the Tink-developers themselves don't recommend this approach because the AesGcmJce-class belongs to the com.google.crypto.tink.subtle-package which may change at any time without further notice, (see also here, section Important Warnings). Therefore, also this approach isn't optimal.

    Well, how does Tink typically use symmetric encryption? This is shown in the following snippet from:

    String plainText = "This is a plain text which needs to be encrypted!";
    String aad = "These are additional authenticated data (optional)";
    
    AeadConfig.register();
        
    KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES256_GCM);
    Aead aead = AeadFactory.getPrimitive(keysetHandle);
        
    // Encryption
    byte[] ciphertext = aead.encrypt(plainText.getBytes(), aad.getBytes());
    
    // Decryption
    byte[] decrypted = aead.decrypt(ciphertext, aad.getBytes());
    

    The generateNew-method generates a new key. However, the creation isn't based on a password or a byte-sequence and because of this, a key generated for the encryption can't be easily reconstructed for decryption. Therefore, the key used for encryption has to be persisted to a storage system, e.g. the file system, so it can be used later for decryption. Tink allows the storing of cleartext keys (which is of course not recommended). A more secure approach is the encryption of keys with master keys stored in a remote key management system (this is in more detail explained Tink's JAVA-HOWTO, sections Storing Keysets and Loading Existing Keysets).

    Tink's key management concept (with the aim of avoiding accidental leakage of sensitive key material) makes it also somehow cumbersome (this may change in later versions). That's why I said in my comment that I'm not sure if Tink fits your ideas concerning simplicity.