xref: /aosp_15_r20/external/tink/docs/GOLANG-HOWTO.md (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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