Proving Messages and That Bob Is Still Sending Them: MAC With Google Tink

Google Tink is an open source repository for the integration of cryptography methods. It uses best practice in order to reduce risks, and…

Proving Messages and That Bob Is Still Sending Them: MAC With Google Tink

Google Tink is an open source repository for the integration of cryptography methods. It uses best practice in order to reduce risks, and also to simplify code integration. Currently it supports Java, C++ and Objective-C. As Java is well supported on Android devices, the code has already been integrated into a wide range of applications, including Google Pay.

One of the standard methods that we use in cryptography is to sign a message. For this we generate a signing key, and which is kept secret for a range of messages. This could relate to a single conversation between Bob and Alice, or for long-term communications between them.

Either Bob or Alice (or both of them) create a shared private key, and then pass it securely. Only Bob and Alice will have this key, and Eve awill not be able to discover it. Every time Bob sends a message to Alice he sends the message with a MAC (Message Authentication Code), and which is the message encrypted with the private key and then produced as a hash code (SHA-256). This method is known as HMAC (Hash-based Message Authentication Code). Alice takes the signing key and checks that she gets the same MAC. If she does, she has checked that it is still Bob who is signing the messages. If it doesn’t tie-up, she assumes that Eve is pretending to be Bob, and discards the message.

Now let’s look at how Google Tink generates MAC codes. For this we generate a new MAC key with getPrimitive() method for MacFactory, and then use the computeMac() to create and verifyMac() to check:

KeysetHandle keysetHandle = KeysetHandle.generateNew(MacKeyTemplates.HMAC_SHA256_128BITTAG);

Mac mac = MacFactory.getPrimitive(keysetHandle);

byte[] tag = mac.computeMac(plaintext.getBytes());

mac.verifyMac(tag,plaintext.getBytes());

A sample run which shows the MAC for a message of “hello123” for Base-64 and Hex formats:

Text:		hello123

MAC: ASJFEIAQEqk9MvGaIsJyKcLiN2iw
MAC: 41534A464549415145716B394D76476149734A794B634C694E326977

Valid MAC

The key can also be printed and which shows the symmetric key used (and that we are using HMAC):

Printing out key:

MAC: {
"primaryKeyId": 574951552,
"key": [{
"keyData": {
"typeUrl": "type.googleapis.com/google.crypto.tink.HmacKey",
"keyMaterialType": "SYMMETRIC",
"value": "EgQIAxAQGiAU/p0/1SEV+O1WE/fvQufi7z+rxQ0W6cJeRtgHHtqMQg=="
},
"outputPrefixType": "TINK",
"keyId": 574951552,
"status": "ENABLED"
}]
}

We can see that the encryption key used is “EgQIAxAQGiAU/p0/1SEV+O1WE/fvQufi7z+rxQ0W6cJeRtgHHtqMQg==” and that the format of the HmacKey is defined

If you want to try this it, try here. Here is the code:

package com.helloworld;
import java.util.Base64;
import com.google.crypto.tink.aead.AeadConfig;
import java.security.GeneralSecurityException;
import java.io.ByteArrayOutputStream;

import com.google.crypto.tink.Aead;

import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.Mac;
import com.google.crypto.tink.mac.MacFactory;
import com.google.crypto.tink.mac.MacKeyTemplates;
import org.apache.commons.codec.binary.Hex;
import com.google.crypto.tink.CleartextKeysetHandle;
import com.google.crypto.tink.JsonKeysetWriter;


public final class HelloWorld {



public static void main(String[] args) throws Exception {


AeadConfig.register();

try {



String plaintext="napier";


if (args.length>0) plaintext=args[0];


System.out.println("Text:\t"+plaintext);

KeysetHandle keysetHandle = KeysetHandle.generateNew(MacKeyTemplates.HMAC_SHA256_128BITTAG);



Mac mac = MacFactory.getPrimitive(keysetHandle);




byte[] tag = mac.computeMac(plaintext.getBytes());

byte[] encoded = Base64.getEncoder().encode(tag);
System.out.println("\nMAC (Base64):\t"+ new String(encoded));
System.out.println("MAC (Hex):\t"+ toHexString(encoded));

try {
mac.verifyMac(tag,plaintext.getBytes());
System.out.println("\nValid MAC");
} catch (GeneralSecurityException e) {
System.out.println("In Valid MAC");

}


System.out.println("\nPrinting out key:");


ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withOutputStream(outputStream));

System.out.println("\nMAC:\t"+ new String(outputStream.toByteArray()));


} catch (GeneralSecurityException e) {
System.out.println(e);
System.exit(1);
}
}

public static String toHexString( byte[] bytes )
{
StringBuffer sb = new StringBuffer( bytes.length*2 );
for( int i = 0; i < bytes.length; i++ )
{
sb.append( toHex(bytes[i] >> 4) );
sb.append( toHex(bytes[i]) );
}

return sb.toString();
}
private static char toHex(int nibble)
{
final char[] hexDigit =
{
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};
return hexDigit[nibble & 0xF];
}

}

A demo of this method is here.

Conclusions

With Google Tink we finally get a code based which has now been hacked together over the years (such as with OpenSSL) and which is consistent in its usage and focused on API integration. It is a code based for a modern world.