github.com/dorkamotorka/go/src@v0.0.0-20230614113921-187095f0e316/crypto/aes/gcm_s390x.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package aes 6 7 import ( 8 "crypto/cipher" 9 "crypto/internal/alias" 10 "crypto/subtle" 11 "encoding/binary" 12 "errors" 13 "internal/cpu" 14 ) 15 16 // This file contains two implementations of AES-GCM. The first implementation 17 // (gcmAsm) uses the KMCTR instruction to encrypt using AES in counter mode and 18 // the KIMD instruction for GHASH. The second implementation (gcmKMA) uses the 19 // newer KMA instruction which performs both operations. 20 21 // gcmCount represents a 16-byte big-endian count value. 22 type gcmCount [16]byte 23 24 // inc increments the rightmost 32-bits of the count value by 1. 25 func (x *gcmCount) inc() { 26 binary.BigEndian.PutUint32(x[len(x)-4:], binary.BigEndian.Uint32(x[len(x)-4:])+1) 27 } 28 29 // gcmLengths writes len0 || len1 as big-endian values to a 16-byte array. 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 // gcmHashKey represents the 16-byte hash key required by the GHASH algorithm. 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 // NIST SP 800-38D recommends tags with 12 or more bytes. 51 gcmStandardNonceSize = 12 52 ) 53 54 var errOpen = errors.New("cipher: message authentication failed") 55 56 // Assert that aesCipherAsm implements the gcmAble interface. 57 var _ gcmAble = (*aesCipherAsm)(nil) 58 59 // NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only 60 // called by crypto/cipher.NewGCM via the gcmAble interface. 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 // sliceForAppend takes a slice and a requested number of bytes. It returns a 86 // slice with the contents of the given slice followed by that many bytes and a 87 // second slice that aliases into it and contains only the extra bytes. If the 88 // original slice has sufficient capacity then no allocation is performed. 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 // ghash uses the GHASH algorithm to hash data with the given key. The initial 101 // hash value is given by hash which will be updated with the new hash value. 102 // The length of data must be a multiple of 16-bytes. 103 // 104 //go:noescape 105 func ghash(key *gcmHashKey, hash *[16]byte, data []byte) 106 107 // paddedGHASH pads data with zeroes until its length is a multiple of 108 // 16-bytes. It then calculates a new value for hash using the GHASH algorithm. 109 func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) { 110 siz := len(data) &^ 0xf // align size to 16-bytes 111 if siz > 0 { 112 ghash(&g.hashKey, hash, data[:siz]) 113 data = data[siz:] 114 } 115 if len(data) > 0 { 116 var s [16]byte 117 copy(s[:], data) 118 ghash(&g.hashKey, hash, s[:]) 119 } 120 } 121 122 // cryptBlocksGCM encrypts src using AES in counter mode using the given 123 // function code and key. The rightmost 32-bits of the counter are incremented 124 // between each block as required by the GCM spec. The initial counter value 125 // is given by cnt, which is updated with the value of the next counter value 126 // to use. 127 // 128 // The lengths of both dst and buf must be greater than or equal to the length 129 // of src. buf may be partially or completely overwritten during the execution 130 // of the function. 131 // 132 //go:noescape 133 func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *gcmCount) 134 135 // counterCrypt encrypts src using AES in counter mode and places the result 136 // into dst. cnt is the initial count value and will be updated with the next 137 // count value. The length of dst must be greater than or equal to the length 138 // of src. 139 func (g *gcmAsm) counterCrypt(dst, src []byte, cnt *gcmCount) { 140 // Copying src into a buffer improves performance on some models when 141 // src and dst point to the same underlying array. We also need a 142 // buffer for counter values. 143 var ctrbuf, srcbuf [2048]byte 144 for len(src) >= 16 { 145 siz := len(src) 146 if len(src) > len(ctrbuf) { 147 siz = len(ctrbuf) 148 } 149 siz &^= 0xf // align siz to 16-bytes 150 copy(srcbuf[:], src[:siz]) 151 cryptBlocksGCM(g.block.function, g.block.key, dst[:siz], srcbuf[:siz], ctrbuf[:], cnt) 152 src = src[siz:] 153 dst = dst[siz:] 154 } 155 if len(src) > 0 { 156 var x [16]byte 157 g.block.Encrypt(x[:], cnt[:]) 158 for i := range src { 159 dst[i] = src[i] ^ x[i] 160 } 161 cnt.inc() 162 } 163 } 164 165 // deriveCounter computes the initial GCM counter state from the given nonce. 166 // See NIST SP 800-38D, section 7.1. 167 func (g *gcmAsm) deriveCounter(nonce []byte) gcmCount { 168 // GCM has two modes of operation with respect to the initial counter 169 // state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path" 170 // for nonces of other lengths. For a 96-bit nonce, the nonce, along 171 // with a four-byte big-endian counter starting at one, is used 172 // directly as the starting counter. For other nonce sizes, the counter 173 // is computed by passing it through the GHASH function. 174 var counter gcmCount 175 if len(nonce) == gcmStandardNonceSize { 176 copy(counter[:], nonce) 177 counter[gcmBlockSize-1] = 1 178 } else { 179 var hash [16]byte 180 g.paddedGHASH(&hash, nonce) 181 lens := gcmLengths(0, uint64(len(nonce))*8) 182 g.paddedGHASH(&hash, lens[:]) 183 copy(counter[:], hash[:]) 184 } 185 return counter 186 } 187 188 // auth calculates GHASH(ciphertext, additionalData), masks the result with 189 // tagMask and writes the result to out. 190 func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) { 191 var hash [16]byte 192 g.paddedGHASH(&hash, additionalData) 193 g.paddedGHASH(&hash, ciphertext) 194 lens := gcmLengths(uint64(len(additionalData))*8, uint64(len(ciphertext))*8) 195 g.paddedGHASH(&hash, lens[:]) 196 197 copy(out, hash[:]) 198 for i := range out { 199 out[i] ^= tagMask[i] 200 } 201 } 202 203 // Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for 204 // details. 205 func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { 206 if len(nonce) != g.nonceSize { 207 panic("crypto/cipher: incorrect nonce length given to GCM") 208 } 209 if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize { 210 panic("crypto/cipher: message too large for GCM") 211 } 212 213 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) 214 if alias.InexactOverlap(out[:len(plaintext)], plaintext) { 215 panic("crypto/cipher: invalid buffer overlap") 216 } 217 218 counter := g.deriveCounter(nonce) 219 220 var tagMask [gcmBlockSize]byte 221 g.block.Encrypt(tagMask[:], counter[:]) 222 counter.inc() 223 224 var tagOut [gcmTagSize]byte 225 g.counterCrypt(out, plaintext, &counter) 226 g.auth(tagOut[:], out[:len(plaintext)], data, &tagMask) 227 copy(out[len(plaintext):], tagOut[:]) 228 229 return ret 230 } 231 232 // Open authenticates and decrypts ciphertext. See the cipher.AEAD interface 233 // for details. 234 func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { 235 if len(nonce) != g.nonceSize { 236 panic("crypto/cipher: incorrect nonce length given to GCM") 237 } 238 // Sanity check to prevent the authentication from always succeeding if an implementation 239 // leaves tagSize uninitialized, for example. 240 if g.tagSize < gcmMinimumTagSize { 241 panic("crypto/cipher: incorrect GCM tag size") 242 } 243 if len(ciphertext) < g.tagSize { 244 return nil, errOpen 245 } 246 if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) { 247 return nil, errOpen 248 } 249 250 tag := ciphertext[len(ciphertext)-g.tagSize:] 251 ciphertext = ciphertext[:len(ciphertext)-g.tagSize] 252 253 counter := g.deriveCounter(nonce) 254 255 var tagMask [gcmBlockSize]byte 256 g.block.Encrypt(tagMask[:], counter[:]) 257 counter.inc() 258 259 var expectedTag [gcmTagSize]byte 260 g.auth(expectedTag[:], ciphertext, data, &tagMask) 261 262 ret, out := sliceForAppend(dst, len(ciphertext)) 263 if alias.InexactOverlap(out, ciphertext) { 264 panic("crypto/cipher: invalid buffer overlap") 265 } 266 267 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { 268 // The AESNI code decrypts and authenticates concurrently, and 269 // so overwrites dst in the event of a tag mismatch. That 270 // behavior is mimicked here in order to be consistent across 271 // platforms. 272 for i := range out { 273 out[i] = 0 274 } 275 return nil, errOpen 276 } 277 278 g.counterCrypt(out, ciphertext, &counter) 279 return ret, nil 280 } 281 282 // gcmKMA implements the cipher.AEAD interface using the KMA instruction. It should 283 // only be used if hasKMA is true. 284 type gcmKMA struct { 285 gcmAsm 286 } 287 288 // flags for the KMA instruction 289 const ( 290 kmaHS = 1 << 10 // hash subkey supplied 291 kmaLAAD = 1 << 9 // last series of additional authenticated data 292 kmaLPC = 1 << 8 // last series of plaintext or ciphertext blocks 293 kmaDecrypt = 1 << 7 // decrypt 294 ) 295 296 // kmaGCM executes the encryption or decryption operation given by fn. The tag 297 // will be calculated and written to tag. cnt should contain the current 298 // counter state and will be overwritten with the updated counter state. 299 // TODO(mundaym): could pass in hash subkey 300 // 301 //go:noescape 302 func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount) 303 304 // Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for 305 // details. 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 // Open authenticates and decrypts ciphertext. See the cipher.AEAD interface 330 // for details. 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 // The AESNI code decrypts and authenticates concurrently, and 361 // so overwrites dst in the event of a tag mismatch. That 362 // behavior is mimicked here in order to be consistent across 363 // platforms. 364 for i := range out { 365 out[i] = 0 366 } 367 return nil, errOpen 368 } 369 370 return ret, nil 371 }