blob: 15b8935ae6862d9019ef654f86f7b7a91c8c1ad5 [file] [log] [blame] [view]
# Tink for Go HOW-TO
This document contains instructions for common tasks in
[Tink](https://github.com/google/tink). Example code snippets for these tasks
and API documentation can be found on
[pkg.go.dev](https://pkg.go.dev/github.com/google/tink/go).
## Setup instructions
To install Tink locally run:
```sh
go get github.com/google/tink/go/...
```
to run all the tests locally:
```sh
cd $GOPATH/go/src/github.com/google/tink/go
go test ./...
```
Golang Tink API also supports [Bazel](https://www.bazel.build) builds. To run
the tests using bazel:
```sh
cd $GOPATH/go/src/github.com/google/tink/go
bazel build ... && bazel test ...
```
## Generating new keys and keysets
To take advantage of key rotation and other key management features, you usually
do not work with single keys, but with keysets. Keysets are just sets of keys
with some additional parameters and metadata.
Internally Tink stores keysets as Protocol Buffers, but you can work with
keysets via a wrapper called a keyset handle. You can generate a new keyset and
obtain its handle using a KeyTemplate. KeysetHandle objects enforce certain
restrictions that prevent accidental leakage of the sensitive key material.
```go
package main
import (
"fmt"
"log"
"github.com/google/tink/go/aead"
"github.com/google/tink/go/keyset"
)
func main() {
// Other key templates can also be used.
kh, err := keyset.NewHandle(aead.AES128GCMKeyTemplate())
if err != nil {
log.Fatal(err)
}
fmt.Println(kh.String())
}
```
Key templates are available for MAC, digital signatures, AEAD encryption, DAEAD
encryption and hybrid encryption.
Key Template Type | Key Template
----------------- | ------------------------------------------------
AEAD | aead.AES128CTRHMACSHA256KeyTemplate()
AEAD | aead.AES128GCMKeyTemplate()
AEAD | aead.AES256CTRHMACSHA256KeyTemplate()
AEAD | aead.AES256GCMKeyTemplate()
AEAD | aead.ChaCha20Poly1305KeyTemplate()
AEAD | aead.XChaCha20Poly1305KeyTemplate()
DAEAD | daead.AESSIVKeyTemplate()
MAC | mac.HMACSHA256Tag128KeyTemplate()
MAC | mac.HMACSHA256Tag256KeyTemplate()
MAC | mac.HMACSHA512Tag256KeyTemplate()
MAC | mac.HMACSHA512Tag512KeyTemplate()
Signature | signature.ECDSAP256KeyTemplate()
Signature | signature.ECDSAP384KeyTemplate()
Signature | signature.ECDSAP521KeyTemplate()
Hybrid | hybrid.ECIESHKDFAES128GCMKeyTemplate()
Hybrid | hybrid.ECIESHKDFAES128CTRHMACSHA256KeyTemplate()
To avoid accidental leakage of sensitive key material, you should avoid mixing
keyset generation and usage in code. To support the separation of these
activities Tink provides a command-line tool, [Tinkey](TINKEY.md), which can be
used for common key management tasks.
## Storing and loading existing keysets
After generating key material, you might want to persist it to a storage system.
Tink supports encrypting and persisting the keys to any io.Writer and io.Reader
implementations.
```go
package main
import (
"fmt"
"log"
"github.com/google/tink/go/aead"
"github.com/google/tink/go/core/registry"
"github.com/google/tink/go/integration/gcpkms"
"github.com/google/tink/go/keyset"
)
const (
// Change this. AWS KMS, Google Cloud KMS and HashiCorp Vault are supported out of the box.
keyURI = "gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar"
credentialsPath = "credentials.json"
)
func main() {
// Generate a new keyset handle.
handle1, err := keyset.NewHandle(aead.AES128GCMKeyTemplate())
if err != nil {
log.Fatal(err)
}
// Get the key encryption AEAD from a KMS.
gcpClient, err := gcpkms.NewClientWithCredentials(keyURI, credentialsPath)
if err != nil {
log.Fatal(err)
}
registry.RegisterKMSClient(gcpClient)
keyEncryptionAEAD, err := gcpClient.GetAEAD(keyURI)
if err != nil {
log.Fatal(err)
}
// Serialize and encrypt the keyset handle using the key encryption AEAD.
// We strongly recommend that you encrypt the keyset handle before persisting
// it.
buf := new(bytes.Buffer)
writer := keyset.NewBinaryWriter(buf)
err = handle1.Write(writer, keyEncryptionAEAD)
if err != nil {
log.Fatal(err)
}
encryptedHandle := buf.Bytes()
// Decrypt and parse the encrypted keyset using the key encryption AEAD.
reader := keyset.NewBinaryReader(bytes.NewReader(encryptedHandle))
handle2, err := keyset.Read(reader, keyEncryptionAEAD)
if err != nil {
log.Fatal(err)
}
}
```
## AEAD
The AEAD primitive (authenticated encryption with associated data) is the most
common primitive to ***encrypt*** data. It is symmetric, and using the same key
for encryption and decryption.
Check out the
[AEAD examples](https://pkg.go.dev/github.com/google/tink/go/aead#example-package).
The `Play` button at the corner right allows you to run them on the Go
Playground.
## Deterministic AEAD
The Deterministic AEAD primitive (authenticated encryption with associated data)
is used to ***deterministically encrypt*** data. It is symmetric, and using the
same key for encryption and decryption.
Unlike AEAD, implementations of this interface are not semantically secure,
because encrypting the same plaintext always yields the same ciphertext.
Check out the
[Deterministic AEAD examples](https://pkg.go.dev/github.com/google/tink/go/daead#example-package).
The `Play` button at the corner right allows you to run them on the Go
Playground.
## MAC
The MAC primitive allows you to ensure that nobody tampers with data you own. It
is symmetric, and using the same key for authentication and verification.
Check out the
[MAC examples](https://pkg.go.dev/github.com/google/tink/go/mac#example-package).
The `Play` button at the corner right allows you to run them on the Go
Playground.
## Digital signature
The digital signature primitives allow you to ensure that nobody tampers with
your data. It is asymmetric, and hence comes with a pair of keys (public key and
private key). The private key allows to sign messages, and the public key allows
to verify.
Check out the
[digital signature examples](https://pkg.go.dev/github.com/google/tink/go/signature#example-package).
The `Play` button at the corner right allows you to run them on the Go
Playground.
## Hybrid encryption
The hybrid encryption primitives allow you to encrypt data with a public key.
Only users with the secret key will be able to decrypt the data.
Check out the
[hybrid encryption examples](https://pkg.go.dev/github.com/google/tink/go/hybrid#example-package).
The `Play` button at the corner right allows you to run them on the Go
Playground.
## Envelope encryption
Via the AEAD interface, Tink supports
[envelope encryption](KEY-MANAGEMENT.md#envelope-encryption).
For example, you can perform envelope encryption with a Google Cloud KMS key at
`gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar`
using the credentials in `credentials.json` as follows:
```go
package main
import (
"encoding/base64"
"fmt"
"github.com/google/tink/go/aead"
"github.com/google/tink/go/core/registry"
"github.com/google/tink/go/integration/gcpkms"
"github.com/google/tink/go/keyset"
)
const (
// Change this. AWS KMS, Google Cloud KMS and HashiCorp Vault are supported out of the box.
keyURI = "gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar"
credentialsPath = "credentials.json"
)
func main() {
gcpclient, err := gcpkms.NewClientWithCredentials(keyURI, credentialsPath)
if err != nil {
log.Fatal(err)
}
registry.RegisterKMSClient(gcpclient)
dek := aead.AES128CTRHMACSHA256KeyTemplate()
kh, err := keyset.NewHandle(aead.KMSEnvelopeAEADKeyTemplate(keyURI, dek))
if err != nil {
log.Fatal(err)
}
a, err := aead.New(kh)
if err != nil {
log.Fatal(err)
}
msg := []byte("this message needs to be encrypted")
aad := []byte("this data needs to be authenticated, but not encrypted")
ct, err := a.Encrypt(msg, aad)
if err != nil {
log.Fatal(err)
}
pt, err := a.Decrypt(ct, aad)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Ciphertext: %s\n", base64.StdEncoding.EncodeToString(ct))
fmt.Printf("Original plaintext: %s\n", msg)
fmt.Printf("Decrypted Plaintext: %s\n", pt)
}
```