Source file
src/crypto/aes/aes_gcm.go
1
2
3
4
5
6
7 package aes
8
9 import (
10 "crypto/cipher"
11 "crypto/internal/alias"
12 "crypto/subtle"
13 "errors"
14 )
15
16
17
18
19 func gcmAesInit(productTable *[256]byte, ks []uint32)
20
21
22 func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte)
23
24
25 func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
26
27
28 func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
29
30
31 func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64)
32
33 const (
34 gcmBlockSize = 16
35 gcmTagSize = 16
36 gcmMinimumTagSize = 12
37 gcmStandardNonceSize = 12
38 )
39
40 var errOpen = errors.New("cipher: message authentication failed")
41
42
43 var _ gcmAble = (*aesCipherGCM)(nil)
44
45
46
47 func (c *aesCipherGCM) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
48 g := &gcmAsm{ks: c.enc[:c.l], nonceSize: nonceSize, tagSize: tagSize}
49 gcmAesInit(&g.productTable, g.ks)
50 return g, nil
51 }
52
53 type gcmAsm struct {
54
55
56 ks []uint32
57
58
59 productTable [256]byte
60
61 nonceSize int
62
63 tagSize int
64 }
65
66 func (g *gcmAsm) NonceSize() int {
67 return g.nonceSize
68 }
69
70 func (g *gcmAsm) Overhead() int {
71 return g.tagSize
72 }
73
74
75
76
77
78 func sliceForAppend(in []byte, n int) (head, tail []byte) {
79 if total := len(in) + n; cap(in) >= total {
80 head = in[:total]
81 } else {
82 head = make([]byte, total)
83 copy(head, in)
84 }
85 tail = head[len(in):]
86 return
87 }
88
89
90
91 func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
92 if len(nonce) != g.nonceSize {
93 panic("crypto/cipher: incorrect nonce length given to GCM")
94 }
95 if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
96 panic("crypto/cipher: message too large for GCM")
97 }
98
99 var counter, tagMask [gcmBlockSize]byte
100
101 if len(nonce) == gcmStandardNonceSize {
102
103 copy(counter[:], nonce)
104 counter[gcmBlockSize-1] = 1
105 } else {
106
107 gcmAesData(&g.productTable, nonce, &counter)
108 gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
109 }
110
111 encryptBlockAsm(len(g.ks)/4-1, &g.ks[0], &tagMask[0], &counter[0])
112
113 var tagOut [gcmTagSize]byte
114 gcmAesData(&g.productTable, data, &tagOut)
115
116 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
117 if alias.InexactOverlap(out[:len(plaintext)], plaintext) {
118 panic("crypto/cipher: invalid buffer overlap")
119 }
120 if len(plaintext) > 0 {
121 gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks)
122 }
123 gcmAesFinish(&g.productTable, &tagMask, &tagOut, uint64(len(plaintext)), uint64(len(data)))
124 copy(out[len(plaintext):], tagOut[:])
125
126 return ret
127 }
128
129
130
131 func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
132 if len(nonce) != g.nonceSize {
133 panic("crypto/cipher: incorrect nonce length given to GCM")
134 }
135
136
137 if g.tagSize < gcmMinimumTagSize {
138 panic("crypto/cipher: incorrect GCM tag size")
139 }
140
141 if len(ciphertext) < g.tagSize {
142 return nil, errOpen
143 }
144 if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
145 return nil, errOpen
146 }
147
148 tag := ciphertext[len(ciphertext)-g.tagSize:]
149 ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
150
151
152 var counter, tagMask [gcmBlockSize]byte
153
154 if len(nonce) == gcmStandardNonceSize {
155
156 copy(counter[:], nonce)
157 counter[gcmBlockSize-1] = 1
158 } else {
159
160 gcmAesData(&g.productTable, nonce, &counter)
161 gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
162 }
163
164 encryptBlockAsm(len(g.ks)/4-1, &g.ks[0], &tagMask[0], &counter[0])
165
166 var expectedTag [gcmTagSize]byte
167 gcmAesData(&g.productTable, data, &expectedTag)
168
169 ret, out := sliceForAppend(dst, len(ciphertext))
170 if alias.InexactOverlap(out, ciphertext) {
171 panic("crypto/cipher: invalid buffer overlap")
172 }
173 if len(ciphertext) > 0 {
174 gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks)
175 }
176 gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data)))
177
178 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
179 clear(out)
180 return nil, errOpen
181 }
182
183 return ret, nil
184 }
185
View as plain text