Tink encryption (Hybrid Encryption)Google has released Tink and which is a multi-language, cross-platform cryptographic library. Hybrid Encryption is a combination of symmetric key encryption and public-key encryption. We encrypt with a newly created symmetric key, and then encrypt this with the public key of the recipient. The most popular public method is elliptic curve with Curve 25591, and the most popular symmetric method is AES [Tink Symmetric key][Tink MAC][Tink ECDSA/Ed25519][Tink Hybrid encryption][Tink Envelope encryption][HKDF][Deterministic Authenticated Encryption]. |
Outline
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.
We create the symmetric key with:
KeysetHandle privateKeysetHandle = KeysetHandle.generateNew( HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM); KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle();
and the public key pair with:
KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle(); HybridEncrypt hybridEncrypt = HybridEncryptFactory.getPrimitive(publicKeysetHandle);
The encryption and decryption are then:
byte[] ciphertext = hybridEncrypt.encrypt(plaintext.getBytes(), aad.getBytes()); HybridDecrypt hybridDecrypt = HybridDecryptFactory.getPrimitive( privateKeysetHandle); byte[] decrypted = hybridDecrypt.decrypt(ciphertext, aad.getBytes());
A sample run is:
Text: hello Password: qwerty Sig (Base64): ATJrfYwE7x3tQ6d4Zu5vGZ8/2hW3433Dk1cfw8ca900YdH1vJM9c+h2YPIFcXwk1duuOKXHPZ3qXx7QVikuHL4+D9tF38L7tHHnddsQlLnm4I9Oy+BV3ai4vEzmpts4LSeFwmfvqfw== Sig (Hex):41544A726659774537783374513664345A753576475A382F32685733343333446B3163667738636139303059644831764A4D39632B6832595049466358776B316475754F4B5848505A33715878375156696B75484C342B4439744633384C377448486E646473516C4C6E6D3449394F792B42563361693476457A6D707473344C536546776D66767166773D3D Decrypted: hello
In terms of the key pair we can view the key pair here:
Printing out key: { "primaryKeyId": 845905292, "key": [{ "keyData": { "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", "keyMaterialType": "ASYMMETRIC_PUBLIC", "value": "EkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARogOyIb/MongoqTLNlQS9iRbqqhIrzE7w8w1SwpnVjsDpwiIQCrCIUxvLyqXUD9a3nDb3Cbs0YvNQB5wlGMxCLDFTmeDA==" }, "outputPrefixType": "TINK", "keyId": 845905292, "status": "ENABLED" }] }
The code is:
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.HybridDecrypt; import com.google.crypto.tink.HybridEncrypt; import com.google.crypto.tink.hybrid.HybridDecryptFactory; import com.google.crypto.tink.hybrid.HybridEncryptFactory; import com.google.crypto.tink.hybrid.HybridKeyTemplates; import com.google.crypto.tink.subtle.Hex; import com.google.crypto.tink.KeysetHandle; import com.google.crypto.tink.CleartextKeysetHandle; import com.google.crypto.tink.JsonKeysetWriter; import com.google.crypto.tink.config.TinkConfig; public final class HelloWorld { public static void main(String[] args) throws Exception { TinkConfig.register(); try { String plaintext="napier"; String aad="qwerty123"; if (args.length>0) plaintext=args[0]; if (args.length>1) aad=args[1]; System.out.println("=== Hybrid encryption ==="); System.out.println("Text:\t\t"+plaintext); System.out.println("Password:\t"+aad); KeysetHandle privateKeysetHandle = KeysetHandle.generateNew( HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM); KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle(); HybridEncrypt hybridEncrypt = HybridEncryptFactory.getPrimitive(publicKeysetHandle); byte[] ciphertext = hybridEncrypt.encrypt(plaintext.getBytes(), aad.getBytes()); byte[] encoded = Base64.getEncoder().encode(ciphertext); System.out.println("\nSig (Base64):\t"+ new String(encoded)); System.out.println("Sig (Hex):"+ Hex.encode(encoded)); HybridDecrypt hybridDecrypt = HybridDecryptFactory.getPrimitive( privateKeysetHandle); byte[] decrypted = hybridDecrypt.decrypt(ciphertext, aad.getBytes()); String s = new String(decrypted); System.out.println("\nDecrypted:\t"+s); System.out.println("\nPrinting out key:"); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CleartextKeysetHandle.write( publicKeysetHandle, JsonKeysetWriter.withOutputStream(outputStream)); System.out.println(new String(outputStream.toByteArray())); System.out.println("\nPrinting out public key:"); outputStream = new ByteArrayOutputStream(); } catch (GeneralSecurityException e) { System.out.println(e); System.exit(1); } } }
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.
Presentation
The following is a presentation related to Google Tink [slides]: