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