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