github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/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/subtle" 10 "errors" 11 ) 12 13 // gcmCount represents a 16-byte big-endian count value. 14 type gcmCount [16]byte 15 16 // inc increments the rightmost 32-bits of the count value by 1. 17 func (x *gcmCount) inc() { 18 // The compiler should optimize this to a 32-bit addition. 19 n := uint32(x[15]) | uint32(x[14])<<8 | uint32(x[13])<<16 | uint32(x[12])<<24 20 n += 1 21 x[12] = byte(n >> 24) 22 x[13] = byte(n >> 16) 23 x[14] = byte(n >> 8) 24 x[15] = byte(n) 25 } 26 27 // gcmLengths writes len0 || len1 as big-endian values to a 16-byte array. 28 func gcmLengths(len0, len1 uint64) [16]byte { 29 return [16]byte{ 30 byte(len0 >> 56), 31 byte(len0 >> 48), 32 byte(len0 >> 40), 33 byte(len0 >> 32), 34 byte(len0 >> 24), 35 byte(len0 >> 16), 36 byte(len0 >> 8), 37 byte(len0), 38 byte(len1 >> 56), 39 byte(len1 >> 48), 40 byte(len1 >> 40), 41 byte(len1 >> 32), 42 byte(len1 >> 24), 43 byte(len1 >> 16), 44 byte(len1 >> 8), 45 byte(len1), 46 } 47 } 48 49 // gcmHashKey represents the 16-byte hash key required by the GHASH algorithm. 50 type gcmHashKey [16]byte 51 52 type gcmAsm struct { 53 block *aesCipherAsm 54 hashKey gcmHashKey 55 nonceSize int 56 } 57 58 const ( 59 gcmBlockSize = 16 60 gcmTagSize = 16 61 gcmStandardNonceSize = 12 62 ) 63 64 var errOpen = errors.New("cipher: message authentication failed") 65 66 // Assert that aesCipherAsm implements the gcmAble interface. 67 var _ gcmAble = (*aesCipherAsm)(nil) 68 69 // NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only 70 // called by crypto/cipher.NewGCM via the gcmAble interface. 71 func (c *aesCipherAsm) NewGCM(nonceSize int) (cipher.AEAD, error) { 72 var hk gcmHashKey 73 c.Encrypt(hk[:], hk[:]) 74 g := &gcmAsm{ 75 block: c, 76 hashKey: hk, 77 nonceSize: nonceSize, 78 } 79 return g, nil 80 } 81 82 func (g *gcmAsm) NonceSize() int { 83 return g.nonceSize 84 } 85 86 func (*gcmAsm) Overhead() int { 87 return gcmTagSize 88 } 89 90 // sliceForAppend takes a slice and a requested number of bytes. It returns a 91 // slice with the contents of the given slice followed by that many bytes and a 92 // second slice that aliases into it and contains only the extra bytes. If the 93 // original slice has sufficient capacity then no allocation is performed. 94 func sliceForAppend(in []byte, n int) (head, tail []byte) { 95 if total := len(in) + n; cap(in) >= total { 96 head = in[:total] 97 } else { 98 head = make([]byte, total) 99 copy(head, in) 100 } 101 tail = head[len(in):] 102 return 103 } 104 105 // ghash uses the GHASH algorithm to hash data with the given key. The initial 106 // hash value is given by hash which will be updated with the new hash value. 107 // The length of data must be a multiple of 16-bytes. 108 //go:noescape 109 func ghash(key *gcmHashKey, hash *[16]byte, data []byte) 110 111 // paddedGHASH pads data with zeroes until its length is a multiple of 112 // 16-bytes. It then calculates a new value for hash using the GHASH algorithm. 113 func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) { 114 siz := len(data) &^ 0xf // align size to 16-bytes 115 if siz > 0 { 116 ghash(&g.hashKey, hash, data[:siz]) 117 data = data[siz:] 118 } 119 if len(data) > 0 { 120 var s [16]byte 121 copy(s[:], data) 122 ghash(&g.hashKey, hash, s[:]) 123 } 124 } 125 126 // cryptBlocksGCM encrypts src using AES in counter mode using the given 127 // function code and key. The rightmost 32-bits of the counter are incremented 128 // between each block as required by the GCM spec. The initial counter value 129 // is given by cnt, which is updated with the value of the next counter value 130 // to use. 131 // 132 // The lengths of both dst and buf must be greater than or equal to the length 133 // of src. buf may be partially or completely overwritten during the execution 134 // of the function. 135 //go:noescape 136 func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *gcmCount) 137 138 // counterCrypt encrypts src using AES in counter mode and places the result 139 // into dst. cnt is the initial count value and will be updated with the next 140 // count value. The length of dst must be greater than or equal to the length 141 // of src. 142 func (g *gcmAsm) counterCrypt(dst, src []byte, cnt *gcmCount) { 143 // Copying src into a buffer improves performance on some models when 144 // src and dst point to the same underlying array. We also need a 145 // buffer for counter values. 146 var ctrbuf, srcbuf [2048]byte 147 for len(src) >= 16 { 148 siz := len(src) 149 if len(src) > len(ctrbuf) { 150 siz = len(ctrbuf) 151 } 152 siz &^= 0xf // align siz to 16-bytes 153 copy(srcbuf[:], src[:siz]) 154 cryptBlocksGCM(g.block.function, g.block.key, dst[:siz], srcbuf[:siz], ctrbuf[:], cnt) 155 src = src[siz:] 156 dst = dst[siz:] 157 } 158 if len(src) > 0 { 159 var x [16]byte 160 g.block.Encrypt(x[:], cnt[:]) 161 for i := range src { 162 dst[i] = src[i] ^ x[i] 163 } 164 cnt.inc() 165 } 166 } 167 168 // deriveCounter computes the initial GCM counter state from the given nonce. 169 // See NIST SP 800-38D, section 7.1. 170 func (g *gcmAsm) deriveCounter(nonce []byte) gcmCount { 171 // GCM has two modes of operation with respect to the initial counter 172 // state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path" 173 // for nonces of other lengths. For a 96-bit nonce, the nonce, along 174 // with a four-byte big-endian counter starting at one, is used 175 // directly as the starting counter. For other nonce sizes, the counter 176 // is computed by passing it through the GHASH function. 177 var counter gcmCount 178 if len(nonce) == gcmStandardNonceSize { 179 copy(counter[:], nonce) 180 counter[gcmBlockSize-1] = 1 181 } else { 182 var hash [16]byte 183 g.paddedGHASH(&hash, nonce) 184 lens := gcmLengths(0, uint64(len(nonce))*8) 185 g.paddedGHASH(&hash, lens[:]) 186 copy(counter[:], hash[:]) 187 } 188 return counter 189 } 190 191 // auth calculates GHASH(ciphertext, additionalData), masks the result with 192 // tagMask and writes the result to out. 193 func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) { 194 var hash [16]byte 195 g.paddedGHASH(&hash, additionalData) 196 g.paddedGHASH(&hash, ciphertext) 197 lens := gcmLengths(uint64(len(additionalData))*8, uint64(len(ciphertext))*8) 198 g.paddedGHASH(&hash, lens[:]) 199 200 copy(out, hash[:]) 201 for i := range out { 202 out[i] ^= tagMask[i] 203 } 204 } 205 206 // Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for 207 // details. 208 func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { 209 if len(nonce) != g.nonceSize { 210 panic("cipher: incorrect nonce length given to GCM") 211 } 212 if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize { 213 panic("cipher: message too large for GCM") 214 } 215 216 ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize) 217 218 counter := g.deriveCounter(nonce) 219 220 var tagMask [gcmBlockSize]byte 221 g.block.Encrypt(tagMask[:], counter[:]) 222 counter.inc() 223 224 g.counterCrypt(out, plaintext, &counter) 225 g.auth(out[len(plaintext):], out[:len(plaintext)], data, &tagMask) 226 227 return ret 228 } 229 230 // Open authenticates and decrypts ciphertext. See the cipher.AEAD interface 231 // for details. 232 func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { 233 if len(nonce) != g.nonceSize { 234 panic("cipher: incorrect nonce length given to GCM") 235 } 236 if len(ciphertext) < gcmTagSize { 237 return nil, errOpen 238 } 239 if uint64(len(ciphertext)) > ((1<<32)-2)*BlockSize+gcmTagSize { 240 return nil, errOpen 241 } 242 243 tag := ciphertext[len(ciphertext)-gcmTagSize:] 244 ciphertext = ciphertext[:len(ciphertext)-gcmTagSize] 245 246 counter := g.deriveCounter(nonce) 247 248 var tagMask [gcmBlockSize]byte 249 g.block.Encrypt(tagMask[:], counter[:]) 250 counter.inc() 251 252 var expectedTag [gcmTagSize]byte 253 g.auth(expectedTag[:], ciphertext, data, &tagMask) 254 255 ret, out := sliceForAppend(dst, len(ciphertext)) 256 257 if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 { 258 // The AESNI code decrypts and authenticates concurrently, and 259 // so overwrites dst in the event of a tag mismatch. That 260 // behavior is mimicked here in order to be consistent across 261 // platforms. 262 for i := range out { 263 out[i] = 0 264 } 265 return nil, errOpen 266 } 267 268 g.counterCrypt(out, ciphertext, &counter) 269 return ret, nil 270 }