1
2
3
4
5 package cipher
6
7 import (
8 "crypto/internal/alias"
9 "crypto/subtle"
10 "errors"
11 "internal/byteorder"
12 )
13
14
15
16
17 type AEAD interface {
18
19
20 NonceSize() int
21
22
23
24 Overhead() int
25
26
27
28
29
30
31
32
33 Seal(dst, nonce, plaintext, additionalData []byte) []byte
34
35
36
37
38
39
40
41
42
43
44
45
46 Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error)
47 }
48
49
50
51
52 type gcmAble interface {
53 NewGCM(nonceSize, tagSize int) (AEAD, error)
54 }
55
56
57
58
59
60
61
62
63
64 type gcmFieldElement struct {
65 low, high uint64
66 }
67
68
69
70 type gcm struct {
71 cipher Block
72 nonceSize int
73 tagSize int
74
75
76 productTable [16]gcmFieldElement
77 }
78
79
80
81
82
83
84
85 func NewGCM(cipher Block) (AEAD, error) {
86 return newGCMWithNonceAndTagSize(cipher, gcmStandardNonceSize, gcmTagSize)
87 }
88
89
90
91
92
93
94
95
96 func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
97 return newGCMWithNonceAndTagSize(cipher, size, gcmTagSize)
98 }
99
100
101
102
103
104
105
106
107
108 func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error) {
109 return newGCMWithNonceAndTagSize(cipher, gcmStandardNonceSize, tagSize)
110 }
111
112 func newGCMWithNonceAndTagSize(cipher Block, nonceSize, tagSize int) (AEAD, error) {
113 if tagSize < gcmMinimumTagSize || tagSize > gcmBlockSize {
114 return nil, errors.New("cipher: incorrect tag size given to GCM")
115 }
116
117 if nonceSize <= 0 {
118 return nil, errors.New("cipher: the nonce can't have zero length, or the security of the key will be immediately compromised")
119 }
120
121 if cipher, ok := cipher.(gcmAble); ok {
122 return cipher.NewGCM(nonceSize, tagSize)
123 }
124
125 if cipher.BlockSize() != gcmBlockSize {
126 return nil, errors.New("cipher: NewGCM requires 128-bit block cipher")
127 }
128
129 var key [gcmBlockSize]byte
130 cipher.Encrypt(key[:], key[:])
131
132 g := &gcm{cipher: cipher, nonceSize: nonceSize, tagSize: tagSize}
133
134
135
136
137
138
139 x := gcmFieldElement{
140 byteorder.BeUint64(key[:8]),
141 byteorder.BeUint64(key[8:]),
142 }
143 g.productTable[reverseBits(1)] = x
144
145 for i := 2; i < 16; i += 2 {
146 g.productTable[reverseBits(i)] = gcmDouble(&g.productTable[reverseBits(i/2)])
147 g.productTable[reverseBits(i+1)] = gcmAdd(&g.productTable[reverseBits(i)], &x)
148 }
149
150 return g, nil
151 }
152
153 const (
154 gcmBlockSize = 16
155 gcmTagSize = 16
156 gcmMinimumTagSize = 12
157 gcmStandardNonceSize = 12
158 )
159
160 func (g *gcm) NonceSize() int {
161 return g.nonceSize
162 }
163
164 func (g *gcm) Overhead() int {
165 return g.tagSize
166 }
167
168 func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
169 if len(nonce) != g.nonceSize {
170 panic("crypto/cipher: incorrect nonce length given to GCM")
171 }
172 if uint64(len(plaintext)) > ((1<<32)-2)*uint64(g.cipher.BlockSize()) {
173 panic("crypto/cipher: message too large for GCM")
174 }
175
176 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
177 if alias.InexactOverlap(out, plaintext) {
178 panic("crypto/cipher: invalid buffer overlap")
179 }
180
181 var counter, tagMask [gcmBlockSize]byte
182 g.deriveCounter(&counter, nonce)
183
184 g.cipher.Encrypt(tagMask[:], counter[:])
185 gcmInc32(&counter)
186
187 g.counterCrypt(out, plaintext, &counter)
188
189 var tag [gcmTagSize]byte
190 g.auth(tag[:], out[:len(plaintext)], data, &tagMask)
191 copy(out[len(plaintext):], tag[:])
192
193 return ret
194 }
195
196 var errOpen = errors.New("cipher: message authentication failed")
197
198 func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
199 if len(nonce) != g.nonceSize {
200 panic("crypto/cipher: incorrect nonce length given to GCM")
201 }
202
203
204 if g.tagSize < gcmMinimumTagSize {
205 panic("crypto/cipher: incorrect GCM tag size")
206 }
207
208 if len(ciphertext) < g.tagSize {
209 return nil, errOpen
210 }
211 if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(g.cipher.BlockSize())+uint64(g.tagSize) {
212 return nil, errOpen
213 }
214
215 tag := ciphertext[len(ciphertext)-g.tagSize:]
216 ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
217
218 var counter, tagMask [gcmBlockSize]byte
219 g.deriveCounter(&counter, nonce)
220
221 g.cipher.Encrypt(tagMask[:], counter[:])
222 gcmInc32(&counter)
223
224 var expectedTag [gcmTagSize]byte
225 g.auth(expectedTag[:], ciphertext, data, &tagMask)
226
227 ret, out := sliceForAppend(dst, len(ciphertext))
228 if alias.InexactOverlap(out, ciphertext) {
229 panic("crypto/cipher: invalid buffer overlap")
230 }
231
232 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
233
234
235
236
237 clear(out)
238 return nil, errOpen
239 }
240
241 g.counterCrypt(out, ciphertext, &counter)
242
243 return ret, nil
244 }
245
246
247 func reverseBits(i int) int {
248 i = ((i << 2) & 0xc) | ((i >> 2) & 0x3)
249 i = ((i << 1) & 0xa) | ((i >> 1) & 0x5)
250 return i
251 }
252
253
254 func gcmAdd(x, y *gcmFieldElement) gcmFieldElement {
255
256 return gcmFieldElement{x.low ^ y.low, x.high ^ y.high}
257 }
258
259
260 func gcmDouble(x *gcmFieldElement) (double gcmFieldElement) {
261 msbSet := x.high&1 == 1
262
263
264 double.high = x.high >> 1
265 double.high |= x.low << 63
266 double.low = x.low >> 1
267
268
269
270
271
272
273
274
275 if msbSet {
276 double.low ^= 0xe100000000000000
277 }
278
279 return
280 }
281
282 var gcmReductionTable = []uint16{
283 0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0,
284 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0,
285 }
286
287
288 func (g *gcm) mul(y *gcmFieldElement) {
289 var z gcmFieldElement
290
291 for i := 0; i < 2; i++ {
292 word := y.high
293 if i == 1 {
294 word = y.low
295 }
296
297
298
299 for j := 0; j < 64; j += 4 {
300 msw := z.high & 0xf
301 z.high >>= 4
302 z.high |= z.low << 60
303 z.low >>= 4
304 z.low ^= uint64(gcmReductionTable[msw]) << 48
305
306
307
308
309 t := &g.productTable[word&0xf]
310
311 z.low ^= t.low
312 z.high ^= t.high
313 word >>= 4
314 }
315 }
316
317 *y = z
318 }
319
320
321
322 func (g *gcm) updateBlocks(y *gcmFieldElement, blocks []byte) {
323 for len(blocks) > 0 {
324 y.low ^= byteorder.BeUint64(blocks)
325 y.high ^= byteorder.BeUint64(blocks[8:])
326 g.mul(y)
327 blocks = blocks[gcmBlockSize:]
328 }
329 }
330
331
332
333 func (g *gcm) update(y *gcmFieldElement, data []byte) {
334 fullBlocks := (len(data) >> 4) << 4
335 g.updateBlocks(y, data[:fullBlocks])
336
337 if len(data) != fullBlocks {
338 var partialBlock [gcmBlockSize]byte
339 copy(partialBlock[:], data[fullBlocks:])
340 g.updateBlocks(y, partialBlock[:])
341 }
342 }
343
344
345
346 func gcmInc32(counterBlock *[16]byte) {
347 ctr := counterBlock[len(counterBlock)-4:]
348 byteorder.BePutUint32(ctr, byteorder.BeUint32(ctr)+1)
349 }
350
351
352
353
354
355 func sliceForAppend(in []byte, n int) (head, tail []byte) {
356 if total := len(in) + n; cap(in) >= total {
357 head = in[:total]
358 } else {
359 head = make([]byte, total)
360 copy(head, in)
361 }
362 tail = head[len(in):]
363 return
364 }
365
366
367 func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
368 var mask [gcmBlockSize]byte
369
370 for len(in) >= gcmBlockSize {
371 g.cipher.Encrypt(mask[:], counter[:])
372 gcmInc32(counter)
373
374 subtle.XORBytes(out, in, mask[:])
375 out = out[gcmBlockSize:]
376 in = in[gcmBlockSize:]
377 }
378
379 if len(in) > 0 {
380 g.cipher.Encrypt(mask[:], counter[:])
381 gcmInc32(counter)
382 subtle.XORBytes(out, in, mask[:])
383 }
384 }
385
386
387
388
389 func (g *gcm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) {
390
391
392
393
394
395
396 if len(nonce) == gcmStandardNonceSize {
397 copy(counter[:], nonce)
398 counter[gcmBlockSize-1] = 1
399 } else {
400 var y gcmFieldElement
401 g.update(&y, nonce)
402 y.high ^= uint64(len(nonce)) * 8
403 g.mul(&y)
404 byteorder.BePutUint64(counter[:8], y.low)
405 byteorder.BePutUint64(counter[8:], y.high)
406 }
407 }
408
409
410
411 func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
412 var y gcmFieldElement
413 g.update(&y, additionalData)
414 g.update(&y, ciphertext)
415
416 y.low ^= uint64(len(additionalData)) * 8
417 y.high ^= uint64(len(ciphertext)) * 8
418
419 g.mul(&y)
420
421 byteorder.BePutUint64(out, y.low)
422 byteorder.BePutUint64(out[8:], y.high)
423
424 subtle.XORBytes(out, out, tagMask[:])
425 }
426
View as plain text