Google Tink for Asymmetric Encryption
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:
- Use
tinkey
to 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
{
"primaryKeyId": 415969939,
"key": [
{
"keyData": {
"typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey",
"value": "...snip...",
"keyMaterialType": "ASYMMETRIC_PUBLIC"
},
"status": "ENABLED",
"keyId": 415969939,
"outputPrefixType": "TINK"
}
]
}
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
ARjLMpME/u59NpDGz0aqw46idARWIv81FIon4VbSLic/rEs97cGq51G2JLFFwSJ+oscfMEtW/tXZPAeKw8LFiv5HEIv0EeGLrkGBLnDL1f+cjNZIlPWR6v57fyUZA/Z+QQrmi73D+WPYHdJ2ANt4
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
super secret
Now you know how to handle asymmetric encryption with Tink!
Closing Notes
- 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.
Next Steps
- Try out some of the other cryptographic primitives in Google’s Tink such as AEAD, MAC and others!
- Learn more about Secret Manager in GCP
- Learn more about practical cryptography by reading Serious Cryptography
- Encrypt all the things!!