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