1

I am trying to create an encrypted token that is to be sent as an REST API response. The end user then can send the same token during next request to this api, and I can parse it and get some context info (of the previous one).

Since I'm new to cryptography, I felt it's better to pick up Google tink instead of writing the encryption/decryption code by myself. However I'm not able to decrypt correctly.

I am doing the encryption/decryption like the following:

public class CipherUtils {

    public static byte[] encrypt(byte[] plainText, 
                                 byte[] associatedData) throws GeneralSecurityException {
        KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
        Aead aead = keysetHandle.getPrimitive(Aead.class);
        return aead.encrypt(plainText, associatedData);
    }

    public static byte[] decrypt(byte[] cipherText, 
                                 byte[] associatedData) throws GeneralSecurityException {
        KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
        Aead aead = keysetHandle.getPrimitive(Aead.class);
        return aead.decrypt(cipherText, associatedData);
    }
}

Here's how I am generating the token:

String associatedData = "somethingUnique";
String data = "tokenToBeEncrypted";

byte[] ciphered = CipherUtils.encrypt(data.getBytes(), associatedData.getBytes());
String finalToken = Base64.getEncoder().encodeToString(ciphered);

This finalToken is sent back as response and also retrieved from next request.

Here's I am trying to decrypt:

String associatedData = "somethingUnique"; // same one used for encrypting
String token = // retrieved from http request
byte[] decodedText = Base64.getDecoder().decode(token);
byte[] deciphered = CipherUtils.decrypt(decodedText, associatedData.getBytes());

This always results in the following exception:

java.security.GeneralSecurityException: decryption failed
    at com.google.crypto.tink.aead.AeadWrapper$WrappedAead.decrypt(AeadWrapper.java:82)
    at CipherUtils.decrypt(CipherUtils.java:22)

What am I missing here?

P.S: I'm using tink version 1.3.0-rc1

Termin4t0r
  • 199
  • 3
  • 10
  • [`generateNew`](https://github.com/google/tink/blob/master/docs/JAVA-HOWTO.md#generating-new-keys-and-keysets) generates a _new_ key. Since you call `generateNew` in both `encrypt` and `decrypt`, encryption and decryption use _different_ keys. Therefore the decryption fails. – Topaco Nov 03 '19 at 14:27

2 Answers2

0

You are initializing two separate instances of AEAD keyset. You need to initialize a single keyset and Aead and refer the same object for encryption and decryption

@Test
public void testEnc() throws GeneralSecurityException {
    AeadConfig.register();
    String associatedData = "somethingUnique";
    String data = "tokenToBeEncrypted";
    KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
    Aead aead = keysetHandle.getPrimitive(Aead.class);
    byte[] ciphered = aead.encrypt(data.getBytes(), associatedData.getBytes());
    byte[] deciphered = aead.decrypt(ciphered, associatedData.getBytes());
    assertEquals(data, new String(deciphered));

}
Monish Sen
  • 1,773
  • 3
  • 20
  • 32
  • It seems you are trying to do very basic encryption/decryption, best to stick to the native crypto library. Check out this example https://www.quickprogrammingtips.com/java/how-to-encrypt-and-decrypt-data-in-java-using-aes-algorithm.html – Monish Sen Nov 03 '19 at 14:34
0

My answer depends on the comment from Topaco (Nov 3 at 14:27) and shows some code how to solve the problem. As you generate a new key even when going to decrypt a message the decryption fails (the key used for encryption differs from key for decryption), so you have to save the encryption key and reuse it for decryption. In Tink this can be done with one additional line of code, thats the encryption part:

public static byte[] encrypt(byte[] plainText, byte[] associatedData) throws GeneralSecurityException, IOException {
        KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
        Aead aead = keysetHandle.getPrimitive(Aead.class);
        CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withFile(new File("tinkkey.json"))); // new line
        return aead.encrypt(plainText, associatedData);
    }

Now the decryption-part:

public static byte[] decrypt(byte[] cipherText, byte[] associatedData) throws GeneralSecurityException, IOException {
        // KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM); // deleted line
        KeysetHandle keysetHandle =  CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File("tinkkey.json"))); // new line
        Aead aead = keysetHandle.getPrimitive(Aead.class);
        return aead.decrypt(cipherText, associatedData);
    }

All bind together with a small sample main:

public static void main(String[] args) throws GeneralSecurityException, IOException {
        AeadConfig.register();
        byte[] encryptByte = encrypt("plain".getBytes("UTF-8"), "aad".getBytes("UTF-8"));
        byte[] decryptByte = decrypt(encryptByte, "aad".getBytes("UTF-8"));
        System.out.println("decrypted plaintext:" + new String(decryptByte, "UTF-8"));
    }

In the end you get the decrypted text:

decrypted plaintext:plain

To save the keyfile you need an additional library on the classpath (JSON Org) and you get it here: https://mvnrepository.com/artifact/org.json/json

Please keep in mind that the key needs to get stored securely as everyone with access to the keyfile can decrypt your message.the

Community
  • 1
  • 1
Michael Fehr
  • 5,827
  • 2
  • 19
  • 40