/
aesgcm.go
93 lines (82 loc) · 2.29 KB
/
aesgcm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Package aesgcm is a simple wrapper around standard library for AES-256-GCM.
package aesgcm
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/binary"
"fmt"
"io"
"time"
)
const (
// KeySize is AES-256 key size
KeySize = 32
// NonceSize is size of nonce (IV) for AES-256-GCM
NonceSize = 12 // == gcm.NonceSize()
// TagSize is authentication tag size for AES-256-GCM
TagSize = 16 // == gcm.Overhead()
)
// Aes256Gcm stores key
type Aes256Gcm struct {
key []byte
}
// NewAes256Gcm creates new Aes256Gcm with key
func NewAes256Gcm(key []byte) (*Aes256Gcm, error) {
if len(key) != KeySize {
return nil, aes.KeySizeError(len(key))
}
return &Aes256Gcm{key: key}, nil
}
// GenerateNonce generates nonce for AES-256-GCM from current time and RNG
func GenerateNonce() ([]byte, error) {
b := make([]byte, NonceSize)
now := uint64(time.Now().UnixNano())
binary.BigEndian.PutUint64(b, now)
_, err := io.ReadFull(rand.Reader, b[8:])
if err != nil {
return nil, err
}
return b, nil
}
// Seal encrypts and authenticates plaintext, authenticates the
// additional data (aad) and returns ciphertext together with authentication tag.
// The nonce must be NonceSize bytes long and unique for all
// time, for a given key. It can be generated by GenerateNonce.
func (a *Aes256Gcm) Seal(plaintext, aad, nonce []byte) ([]byte, error) {
if len(nonce) != NonceSize {
return nil, fmt.Errorf("Aes256Gcm.Seal: invalid nonce size %d", nonce)
}
c, err := aes.NewCipher(a.key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(c)
if err != nil {
return nil, err
}
out := gcm.Seal(nil, nonce, plaintext, aad)
return out, nil
}
// Open decrypts and authenticates ciphertext, authenticates the
// additional data (aad) and, if successful, returns plaintext.
// The nonce must be NonceSize bytes long and both it and the additional data
// must match the value passed to Seal.
func (a *Aes256Gcm) Open(ciphertext, aad, nonce []byte) ([]byte, error) {
if len(nonce) != NonceSize {
return nil, fmt.Errorf("Aes256Gcm.Open: invalid nonce size %d", nonce)
}
c, err := aes.NewCipher(a.key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(c)
if err != nil {
return nil, err
}
out, err := gcm.Open(nil, nonce, ciphertext, aad)
if err != nil {
return nil, err
}
return out, nil
}