AES-GCM encryption in Go

2019-10-27

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.

Go Playground

 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}