1
2
3
4
5 package cipher
6
7 import (
8 "crypto/internal/fips140/aes"
9 "crypto/internal/fips140/aes/gcm"
10 "crypto/internal/fips140/alias"
11 "crypto/internal/fips140only"
12 "crypto/subtle"
13 "errors"
14 "internal/byteorder"
15 )
16
17 const (
18 gcmBlockSize = 16
19 gcmStandardNonceSize = 12
20 gcmTagSize = 16
21 gcmMinimumTagSize = 12
22 )
23
24
25
26 func NewGCM(cipher Block) (AEAD, error) {
27 if fips140only.Enforced() {
28 return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
29 }
30 return newGCM(cipher, gcmStandardNonceSize, gcmTagSize)
31 }
32
33
34
35
36
37
38
39
40 func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
41 if fips140only.Enforced() {
42 return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
43 }
44 return newGCM(cipher, size, gcmTagSize)
45 }
46
47
48
49
50
51
52
53
54
55 func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error) {
56 if fips140only.Enforced() {
57 return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
58 }
59 return newGCM(cipher, gcmStandardNonceSize, tagSize)
60 }
61
62 func newGCM(cipher Block, nonceSize, tagSize int) (AEAD, error) {
63 c, ok := cipher.(*aes.Block)
64 if !ok {
65 if fips140only.Enforced() {
66 return nil, errors.New("crypto/cipher: use of GCM with non-AES ciphers is not allowed in FIPS 140-only mode")
67 }
68 return newGCMFallback(cipher, nonceSize, tagSize)
69 }
70
71
72 g, err := gcm.New(c, nonceSize, tagSize)
73 if err != nil {
74 return nil, err
75 }
76 return g, nil
77 }
78
79
80
81
82
83
84
85
86
87
88
89 func NewGCMWithRandomNonce(cipher Block) (AEAD, error) {
90 c, ok := cipher.(*aes.Block)
91 if !ok {
92 return nil, errors.New("cipher: NewGCMWithRandomNonce requires aes.Block")
93 }
94 g, err := gcm.New(c, gcmStandardNonceSize, gcmTagSize)
95 if err != nil {
96 return nil, err
97 }
98 return gcmWithRandomNonce{g}, nil
99 }
100
101 type gcmWithRandomNonce struct {
102 *gcm.GCM
103 }
104
105 func (g gcmWithRandomNonce) NonceSize() int {
106 return 0
107 }
108
109 func (g gcmWithRandomNonce) Overhead() int {
110 return gcmStandardNonceSize + gcmTagSize
111 }
112
113 func (g gcmWithRandomNonce) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
114 if len(nonce) != 0 {
115 panic("crypto/cipher: non-empty nonce passed to GCMWithRandomNonce")
116 }
117
118 ret, out := sliceForAppend(dst, gcmStandardNonceSize+len(plaintext)+gcmTagSize)
119 if alias.InexactOverlap(out, plaintext) {
120 panic("crypto/cipher: invalid buffer overlap of output and input")
121 }
122 if alias.AnyOverlap(out, additionalData) {
123 panic("crypto/cipher: invalid buffer overlap of output and additional data")
124 }
125 nonce = out[:gcmStandardNonceSize]
126 ciphertext := out[gcmStandardNonceSize:]
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151 if alias.AnyOverlap(out, plaintext) {
152 copy(ciphertext, plaintext)
153 plaintext = ciphertext[:len(plaintext)]
154 }
155
156 gcm.SealWithRandomNonce(g.GCM, nonce, ciphertext, plaintext, additionalData)
157 return ret
158 }
159
160 func (g gcmWithRandomNonce) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
161 if len(nonce) != 0 {
162 panic("crypto/cipher: non-empty nonce passed to GCMWithRandomNonce")
163 }
164 if len(ciphertext) < gcmStandardNonceSize+gcmTagSize {
165 return nil, errOpen
166 }
167
168 ret, out := sliceForAppend(dst, len(ciphertext)-gcmStandardNonceSize-gcmTagSize)
169 if alias.InexactOverlap(out, ciphertext) {
170 panic("crypto/cipher: invalid buffer overlap of output and input")
171 }
172 if alias.AnyOverlap(out, additionalData) {
173 panic("crypto/cipher: invalid buffer overlap of output and additional data")
174 }
175
176
177
178
179 if alias.AnyOverlap(out, ciphertext) {
180 nonce = make([]byte, gcmStandardNonceSize)
181 copy(nonce, ciphertext)
182 copy(out[:len(ciphertext)], ciphertext[gcmStandardNonceSize:])
183 ciphertext = out[:len(ciphertext)-gcmStandardNonceSize]
184 } else {
185 nonce = ciphertext[:gcmStandardNonceSize]
186 ciphertext = ciphertext[gcmStandardNonceSize:]
187 }
188
189 _, err := g.GCM.Open(out[:0], nonce, ciphertext, additionalData)
190 if err != nil {
191 return nil, err
192 }
193 return ret, nil
194 }
195
196
197
198
199 type gcmAble interface {
200 NewGCM(nonceSize, tagSize int) (AEAD, error)
201 }
202
203 func newGCMFallback(cipher Block, nonceSize, tagSize int) (AEAD, error) {
204 if tagSize < gcmMinimumTagSize || tagSize > gcmBlockSize {
205 return nil, errors.New("cipher: incorrect tag size given to GCM")
206 }
207 if nonceSize <= 0 {
208 return nil, errors.New("cipher: the nonce can't have zero length")
209 }
210 if cipher, ok := cipher.(gcmAble); ok {
211 return cipher.NewGCM(nonceSize, tagSize)
212 }
213 if cipher.BlockSize() != gcmBlockSize {
214 return nil, errors.New("cipher: NewGCM requires 128-bit block cipher")
215 }
216 return &gcmFallback{cipher: cipher, nonceSize: nonceSize, tagSize: tagSize}, nil
217 }
218
219
220
221
222 type gcmFallback struct {
223 cipher Block
224 nonceSize int
225 tagSize int
226 }
227
228 func (g *gcmFallback) NonceSize() int {
229 return g.nonceSize
230 }
231
232 func (g *gcmFallback) Overhead() int {
233 return g.tagSize
234 }
235
236 func (g *gcmFallback) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
237 if len(nonce) != g.nonceSize {
238 panic("crypto/cipher: incorrect nonce length given to GCM")
239 }
240 if g.nonceSize == 0 {
241 panic("crypto/cipher: incorrect GCM nonce size")
242 }
243 if uint64(len(plaintext)) > uint64((1<<32)-2)*gcmBlockSize {
244 panic("crypto/cipher: message too large for GCM")
245 }
246
247 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
248 if alias.InexactOverlap(out, plaintext) {
249 panic("crypto/cipher: invalid buffer overlap of output and input")
250 }
251 if alias.AnyOverlap(out, additionalData) {
252 panic("crypto/cipher: invalid buffer overlap of output and additional data")
253 }
254
255 var H, counter, tagMask [gcmBlockSize]byte
256 g.cipher.Encrypt(H[:], H[:])
257 deriveCounter(&H, &counter, nonce)
258 gcmCounterCryptGeneric(g.cipher, tagMask[:], tagMask[:], &counter)
259
260 gcmCounterCryptGeneric(g.cipher, out, plaintext, &counter)
261
262 var tag [gcmTagSize]byte
263 gcmAuth(tag[:], &H, &tagMask, out[:len(plaintext)], additionalData)
264 copy(out[len(plaintext):], tag[:])
265
266 return ret
267 }
268
269 var errOpen = errors.New("cipher: message authentication failed")
270
271 func (g *gcmFallback) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
272 if len(nonce) != g.nonceSize {
273 panic("crypto/cipher: incorrect nonce length given to GCM")
274 }
275 if g.tagSize < gcmMinimumTagSize {
276 panic("crypto/cipher: incorrect GCM tag size")
277 }
278
279 if len(ciphertext) < g.tagSize {
280 return nil, errOpen
281 }
282 if uint64(len(ciphertext)) > uint64((1<<32)-2)*gcmBlockSize+uint64(g.tagSize) {
283 return nil, errOpen
284 }
285
286 ret, out := sliceForAppend(dst, len(ciphertext)-g.tagSize)
287 if alias.InexactOverlap(out, ciphertext) {
288 panic("crypto/cipher: invalid buffer overlap of output and input")
289 }
290 if alias.AnyOverlap(out, additionalData) {
291 panic("crypto/cipher: invalid buffer overlap of output and additional data")
292 }
293
294 var H, counter, tagMask [gcmBlockSize]byte
295 g.cipher.Encrypt(H[:], H[:])
296 deriveCounter(&H, &counter, nonce)
297 gcmCounterCryptGeneric(g.cipher, tagMask[:], tagMask[:], &counter)
298
299 tag := ciphertext[len(ciphertext)-g.tagSize:]
300 ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
301
302 var expectedTag [gcmTagSize]byte
303 gcmAuth(expectedTag[:], &H, &tagMask, ciphertext, additionalData)
304 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
305
306
307
308
309 clear(out)
310 return nil, errOpen
311 }
312
313 gcmCounterCryptGeneric(g.cipher, out, ciphertext, &counter)
314
315 return ret, nil
316 }
317
318 func deriveCounter(H, counter *[gcmBlockSize]byte, nonce []byte) {
319 if len(nonce) == gcmStandardNonceSize {
320 copy(counter[:], nonce)
321 counter[gcmBlockSize-1] = 1
322 } else {
323 lenBlock := make([]byte, 16)
324 byteorder.BEPutUint64(lenBlock[8:], uint64(len(nonce))*8)
325 J := gcm.GHASH(H, nonce, lenBlock)
326 copy(counter[:], J)
327 }
328 }
329
330 func gcmCounterCryptGeneric(b Block, out, src []byte, counter *[gcmBlockSize]byte) {
331 var mask [gcmBlockSize]byte
332 for len(src) >= gcmBlockSize {
333 b.Encrypt(mask[:], counter[:])
334 gcmInc32(counter)
335
336 subtle.XORBytes(out, src, mask[:])
337 out = out[gcmBlockSize:]
338 src = src[gcmBlockSize:]
339 }
340 if len(src) > 0 {
341 b.Encrypt(mask[:], counter[:])
342 gcmInc32(counter)
343 subtle.XORBytes(out, src, mask[:])
344 }
345 }
346
347 func gcmInc32(counterBlock *[gcmBlockSize]byte) {
348 ctr := counterBlock[len(counterBlock)-4:]
349 byteorder.BEPutUint32(ctr, byteorder.BEUint32(ctr)+1)
350 }
351
352 func gcmAuth(out []byte, H, tagMask *[gcmBlockSize]byte, ciphertext, additionalData []byte) {
353 lenBlock := make([]byte, 16)
354 byteorder.BEPutUint64(lenBlock[:8], uint64(len(additionalData))*8)
355 byteorder.BEPutUint64(lenBlock[8:], uint64(len(ciphertext))*8)
356 S := gcm.GHASH(H, additionalData, ciphertext, lenBlock)
357 subtle.XORBytes(out, S, tagMask[:])
358 }
359
360
361
362
363
364 func sliceForAppend(in []byte, n int) (head, tail []byte) {
365 if total := len(in) + n; cap(in) >= total {
366 head = in[:total]
367 } else {
368 head = make([]byte, total)
369 copy(head, in)
370 }
371 tail = head[len(in):]
372 return
373 }
374
View as plain text