Somehow I ended up using AES-GCM at least once per week, so I’m tired of googling the same thing over and over. Here’s a working example extracted from the book Build a web application with Golang .
Note: the key should be 32 bytes result of a safe hash function like SHA256.
1package main
2
3import (
4 "crypto/aes"
5 "crypto/cipher"
6 "crypto/rand"
7 "errors"
8 "fmt"
9 "io"
10 "log"
11)
12
13func main() {
14 text := []byte("Hola mundo")
15 key := []byte("the-key-has-to-be-32-bytes-long!")
16
17 ciphertext, err := encrypt(text, key)
18 if err != nil {
19 // TODO: Properly handle error
20 log.Fatal(err)
21 }
22 fmt.Printf("%s => %x\n", text, ciphertext)
23
24 plaintext, err := decrypt(ciphertext, key)
25 if err != nil {
26 // TODO: Properly handle error
27 log.Fatal(err)
28 }
29 fmt.Printf("%x => %s\n", ciphertext, plaintext)
30}
31
32func encrypt(plaintext []byte, key []byte) ([]byte, error) {
33 c, err := aes.NewCipher(key)
34 if err != nil {
35 return nil, err
36 }
37
38 gcm, err := cipher.NewGCM(c)
39 if err != nil {
40 return nil, err
41 }
42
43 nonce := make([]byte, gcm.NonceSize())
44 if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
45 return nil, err
46 }
47
48 return gcm.Seal(nonce, nonce, plaintext, nil), nil
49}
50
51func decrypt(ciphertext []byte, key []byte) ([]byte, error) {
52 c, err := aes.NewCipher(key)
53 if err != nil {
54 return nil, err
55 }
56
57 gcm, err := cipher.NewGCM(c)
58 if err != nil {
59 return nil, err
60 }
61
62 nonceSize := gcm.NonceSize()
63 if len(ciphertext) < nonceSize {
64 return nil, errors.New("ciphertext too short")
65 }
66
67 nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
68 return gcm.Open(nil, nonce, ciphertext, nil)
69}