1# Tink for Go HOW-TO 2 3This document contains instructions for common tasks in 4[Tink](https://github.com/google/tink). Example code snippets for these tasks 5and API documentation can be found on 6[pkg.go.dev](https://pkg.go.dev/github.com/google/tink/go). 7 8## Setup instructions 9 10To install Tink locally run: 11 12```sh 13go get github.com/google/tink/go/... 14``` 15 16to run all the tests locally: 17 18```sh 19cd $GOPATH/go/src/github.com/google/tink/go 20go test ./... 21``` 22 23Golang Tink API also supports [Bazel](https://www.bazel.build) builds. To run 24the tests using bazel: 25 26```sh 27cd $GOPATH/go/src/github.com/google/tink/go 28bazel build ... && bazel test ... 29``` 30 31## Generating new keys and keysets 32 33To take advantage of key rotation and other key management features, you usually 34do not work with single keys, but with keysets. Keysets are just sets of keys 35with some additional parameters and metadata. 36 37Internally Tink stores keysets as Protocol Buffers, but you can work with 38keysets via a wrapper called a keyset handle. You can generate a new keyset and 39obtain its handle using a KeyTemplate. KeysetHandle objects enforce certain 40restrictions that prevent accidental leakage of the sensitive key material. 41 42```go 43package main 44 45import ( 46 "fmt" 47 "log" 48 49 "github.com/google/tink/go/aead" 50 "github.com/google/tink/go/keyset" 51) 52 53func main() { 54 // Other key templates can also be used. 55 kh, err := keyset.NewHandle(aead.AES128GCMKeyTemplate()) 56 if err != nil { 57 log.Fatal(err) 58 } 59 60 fmt.Println(kh.String()) 61} 62 63``` 64 65Key templates are available for MAC, digital signatures, AEAD encryption, DAEAD 66encryption and hybrid encryption. 67 68Key Template Type | Key Template 69----------------- | ------------------------------------------------ 70AEAD | aead.AES128CTRHMACSHA256KeyTemplate() 71AEAD | aead.AES128GCMKeyTemplate() 72AEAD | aead.AES256CTRHMACSHA256KeyTemplate() 73AEAD | aead.AES256GCMKeyTemplate() 74AEAD | aead.ChaCha20Poly1305KeyTemplate() 75AEAD | aead.XChaCha20Poly1305KeyTemplate() 76DAEAD | daead.AESSIVKeyTemplate() 77MAC | mac.HMACSHA256Tag128KeyTemplate() 78MAC | mac.HMACSHA256Tag256KeyTemplate() 79MAC | mac.HMACSHA512Tag256KeyTemplate() 80MAC | mac.HMACSHA512Tag512KeyTemplate() 81Signature | signature.ECDSAP256KeyTemplate() 82Signature | signature.ECDSAP384KeyTemplate() 83Signature | signature.ECDSAP521KeyTemplate() 84Hybrid | hybrid.ECIESHKDFAES128GCMKeyTemplate() 85Hybrid | hybrid.ECIESHKDFAES128CTRHMACSHA256KeyTemplate() 86 87To avoid accidental leakage of sensitive key material, you should avoid mixing 88keyset generation and usage in code. To support the separation of these 89activities Tink provides a command-line tool, [Tinkey](TINKEY.md), which can be 90used for common key management tasks. 91 92## Storing and loading existing keysets 93 94After generating key material, you might want to persist it to a storage system. 95Tink supports encrypting and persisting the keys to any io.Writer and io.Reader 96implementations. 97 98```go 99package main 100 101import ( 102 "fmt" 103 "log" 104 105 "github.com/google/tink/go/aead" 106 "github.com/google/tink/go/core/registry" 107 "github.com/google/tink/go/integration/gcpkms" 108 "github.com/google/tink/go/keyset" 109) 110 111const ( 112 // Change this. AWS KMS, Google Cloud KMS and HashiCorp Vault are supported out of the box. 113 keyURI = "gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar" 114 credentialsPath = "credentials.json" 115) 116 117func main() { 118 // Generate a new keyset handle. 119 handle1, err := keyset.NewHandle(aead.AES128GCMKeyTemplate()) 120 if err != nil { 121 log.Fatal(err) 122 } 123 124 // Get the key encryption AEAD from a KMS. 125 gcpClient, err := gcpkms.NewClientWithCredentials(keyURI, credentialsPath) 126 if err != nil { 127 log.Fatal(err) 128 } 129 registry.RegisterKMSClient(gcpClient) 130 keyEncryptionAEAD, err := gcpClient.GetAEAD(keyURI) 131 if err != nil { 132 log.Fatal(err) 133 } 134 135 // Serialize and encrypt the keyset handle using the key encryption AEAD. 136 // We strongly recommend that you encrypt the keyset handle before persisting 137 // it. 138 buf := new(bytes.Buffer) 139 writer := keyset.NewBinaryWriter(buf) 140 err = handle1.Write(writer, keyEncryptionAEAD) 141 if err != nil { 142 log.Fatal(err) 143 } 144 encryptedHandle := buf.Bytes() 145 146 // Decrypt and parse the encrypted keyset using the key encryption AEAD. 147 reader := keyset.NewBinaryReader(bytes.NewReader(encryptedHandle)) 148 handle2, err := keyset.Read(reader, keyEncryptionAEAD) 149 if err != nil { 150 log.Fatal(err) 151 } 152} 153``` 154 155## AEAD 156 157The AEAD primitive (authenticated encryption with associated data) is the most 158common primitive to ***encrypt*** data. It is symmetric, and using the same key 159for encryption and decryption. 160 161Check out the 162[AEAD examples](https://pkg.go.dev/github.com/google/tink/go/aead#example-package). 163The `Play` button at the corner right allows you to run them on the Go 164Playground. 165 166## Deterministic AEAD 167 168The Deterministic AEAD primitive (authenticated encryption with associated data) 169is used to ***deterministically encrypt*** data. It is symmetric, and using the 170same key for encryption and decryption. 171 172Unlike AEAD, implementations of this interface are not semantically secure, 173because encrypting the same plaintext always yields the same ciphertext. 174 175Check out the 176[Deterministic AEAD examples](https://pkg.go.dev/github.com/google/tink/go/daead#example-package). 177The `Play` button at the corner right allows you to run them on the Go 178Playground. 179 180## MAC 181 182The MAC primitive allows you to ensure that nobody tampers with data you own. It 183is symmetric, and using the same key for authentication and verification. 184 185Check out the 186[MAC examples](https://pkg.go.dev/github.com/google/tink/go/mac#example-package). 187The `Play` button at the corner right allows you to run them on the Go 188Playground. 189 190## Digital signature 191 192The digital signature primitives allow you to ensure that nobody tampers with 193your data. It is asymmetric, and hence comes with a pair of keys (public key and 194private key). The private key allows to sign messages, and the public key allows 195to verify. 196 197Check out the 198[digital signature examples](https://pkg.go.dev/github.com/google/tink/go/signature#example-package). 199The `Play` button at the corner right allows you to run them on the Go 200Playground. 201 202## Hybrid encryption 203 204The hybrid encryption primitives allow you to encrypt data with a public key. 205Only users with the secret key will be able to decrypt the data. 206 207Check out the 208[hybrid encryption examples](https://pkg.go.dev/github.com/google/tink/go/hybrid#example-package). 209The `Play` button at the corner right allows you to run them on the Go 210Playground. 211 212## Envelope encryption 213 214Via the AEAD interface, Tink supports 215[envelope encryption](KEY-MANAGEMENT.md#envelope-encryption). 216 217For example, you can perform envelope encryption with a Google Cloud KMS key at 218`gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar` 219using the credentials in `credentials.json` as follows: 220 221```go 222package main 223 224import ( 225 "encoding/base64" 226 "fmt" 227 228 "github.com/google/tink/go/aead" 229 "github.com/google/tink/go/core/registry" 230 "github.com/google/tink/go/integration/gcpkms" 231 "github.com/google/tink/go/keyset" 232) 233 234const ( 235 // Change this. AWS KMS, Google Cloud KMS and HashiCorp Vault are supported out of the box. 236 keyURI = "gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar" 237 credentialsPath = "credentials.json" 238) 239 240func main() { 241 gcpclient, err := gcpkms.NewClientWithCredentials(keyURI, credentialsPath) 242 if err != nil { 243 log.Fatal(err) 244 } 245 registry.RegisterKMSClient(gcpclient) 246 247 dek := aead.AES128CTRHMACSHA256KeyTemplate() 248 kh, err := keyset.NewHandle(aead.KMSEnvelopeAEADKeyTemplate(keyURI, dek)) 249 if err != nil { 250 log.Fatal(err) 251 } 252 253 a, err := aead.New(kh) 254 if err != nil { 255 log.Fatal(err) 256 } 257 258 msg := []byte("this message needs to be encrypted") 259 aad := []byte("this data needs to be authenticated, but not encrypted") 260 ct, err := a.Encrypt(msg, aad) 261 if err != nil { 262 log.Fatal(err) 263 } 264 265 pt, err := a.Decrypt(ct, aad) 266 if err != nil { 267 log.Fatal(err) 268 } 269 270 fmt.Printf("Ciphertext: %s\n", base64.StdEncoding.EncodeToString(ct)) 271 fmt.Printf("Original plaintext: %s\n", msg) 272 fmt.Printf("Decrypted Plaintext: %s\n", pt) 273} 274``` 275