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