Tink encryption (Digital Signature)Google has released Tink and which is a multi-language, cross-platform cryptographic library. With OpenSSL we have complex bindings and which were often focused on specific systems, such as for DLLs in Windows systems. Tink is open-source and focuses on creating simple APIs and which should make the infrastructure more portable. In this example we will compute the a digital signature which is signed by a private key and then proved with a public key [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.
One of the standard methods that we use in cryptography is to sign a message with a private key, and to prove the signing with the public. Thus if Bob has a key pair, he uses his private key to sign the message, and then Alice will prove that it was Bob who signed it, using Bob's public key. It will also prove that the message has not been changed by Eve.
Now let's look at how Google Tink generates digital signatures codes. The core method is to use ECDSA (Elliptic Curve Digital Signature Algorithm). For this we generate a new key pair with getPrimitive() method for PublicKeySignFactory. We can then use the private key of the key pair to sign a message with the sign() method:
KeysetHandle privateKeysetHandle = KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P256); PublicKeySign signer = PublicKeySignFactory.getPrimitive(privateKeysetHandle); byte[] signature = signer.sign(plaintext.getBytes());
A sample run which show the signature for a message of "hello" for Base-64 and Hex formats:
Signature generator Text: hello Type: ECDSA_P521 Sig (Base64): AT7OS9IwgYcCQVZeR3E4VMMWZS7PbhyHYXCliDemEAy6VgR4cuVjEP1xvD2vB03fSU9OnTj9Q2BJnykcneGkyzeCsUpIuzgMJ1zoAkIAvy7yr9wLiKEoZfmNYp5+QwIighOtDpy+5t2XjzArkpgmYA23dR64o7L1/EyHUtM9JoMuL3DxWgJ3eeCvEf2aq8I= Sig (Hex): 013ECE4BD23081870241565E47713854C316652ECF6E1C876170A58837A6100CBA56047872E56310FD71BC3DAF074DDF494F4E9D38FD4360499F291C9DE1A4CB3782B14A48BB380C275CE8024200BF2EF2AFDC0B88A12865F98D629E7E4302228213AD0E9CBEE6DD978F302B929826600DB7751EB8A3B2F5FC4C8752D33D26832E2F70F15A027779E0AF11FD9AABC2 ID (Hex): 3ECE4BD2 (1053707218) DER: 3081870241565E47713854C316652ECF6E1C876170A58837A6100CBA56047872E56310FD71BC3DAF074DDF494F4E9D38FD4360499F291C9DE1A4CB3782B14A48BB380C275CE8024200BF2EF2AFDC0B88A12865F98D629E7E4302228213AD0E9CBEE6DD978F302B929826600DB7751EB8A3B2F5FC4C8752D33D26832E2F70F15A027779E0AF11FD9AABC2 Valid Signature
In terms of the key pair we can view the key pair here:
Printing out key: { "primaryKeyId": 1053707218, "key": [{ "keyData": { "typeUrl": "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey", "keyMaterialType": "ASYMMETRIC_PRIVATE", "value": "EpABEgYIBBAEGAIaQgEgzL3hg6dIjkQ9tBZYC56q7QJo2cYNxvN+nxSxuMG9qzvlKZz0FSHH4OtYrQagCm3X+1e2CyXtOkyUP7Cy8n2LaSJCAWmcOiDprwbE0w9LOnEYQosUOXwb47jkbT0W3V4U2P4ao10EX+3H+y06fTAjiy/lAjEO37HsqnW5Aaqs8TDtkxgbGkIAxYqPIyl0OZJX09P6pgUpBgEIsmiy50v000fGwrWJ5ZXMfn1kqOJp9xYNieeVWFsVrk5kBDTBkzfqCPA1gBPVVGY=" }, "outputPrefixType": "TINK", "keyId": 1053707218, "status": "ENABLED" }] }
We can see that the encryption key used is "EpABEgYIBBAEGAIa ... 1gBPVVGY=" and that the format of the EcdsPrivateKey is defined. The code is:
We can also view the public key:
Printing out public key: { "primaryKeyId": 1053707218, "key": [{ "keyData": { "typeUrl": "type.googleapis.com/google.crypto.tink.EcdsaPublicKey", "keyMaterialType": "ASYMMETRIC_PUBLIC", "value": "EgYIBBAEGAIaQgEgzL3hg6dIjkQ9tBZYC56q7QJo2cYNxvN+nxSxuMG9qzvlKZz0FSHH4OtYrQagCm3X+1e2CyXtOkyUP7Cy8n2LaSJCAWmcOiDprwbE0w9LOnEYQosUOXwb47jkbT0W3V4U2P4ao10EX+3H+y06fTAjiy/lAjEO37HsqnW5Aaqs8TDtkxgb" }, "outputPrefixType": "TINK", "keyId": 1053707218, "status": "ENABLED" }] }
and which has encrytpion key of "EgYIBBAEGAIaQgEgzL3hg6dIjkQ9tBZYC...AjEO37HsqnW5Aaqs8TDtkxgb".
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.KeysetHandle; import com.google.crypto.tink.PublicKeySign; import com.google.crypto.tink.PublicKeyVerify; import com.google.crypto.tink.signature.PublicKeySignFactory; import com.google.crypto.tink.signature.PublicKeyVerifyFactory; import com.google.crypto.tink.signature.SignatureKeyTemplates; import com.google.crypto.tink.subtle.Hex; //import org.apache.commons.codec.binary.Hex; 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"; int t=1; if (args.length>0) plaintext=args[0]; if (args.length>1) t=Integer.valueOf(args[1]); System.out.println("Signature generator"); System.out.println("Text:\t"+plaintext); KeysetHandle privateKeysetHandle = KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P256); if (t==2) { System.out.println("Type:\tED25519"); privateKeysetHandle = KeysetHandle.generateNew(SignatureKeyTemplates.ED25519); } else if (t==3) { System.out.println("Type:\tECDSA_P384"); privateKeysetHandle = KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P384); } else if (t==4) { System.out.println("Type:\tECDSA_P521"); privateKeysetHandle = KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P521); } else if (t==5) { System.out.println("Type:\tECDSA_P256_IEEE_P1363"); privateKeysetHandle = KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P256_IEEE_P1363); } else System.out.println("Type:\tECDSA_P256"); // privateKeysetHandle = KeysetHandle.generateNew(SignatureKeyTemplates.RSA_SSA_PKCS1_3072_SHA256_F4); PublicKeySign signer = PublicKeySignFactory.getPrimitive(privateKeysetHandle); byte[] signature = signer.sign(plaintext.getBytes()); byte[] encoded = Base64.getEncoder().encode(signature); System.out.println("\nSig (Base64): "+ new String(encoded)); String s = Hex.encode(signature); System.out.println("Sig (Hex): "+s ); System.out.println(" ID (Hex): "+ s.substring(2,10)+ " ("+ Integer.parseInt(s.substring(2,10), 16)+")"); System.out.println(" DER: "+ s.substring(10)); KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle(); PublicKeyVerify verifier = PublicKeyVerifyFactory.getPrimitive( publicKeysetHandle); try { verifier.verify(signature, plaintext.getBytes()); System.out.println("\nValid Signature"); } catch (GeneralSecurityException e) { System.out.println("In Valid Signature"); } System.out.println("\nPrinting out key:"); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CleartextKeysetHandle.write( privateKeysetHandle, JsonKeysetWriter.withOutputStream(outputStream)); System.out.println(new String(outputStream.toByteArray())); System.out.println("\nPrinting out public key:"); outputStream = new ByteArrayOutputStream(); CleartextKeysetHandle.write( publicKeysetHandle, JsonKeysetWriter.withOutputStream(outputStream)); System.out.println(new String(outputStream.toByteArray())); } 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]: