Tink encryptionIn this case we will use Tink with symmetric key encryption for the keys of 128-bit AES CTR with HMAC/SHA256, 128-bit GCM, 256-bit CTR HMAC/SHA256, 256-bit AES GCM, Chacha20, and XChaCha20. |
Outline
For Tink — based on BoringSSL and now at Version 1.2.0 — the adoption has been good and is already integrated into AdMob, Google Pay, Google Assistant, and Firebase. It also integrates AEAD (Authenticated encryption AE and authenticated encryption with associated data) methods and which integrates encryption keys, a hash function, and a message authentication code (MAC). Google, too, have analysed many cryptography weaknesses and have created code which addresses many of these problems.
The minimal standards for AEAD include [RFC5116]:
- The plaintext and associated data can have any length (from 0 to 2³² bytes).
- Supports 80-bit authentication.
- CCA2 security (adaptive chosen-ciphertext attack).
Outline
The workhorse of the cybersecurity industry is AES (Advanced Encryption Standard) and which is used to encrypt and decrypt data. The method comes from the winner of a NIST competition in 2001, and was previously known as the Rijndael (“Rain Dahl”) cipher.
AES is a symmetric key method, and where Bob and Alice have the same encryption key. In the following, Bob and Alice share an encryption key, and where Bob converts his plaintext into ciphertext, and then Alice converts the ciphertext back into plaintext using a shared secret key:
The problem with this setup is that the same plaintext will always result in the same ciphertext, so we typically add salt into the encryption process. We also need a way for Bob and Alice to generate the same secret key. This is either typically done through a key exchange method (such as with the Diffie-Hellman method) or by a KDF (Key Derivation Function). One of the most popular KDFs is PBKDF2 and which allows a password to be converted into an encryption key of a defined size:
Another mode of encryption is defined as AEAD (Authenticated Encryption with Additional Data), and where we can add some plaintext authenication data to the ciphering process, and where we need the same authentication data for the decrpytion process:
The size of the key is typically either 128 bits or 256 bits. AES (Advanced Encryption Standard) can be applied into three modes:
- Block cipher. This can be implemented with CBC (Cipher Block Chaining) and which implements a block cipher. In the case of AES, the block size will be 16 bytes, and thus the ciphertext will be a multiple of the block size. As we use a block cipher, we need to pad the data for the cipher process, and then unpad the decrypted data. The most common method is PKCS7, and which pads with the value which equals the number of padding bytes.
- AEAD (Authenticated Encryption with Additional Data). This can be implemented with GCM (Galois Counter Mode) and which implements with a stream cipher with the addition of additional data. This additional data can include something related to the ciphertext, such as with a session ID or TCP port. There is no padding required for the plaintext text, and thus the ciphertext will have the same length as the plaintext.
- Stream cipher. This can be implemented with CFB (Cipher FeedBack) and which implements a stream cipher. As we use a stream cipher, we do not need to pad the data, and where the ciphertext size will be the same as the plaintext. Overall we use a simple XOR operation between the plaintext stream and a key stream (derived from the main encryption key). The decryption is performed by just XOR’ing the ciphertext stream with the same key stream.
Sample code
In this case we will use Tink with symmetric key encryption for the keys of 128-bit AES CTR with HMAC/SHA256, 128-bit GCM, 256-bit CTR HMAC/SHA256, 256-bit AES GCM, Chacha20, and XChaCha20:
package main import ( "fmt" "github.com/google/tink/go/mac" "github.com/google/tink/go/keyset" "github.com/google/tink/go/insecurecleartextkeyset" "os" "strconv" "github.com/golang/protobuf/proto" "encoding/base64" ) func main() { msg:="This is a test" key,_ := keyset.NewHandle(mac.HMACSHA256Tag128KeyTemplate()) t:=1 argCount := len(os.Args[1:]) if (argCount>0) { msg= (os.Args[1])} if argCount > 1 { t,_ = strconv.Atoi(os.Args[2]) } switch t { case 1: key,_ =keyset.NewHandle(mac.HMACSHA256Tag256KeyTemplate()) case 2: key,_ =keyset.NewHandle(mac.HMACSHA256Tag128KeyTemplate()) case 3: key,_ =keyset.NewHandle(mac.HMACSHA512Tag256KeyTemplate()) case 4: key,_ =keyset.NewHandle(mac.HMACSHA512Tag512KeyTemplate()) } m, _ := mac.New(key) mac, _ := m.ComputeMAC([]byte(msg)) res:=m.VerifyMAC(mac, []byte(msg)) if (res!=nil) { fmt.Printf("MAC failed!") } else { fmt.Printf("Message: %s\n\n", msg) fmt.Printf("MAC: %x\n", mac) fmt.Printf("\nMAC success!\n\n") exportedPriv := &keyset.MemReaderWriter{} insecurecleartextkeyset.Write(key, exportedPriv) fmt.Printf("Key: %s\n\n", exportedPriv) // Print key ksw := &keyset.MemReaderWriter{} _ = insecurecleartextkeyset.Write(key, ksw) ks, _ := proto.Marshal(ksw.Keyset) fmt.Printf("\nRaw key: %s", base64.RawStdEncoding.EncodeToString(ks)) }
A sample run proves the process:
Message: Testing 123 MAC: 01436d9ad7353db69d8d09423434c3f4ba4056d5ca MAC success! Key: .{primary_key_id:1131256535 key:.key_data:.type_url:"type.googleapis.com/google.crypto.tink.HmacKey" value:"\022\004\010\003\020\020\032 [i/\213\203t\223\017\257b\242\177\nK\236g\004\n\363\020\243\365\212\001\266{\207m\366\270\234?" key_material_type:SYMMETRIC . status:ENABLED key_id:1131256535 output_prefix_type:TINK . .nil.} Raw key: CNe1tpsEEmgKXAoudHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuSG1hY0tleRIoEgQIAxAQGiBbaS+Lg3STD69ion8KS55nBArzEKP1igG2e4dt9ricPxgBEAEY17W2mwQgAQ
Presentation
The following is a presentation related to Google Tink [slides]: