Source file
src/crypto/aes/gcm_s390x.go
1
2
3
4
5 package aes
6
7 import (
8 "crypto/cipher"
9 subtleoverlap "crypto/internal/subtle"
10 "crypto/subtle"
11 "encoding/binary"
12 "errors"
13 "internal/cpu"
14 )
15
16
17
18
19
20
21
22 type gcmCount [16]byte
23
24
25 func (x *gcmCount) inc() {
26 binary.BigEndian.PutUint32(x[len(x)-4:], binary.BigEndian.Uint32(x[len(x)-4:])+1)
27 }
28
29
30 func gcmLengths(len0, len1 uint64) [16]byte {
31 v := [16]byte{}
32 binary.BigEndian.PutUint64(v[0:], len0)
33 binary.BigEndian.PutUint64(v[8:], len1)
34 return v
35 }
36
37
38 type gcmHashKey [16]byte
39
40 type gcmAsm struct {
41 block *aesCipherAsm
42 hashKey gcmHashKey
43 nonceSize int
44 tagSize int
45 }
46
47 const (
48 gcmBlockSize = 16
49 gcmTagSize = 16
50 gcmMinimumTagSize = 12
51 gcmStandardNonceSize = 12
52 )
53
54 var errOpen = errors.New("cipher: message authentication failed")
55
56
57 var _ gcmAble = (*aesCipherAsm)(nil)
58
59
60
61 func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
62 var hk gcmHashKey
63 c.Encrypt(hk[:], hk[:])
64 g := gcmAsm{
65 block: c,
66 hashKey: hk,
67 nonceSize: nonceSize,
68 tagSize: tagSize,
69 }
70 if cpu.S390X.HasAESGCM {
71 g := gcmKMA{g}
72 return &g, nil
73 }
74 return &g, nil
75 }
76
77 func (g *gcmAsm) NonceSize() int {
78 return g.nonceSize
79 }
80
81 func (g *gcmAsm) Overhead() int {
82 return g.tagSize
83 }
84
85
86
87
88
89 func sliceForAppend(in []byte, n int) (head, tail []byte) {
90 if total := len(in) + n; cap(in) >= total {
91 head = in[:total]
92 } else {
93 head = make([]byte, total)
94 copy(head, in)
95 }
96 tail = head[len(in):]
97 return
98 }
99
100
101
102
103
104 func ghash(key *gcmHashKey, hash *[16]byte, data []byte)
105
106
107
108 func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) {
109 siz := len(data) &^ 0xf
110 if siz > 0 {
111 ghash(&g.hashKey, hash, data[:siz])
112 data = data[siz:]
113 }
114 if len(data) > 0 {
115 var s [16]byte
116 copy(s[:], data)
117 ghash(&g.hashKey, hash, s[:])
118 }
119 }
120
121
122
123
124
125
126
127
128
129
130
131 func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *gcmCount)
132
133
134
135
136
137 func (g *gcmAsm) counterCrypt(dst, src []byte, cnt *gcmCount) {
138
139
140
141 var ctrbuf, srcbuf [2048]byte
142 for len(src) >= 16 {
143 siz := len(src)
144 if len(src) > len(ctrbuf) {
145 siz = len(ctrbuf)
146 }
147 siz &^= 0xf
148 copy(srcbuf[:], src[:siz])
149 cryptBlocksGCM(g.block.function, g.block.key, dst[:siz], srcbuf[:siz], ctrbuf[:], cnt)
150 src = src[siz:]
151 dst = dst[siz:]
152 }
153 if len(src) > 0 {
154 var x [16]byte
155 g.block.Encrypt(x[:], cnt[:])
156 for i := range src {
157 dst[i] = src[i] ^ x[i]
158 }
159 cnt.inc()
160 }
161 }
162
163
164
165 func (g *gcmAsm) deriveCounter(nonce []byte) gcmCount {
166
167
168
169
170
171
172 var counter gcmCount
173 if len(nonce) == gcmStandardNonceSize {
174 copy(counter[:], nonce)
175 counter[gcmBlockSize-1] = 1
176 } else {
177 var hash [16]byte
178 g.paddedGHASH(&hash, nonce)
179 lens := gcmLengths(0, uint64(len(nonce))*8)
180 g.paddedGHASH(&hash, lens[:])
181 copy(counter[:], hash[:])
182 }
183 return counter
184 }
185
186
187
188 func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
189 var hash [16]byte
190 g.paddedGHASH(&hash, additionalData)
191 g.paddedGHASH(&hash, ciphertext)
192 lens := gcmLengths(uint64(len(additionalData))*8, uint64(len(ciphertext))*8)
193 g.paddedGHASH(&hash, lens[:])
194
195 copy(out, hash[:])
196 for i := range out {
197 out[i] ^= tagMask[i]
198 }
199 }
200
201
202
203 func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
204 if len(nonce) != g.nonceSize {
205 panic("crypto/cipher: incorrect nonce length given to GCM")
206 }
207 if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
208 panic("crypto/cipher: message too large for GCM")
209 }
210
211 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
212 if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) {
213 panic("crypto/cipher: invalid buffer overlap")
214 }
215
216 counter := g.deriveCounter(nonce)
217
218 var tagMask [gcmBlockSize]byte
219 g.block.Encrypt(tagMask[:], counter[:])
220 counter.inc()
221
222 var tagOut [gcmTagSize]byte
223 g.counterCrypt(out, plaintext, &counter)
224 g.auth(tagOut[:], out[:len(plaintext)], data, &tagMask)
225 copy(out[len(plaintext):], tagOut[:])
226
227 return ret
228 }
229
230
231
232 func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
233 if len(nonce) != g.nonceSize {
234 panic("crypto/cipher: incorrect nonce length given to GCM")
235 }
236
237
238 if g.tagSize < gcmMinimumTagSize {
239 panic("crypto/cipher: incorrect GCM tag size")
240 }
241 if len(ciphertext) < g.tagSize {
242 return nil, errOpen
243 }
244 if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
245 return nil, errOpen
246 }
247
248 tag := ciphertext[len(ciphertext)-g.tagSize:]
249 ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
250
251 counter := g.deriveCounter(nonce)
252
253 var tagMask [gcmBlockSize]byte
254 g.block.Encrypt(tagMask[:], counter[:])
255 counter.inc()
256
257 var expectedTag [gcmTagSize]byte
258 g.auth(expectedTag[:], ciphertext, data, &tagMask)
259
260 ret, out := sliceForAppend(dst, len(ciphertext))
261 if subtleoverlap.InexactOverlap(out, ciphertext) {
262 panic("crypto/cipher: invalid buffer overlap")
263 }
264
265 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
266
267
268
269
270 for i := range out {
271 out[i] = 0
272 }
273 return nil, errOpen
274 }
275
276 g.counterCrypt(out, ciphertext, &counter)
277 return ret, nil
278 }
279
280
281
282 type gcmKMA struct {
283 gcmAsm
284 }
285
286
287 const (
288 kmaHS = 1 << 10
289 kmaLAAD = 1 << 9
290 kmaLPC = 1 << 8
291 kmaDecrypt = 1 << 7
292 )
293
294
295
296
297
298
299 func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount)
300
301
302
303 func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte {
304 if len(nonce) != g.nonceSize {
305 panic("crypto/cipher: incorrect nonce length given to GCM")
306 }
307 if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
308 panic("crypto/cipher: message too large for GCM")
309 }
310
311 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
312 if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) {
313 panic("crypto/cipher: invalid buffer overlap")
314 }
315
316 counter := g.deriveCounter(nonce)
317 fc := g.block.function | kmaLAAD | kmaLPC
318
319 var tag [gcmTagSize]byte
320 kmaGCM(fc, g.block.key, out[:len(plaintext)], plaintext, data, &tag, &counter)
321 copy(out[len(plaintext):], tag[:])
322
323 return ret
324 }
325
326
327
328 func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
329 if len(nonce) != g.nonceSize {
330 panic("crypto/cipher: incorrect nonce length given to GCM")
331 }
332 if len(ciphertext) < g.tagSize {
333 return nil, errOpen
334 }
335 if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
336 return nil, errOpen
337 }
338
339 tag := ciphertext[len(ciphertext)-g.tagSize:]
340 ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
341 ret, out := sliceForAppend(dst, len(ciphertext))
342 if subtleoverlap.InexactOverlap(out, ciphertext) {
343 panic("crypto/cipher: invalid buffer overlap")
344 }
345
346 if g.tagSize < gcmMinimumTagSize {
347 panic("crypto/cipher: incorrect GCM tag size")
348 }
349
350 counter := g.deriveCounter(nonce)
351 fc := g.block.function | kmaLAAD | kmaLPC | kmaDecrypt
352
353 var expectedTag [gcmTagSize]byte
354 kmaGCM(fc, g.block.key, out[:len(ciphertext)], ciphertext, data, &expectedTag, &counter)
355
356 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
357
358
359
360
361 for i := range out {
362 out[i] = 0
363 }
364 return nil, errOpen
365 }
366
367 return ret, nil
368 }
369
View as plain text