For those that haven’t heard about Tink, it is a very powerful library for using cryptographic primitives. This library is used within Google and is maintained by a small team of incredbly smart cryptographers to incorporate best cryptographic practices.
In this tutorial, we’ll implement a common solution to a problem that GPG typically solves, but do it all with Tink. That problem is asymmetric encryption; i.e. Alice wants to send a secret message to Bob, so she encrypts a message with Bob’s public key, then Bob decrypts it with his private key.
Tink’s documentation is generally great, but the operational aspect is sometimes missing. That is, how do I use this end-to-end in practice? In this tutorial, we’ll do the following:
tinkeyto generate a new keyset for asymmetric encryption
- Upload the key to Google Secret Manager (you can skip these parts if you’re not GCP yet, but you should look into it!)
- Get the public key from that keyset
- Encrypt a file with the public key
- Decrypt the file with the private key
Generate a suitable asymmetric key pair
First you’ll need to download the
tinkey command line tool which we’ll use to create the key pair. You can do this via Homebrew or build with Bazel. Then execute the following command to create a keyset suitible for asymmetric encryption.
tinkey create-keyset --key-template ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM --out keyset.json
This is a very long name for a template, which can be understandably confusing. The TL;DR is that when using asymmetric encryption, you have to use multiple algorithms to accomplish what you need. In this case we need a Key Encapsulation Mechanism (KEM), Data Encapsulation Mechanism (DEM) and a Key Derivation Function (KDF). In this case, we’re using:
- KEM: ECDH over NIST P-256
- DEM: AES128-GCM
- KDF: HKDF-HMAC-SHA256 with an empty salt
Upload the Keyset to Secret Manager
gcloud secrets create tink-keyset
gcloud secrets versions add tink-keyset --data-file keyset.json
Make sure to downscope access to this secret later using
gcloud secrets add-iam-policy-binding or similar. Also now is the time to delete the secret from your filesystem so you don’t accidentally commit it later on.
Create the public key
Now let’s get the public key from the keyset we just created:
tinkey create-public-keyset --in keyset.json --out pubkey.json
Lets take a look what was just generated. You’ll notice in the snippet below that the key material type is
ASYMMETRIC_PUBLIC that’s how you know it’s ok to share.
$ cat pubkey.json
Now just save this JSON value to a file called
pubkey.json or something similar.
Encrypt with the public key
Now that you have the public key in a file of some kind, lets deliver it to the folks who are building an app that encrypts with it.
Let’s assume there is some Python (or any other supported language) application that does encrypting back to you. It now has access to the public key to encrypt values with, so it only needs to use
tink. Let’s create a very simple command line script that will do this, taking as arguments the path to the public key we just distributed as well as the plaintext file they want to encrypt, then prints the base64 encoded ciphertext.
Usage will look something like this:
python encrypt-with-pubkey.py pubkey.json test.txt
Decrypt with the private key
Once the application sends encrypted data back to you, you can decrypt it again with the private key you have stored in Secret Manager.
gcloud secrets versions access latest --secret tink-keyset > keyset.json
Now let’s create another similar script to decrypt the secret and print it:
This should print the plaintext to standard out such as this:
$ python decrypt-with-keyset.py keyset.json ARjLMpME/u59NpDGz0aqw46idARWIv81FIon4VbSLic/rEs97cGq51G2JLFFwSJ+oscfMEtW/tXZPAeKw8LFiv5HEIv0EeGLrkGBLnDL1f+cjNZIlPWR6v57fyUZA/Z+QQrmi73D+WPYHdJ2ANt4
Now you know how to handle asymmetric encryption with Tink!
- The patterns used here with Python can very easily be ported to any other language Tink supports. They might seem a bit odd for a Python dev, but this Reader/Writer paradigm is very common in C/C++, Go and others.
- You’ll notice that Tink does not care what template you use for the hybrid (or any other) primitive. One of the great things about it, is that it can use the key template from the keyset itself, which makes it much easier to reason about the code.