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/subtle"
12 "errors"
13 )
14
15
16 func hasGCMAsm() bool
17
18
19 func aesEncBlock(dst, src *[16]byte, ks []uint32)
20
21
22 func gcmAesInit(productTable *[256]byte, ks []uint32)
23
24
25 func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte)
26
27
28 func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
29
30
31 func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
32
33
34 func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64)
35
36 const (
37 gcmBlockSize = 16
38 gcmTagSize = 16
39 gcmStandardNonceSize = 12
40 )
41
42 var errOpen = errors.New("cipher: message authentication failed")
43
44
45
46
47 type aesCipherGCM struct {
48 aesCipherAsm
49 }
50
51
52 var _ gcmAble = (*aesCipherGCM)(nil)
53
54
55
56 func (c *aesCipherGCM) NewGCM(nonceSize int) (cipher.AEAD, error) {
57 g := &gcmAsm{ks: c.enc, nonceSize: nonceSize}
58 gcmAesInit(&g.productTable, g.ks)
59 return g, nil
60 }
61
62 type gcmAsm struct {
63
64
65 ks []uint32
66
67
68 productTable [256]byte
69
70 nonceSize int
71 }
72
73 func (g *gcmAsm) NonceSize() int {
74 return g.nonceSize
75 }
76
77 func (*gcmAsm) Overhead() int {
78 return gcmTagSize
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("cipher: incorrect nonce length given to GCM")
101 }
102 if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
103 panic("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 aesEncBlock(&tagMask, &counter, g.ks)
119
120 var tagOut [gcmTagSize]byte
121 gcmAesData(&g.productTable, data, &tagOut)
122
123 ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize)
124 if len(plaintext) > 0 {
125 gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks)
126 }
127 gcmAesFinish(&g.productTable, &tagMask, &tagOut, uint64(len(plaintext)), uint64(len(data)))
128 copy(out[len(plaintext):], tagOut[:])
129
130 return ret
131 }
132
133
134
135 func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
136 if len(nonce) != g.nonceSize {
137 panic("cipher: incorrect nonce length given to GCM")
138 }
139
140 if len(ciphertext) < gcmTagSize {
141 return nil, errOpen
142 }
143 if uint64(len(ciphertext)) > ((1<<32)-2)*BlockSize+gcmTagSize {
144 return nil, errOpen
145 }
146
147 tag := ciphertext[len(ciphertext)-gcmTagSize:]
148 ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
149
150
151 var counter, tagMask [gcmBlockSize]byte
152
153 if len(nonce) == gcmStandardNonceSize {
154
155 copy(counter[:], nonce)
156 counter[gcmBlockSize-1] = 1
157 } else {
158
159 gcmAesData(&g.productTable, nonce, &counter)
160 gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
161 }
162
163 aesEncBlock(&tagMask, &counter, g.ks)
164
165 var expectedTag [gcmTagSize]byte
166 gcmAesData(&g.productTable, data, &expectedTag)
167
168 ret, out := sliceForAppend(dst, len(ciphertext))
169 if len(ciphertext) > 0 {
170 gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks)
171 }
172 gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data)))
173
174 if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 {
175 for i := range out {
176 out[i] = 0
177 }
178 return nil, errOpen
179 }
180
181 return ret, nil
182 }
183
View as plain text