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