-
Notifications
You must be signed in to change notification settings - Fork 219
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(key-manager): add an how-to guide for AEAD Streaming for the Key…
… Manager
- Loading branch information
Mélanie Marques
committed
Sep 2, 2024
1 parent
773027b
commit e4c6b3d
Showing
1 changed file
with
192 additions
and
0 deletions.
There are no files selected for viewing
192 changes: 192 additions & 0 deletions
192
identity-and-access-management/key-manager/how-to/streaming-aead-tink.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
--- | ||
meta: | ||
title: How to use Tink AEAD Streaming with with Scaleway's Key Manager | ||
description: Discover how to use Tink with AEAD Streaming and Scaleway's Key Manager in order to encrypt and decrypt large data streams. | ||
content: | ||
h1: How to use Tink AEAD Streaming with with Scaleway's Key Manager | ||
paragraph: Discover how to use Tink with AEAD Streaming and Scaleway's Key Manager in order to encrypt and decrypt large data streams. | ||
tags: key sensitive-data tink aead streaming | ||
dates: | ||
validation: 2024-08-28 | ||
posted: 2024-08-28 | ||
categories: | ||
- identity-and-access-management | ||
--- | ||
|
||
In this tutorial, you'll learn how to use Scaleway's Tink Key Manager extension to encrypt and decrypt large data streams using AEAD (authenticated encryption with associated data). | ||
|
||
## First steps | ||
|
||
To complete the actions presented below, you must : | ||
|
||
- Create a symmetric Key Manager Key for encryption. Take note of the ID of the key. You need it later. | ||
- In your terminal, paste the following commands to export your environment variables. Make sure you add your **own variables**. You can also use a scaleway configuration file. | ||
|
||
``` | ||
export SCW_ACCESS_KEY="<access-key>" | ||
export SCW_SECRET_KEY="<secret-key>" | ||
export SCW_DEFAULT_ORGANIZATION_ID="<organization-id>" | ||
export SCW_DEFAULT_PROJECT_ID="<project-id>" | ||
export SCW_DEFAULT_REGION="<region>" | ||
export SCW_API_URL="<api-url>" | ||
export SCW_KMS_KEY_ID="<key-id>" | ||
``` | ||
|
||
## Encrypt and decrypt large data streams using AEAD | ||
|
||
1. Add the [Scaleway Tink provider for Go](https://github.com/scaleway/tink-go-scwkms/tree/main) and Tink to your go.mod: | ||
|
||
``` | ||
> go get github.com/scaleway/tink-go-scwkms | ||
> go get github.com/tink-crypto/tink-go/v2 | ||
``` | ||
|
||
2. Create a Go project and copy paste the following code : | ||
|
||
``` | ||
package main | ||
import ( | ||
"bytes" | ||
"fmt" | ||
"github.com/scaleway/tink-go-scwkms/integration/scwkms" | ||
"github.com/tink-crypto/tink-go/v2/keyset" | ||
"github.com/tink-crypto/tink-go/v2/streamingaead" | ||
"io" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
) | ||
func main() { | ||
const keyURIPrefix = "scw-kms://regions/<region>/keys/" | ||
keyURI := keyURIPrefix + os.Getenv("SCW_KMS_KEY_ID") | ||
client, err := scwkms.NewClient(keyURIPrefix) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
kekAEAD, err := client.GetAEAD(keyURI) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
handle, err := keyset.NewHandle(streamingaead.AES256GCMHKDF1MBKeyTemplate()) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
// Encrypt the keyset and store it in memory (using a bytes buffer) | ||
buf := new(bytes.Buffer) | ||
writer := keyset.NewBinaryWriter(buf) | ||
err = handle.Write(writer, kekAEAD) | ||
if err != nil { | ||
log.Fatalf("Error writing encrypted keyset: %v", err) | ||
} | ||
// Decrypt the keyset from the buffer | ||
reader := keyset.NewBinaryReader(buf) | ||
decryptedHandle, err := keyset.Read(reader, kekAEAD) | ||
if err != nil { | ||
log.Fatalf("Error reading encrypted keyset: %v", err) | ||
} | ||
// Create the Streaming AEAD primitive from the decrypted keyset | ||
primitive, err := streamingaead.New(decryptedHandle) | ||
if err != nil { | ||
log.Fatalf("Error creating streaming AEAD primitive: %v", err) | ||
} | ||
// Create a file with the plaintext. | ||
dir, err := os.MkdirTemp("", "streamingaead") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer os.RemoveAll(dir) | ||
plaintextPath := filepath.Join(dir, "plaintext") | ||
if err := os.WriteFile(plaintextPath, []byte("this data needs to be encrypted"), 0666); err != nil { | ||
log.Fatal(err) | ||
} | ||
plaintextFile, err := os.Open(plaintextPath) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
// AssociatedData defines the context of the encryption. (It's optional) | ||
// Here, we include the path of the plaintext file. | ||
associatedData := []byte("associatedData for " + plaintextPath) | ||
// Encrypt the plaintext file and write the output to the ciphertext file. | ||
ciphertextPath := filepath.Join(dir, "ciphertext") | ||
ciphertextFile, err := os.Create(ciphertextPath) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
w, err := primitive.NewEncryptingWriter(ciphertextFile, associatedData) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
if _, err := io.Copy(w, plaintextFile); err != nil { | ||
log.Fatal(err) | ||
} | ||
if err := w.Close(); err != nil { | ||
log.Fatal(err) | ||
} | ||
if err := ciphertextFile.Close(); err != nil { | ||
log.Fatal(err) | ||
} | ||
if err := plaintextFile.Close(); err != nil { | ||
log.Fatal(err) | ||
} | ||
// Print the content of the encrypted file. | ||
c, err := os.ReadFile(ciphertextPath) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
fmt.Println(string(c)) | ||
// Decrypt the ciphertext file and write the output to the decrypted file. | ||
ciphertextFile, err = os.Open(ciphertextPath) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
decryptedPath := filepath.Join(dir, "decrypted") | ||
decryptedFile, err := os.Create(decryptedPath) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
r, err := primitive.NewDecryptingReader(ciphertextFile, associatedData) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
if _, err := io.Copy(decryptedFile, r); err != nil { | ||
log.Fatal(err) | ||
} | ||
if err := decryptedFile.Close(); err != nil { | ||
log.Fatal(err) | ||
} | ||
if err := ciphertextFile.Close(); err != nil { | ||
log.Fatal(err) | ||
} | ||
// Print the content of the decrypted file. | ||
b, err := os.ReadFile(decryptedPath) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
fmt.Println(string(b)) | ||
} | ||
``` | ||
**Caution: Associated data is authenticated but NOT encrypted.** | ||
|
||
In this tutorial, we propose using the Key Manager's remote KEK to protect the DEK and stream AEAD. | ||
However, it is also possible to protect the Data Encryption Key with another key that is not a remote key. | ||
|
||
3. Run your code by using the following command : | ||
|
||
``` | ||
> go mod tidy | ||
> go run test.go | ||
`` |