1
2
3
4
5 package gcm
6
7 import (
8 "crypto/internal/fips140"
9 "crypto/internal/fips140/aes"
10 "crypto/internal/fips140/alias"
11 "errors"
12 )
13
14
15 type GCM struct {
16 cipher aes.Block
17 nonceSize int
18 tagSize int
19 gcmPlatformData
20 }
21
22 func New(cipher *aes.Block, nonceSize, tagSize int) (*GCM, error) {
23
24 return newGCM(&GCM{}, cipher, nonceSize, tagSize)
25 }
26
27
28
29
30
31 func newGCM(g *GCM, cipher *aes.Block, nonceSize, tagSize int) (*GCM, error) {
32 if tagSize < gcmMinimumTagSize || tagSize > gcmBlockSize {
33 return nil, errors.New("cipher: incorrect tag size given to GCM")
34 }
35 if nonceSize <= 0 {
36 return nil, errors.New("cipher: the nonce can't have zero length")
37 }
38 if cipher.BlockSize() != gcmBlockSize {
39 return nil, errors.New("cipher: NewGCM requires 128-bit block cipher")
40 }
41 g.cipher = *cipher
42 g.nonceSize = nonceSize
43 g.tagSize = tagSize
44 initGCM(g)
45 return g, nil
46 }
47
48 const (
49 gcmBlockSize = 16
50 gcmTagSize = 16
51 gcmMinimumTagSize = 12
52 gcmStandardNonceSize = 12
53 )
54
55 func (g *GCM) NonceSize() int {
56 return g.nonceSize
57 }
58
59 func (g *GCM) Overhead() int {
60 return g.tagSize
61 }
62
63 func (g *GCM) Seal(dst, nonce, plaintext, data []byte) []byte {
64 fips140.RecordNonApproved()
65 return g.sealAfterIndicator(dst, nonce, plaintext, data)
66 }
67
68 func (g *GCM) sealAfterIndicator(dst, nonce, plaintext, data []byte) []byte {
69 if len(nonce) != g.nonceSize {
70 panic("crypto/cipher: incorrect nonce length given to GCM")
71 }
72 if g.nonceSize == 0 {
73 panic("crypto/cipher: incorrect GCM nonce size")
74 }
75 if uint64(len(plaintext)) > uint64((1<<32)-2)*gcmBlockSize {
76 panic("crypto/cipher: message too large for GCM")
77 }
78
79 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
80 if alias.InexactOverlap(out, plaintext) {
81 panic("crypto/cipher: invalid buffer overlap of output and input")
82 }
83 if alias.AnyOverlap(out, data) {
84 panic("crypto/cipher: invalid buffer overlap of output and additional data")
85 }
86
87 seal(out, g, nonce, plaintext, data)
88 return ret
89 }
90
91 var errOpen = errors.New("cipher: message authentication failed")
92
93 func (g *GCM) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
94 if len(nonce) != g.nonceSize {
95 panic("crypto/cipher: incorrect nonce length given to GCM")
96 }
97
98
99 if g.tagSize < gcmMinimumTagSize {
100 panic("crypto/cipher: incorrect GCM tag size")
101 }
102
103 if len(ciphertext) < g.tagSize {
104 return nil, errOpen
105 }
106 if uint64(len(ciphertext)) > uint64((1<<32)-2)*gcmBlockSize+uint64(g.tagSize) {
107 return nil, errOpen
108 }
109
110 ret, out := sliceForAppend(dst, len(ciphertext)-g.tagSize)
111 if alias.InexactOverlap(out, ciphertext) {
112 panic("crypto/cipher: invalid buffer overlap of output and input")
113 }
114 if alias.AnyOverlap(out, data) {
115 panic("crypto/cipher: invalid buffer overlap of output and additional data")
116 }
117
118 fips140.RecordApproved()
119 if err := open(out, g, nonce, ciphertext, data); err != nil {
120
121
122
123
124 clear(out)
125 return nil, err
126 }
127 return ret, nil
128 }
129
130
131
132
133
134 func sliceForAppend(in []byte, n int) (head, tail []byte) {
135 if total := len(in) + n; cap(in) >= total {
136 head = in[:total]
137 } else {
138 head = make([]byte, total)
139 copy(head, in)
140 }
141 tail = head[len(in):]
142 return
143 }
144
View as plain text