github.com/gidoBOSSftw5731/go/src@v0.0.0-20210226122457-d24b0edbf019/crypto/aes/aes_gcm.go (about) 1 // Copyright 2015 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 //go:build amd64 || arm64 6 // +build amd64 arm64 7 8 package aes 9 10 import ( 11 "crypto/cipher" 12 subtleoverlap "crypto/internal/subtle" 13 "crypto/subtle" 14 "errors" 15 ) 16 17 // The following functions are defined in gcm_*.s. 18 19 //go:noescape 20 func gcmAesInit(productTable *[256]byte, ks []uint32) 21 22 //go:noescape 23 func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte) 24 25 //go:noescape 26 func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) 27 28 //go:noescape 29 func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) 30 31 //go:noescape 32 func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64) 33 34 const ( 35 gcmBlockSize = 16 36 gcmTagSize = 16 37 gcmMinimumTagSize = 12 // NIST SP 800-38D recommends tags with 12 or more bytes. 38 gcmStandardNonceSize = 12 39 ) 40 41 var errOpen = errors.New("cipher: message authentication failed") 42 43 // aesCipherGCM implements crypto/cipher.gcmAble so that crypto/cipher.NewGCM 44 // will use the optimised implementation in this file when possible. Instances 45 // of this type only exist when hasGCMAsm returns true. 46 type aesCipherGCM struct { 47 aesCipherAsm 48 } 49 50 // Assert that aesCipherGCM implements the gcmAble interface. 51 var _ gcmAble = (*aesCipherGCM)(nil) 52 53 // NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only 54 // called by crypto/cipher.NewGCM via the gcmAble interface. 55 func (c *aesCipherGCM) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { 56 g := &gcmAsm{ks: c.enc, nonceSize: nonceSize, tagSize: tagSize} 57 gcmAesInit(&g.productTable, g.ks) 58 return g, nil 59 } 60 61 type gcmAsm struct { 62 // ks is the key schedule, the length of which depends on the size of 63 // the AES key. 64 ks []uint32 65 // productTable contains pre-computed multiples of the binary-field 66 // element used in GHASH. 67 productTable [256]byte 68 // nonceSize contains the expected size of the nonce, in bytes. 69 nonceSize int 70 // tagSize contains the size of the tag, in bytes. 71 tagSize int 72 } 73 74 func (g *gcmAsm) NonceSize() int { 75 return g.nonceSize 76 } 77 78 func (g *gcmAsm) Overhead() int { 79 return g.tagSize 80 } 81 82 // sliceForAppend takes a slice and a requested number of bytes. It returns a 83 // slice with the contents of the given slice followed by that many bytes and a 84 // second slice that aliases into it and contains only the extra bytes. If the 85 // original slice has sufficient capacity then no allocation is performed. 86 func sliceForAppend(in []byte, n int) (head, tail []byte) { 87 if total := len(in) + n; cap(in) >= total { 88 head = in[:total] 89 } else { 90 head = make([]byte, total) 91 copy(head, in) 92 } 93 tail = head[len(in):] 94 return 95 } 96 97 // Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for 98 // details. 99 func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { 100 if len(nonce) != g.nonceSize { 101 panic("crypto/cipher: incorrect nonce length given to GCM") 102 } 103 if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize { 104 panic("crypto/cipher: message too large for GCM") 105 } 106 107 var counter, tagMask [gcmBlockSize]byte 108 109 if len(nonce) == gcmStandardNonceSize { 110 // Init counter to nonce||1 111 copy(counter[:], nonce) 112 counter[gcmBlockSize-1] = 1 113 } else { 114 // Otherwise counter = GHASH(nonce) 115 gcmAesData(&g.productTable, nonce, &counter) 116 gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) 117 } 118 119 encryptBlockAsm(len(g.ks)/4-1, &g.ks[0], &tagMask[0], &counter[0]) 120 121 var tagOut [gcmTagSize]byte 122 gcmAesData(&g.productTable, data, &tagOut) 123 124 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) 125 if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) { 126 panic("crypto/cipher: invalid buffer overlap") 127 } 128 if len(plaintext) > 0 { 129 gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks) 130 } 131 gcmAesFinish(&g.productTable, &tagMask, &tagOut, uint64(len(plaintext)), uint64(len(data))) 132 copy(out[len(plaintext):], tagOut[:]) 133 134 return ret 135 } 136 137 // Open authenticates and decrypts ciphertext. See the cipher.AEAD interface 138 // for details. 139 func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { 140 if len(nonce) != g.nonceSize { 141 panic("crypto/cipher: incorrect nonce length given to GCM") 142 } 143 // Sanity check to prevent the authentication from always succeeding if an implementation 144 // leaves tagSize uninitialized, for example. 145 if g.tagSize < gcmMinimumTagSize { 146 panic("crypto/cipher: incorrect GCM tag size") 147 } 148 149 if len(ciphertext) < g.tagSize { 150 return nil, errOpen 151 } 152 if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) { 153 return nil, errOpen 154 } 155 156 tag := ciphertext[len(ciphertext)-g.tagSize:] 157 ciphertext = ciphertext[:len(ciphertext)-g.tagSize] 158 159 // See GCM spec, section 7.1. 160 var counter, tagMask [gcmBlockSize]byte 161 162 if len(nonce) == gcmStandardNonceSize { 163 // Init counter to nonce||1 164 copy(counter[:], nonce) 165 counter[gcmBlockSize-1] = 1 166 } else { 167 // Otherwise counter = GHASH(nonce) 168 gcmAesData(&g.productTable, nonce, &counter) 169 gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) 170 } 171 172 encryptBlockAsm(len(g.ks)/4-1, &g.ks[0], &tagMask[0], &counter[0]) 173 174 var expectedTag [gcmTagSize]byte 175 gcmAesData(&g.productTable, data, &expectedTag) 176 177 ret, out := sliceForAppend(dst, len(ciphertext)) 178 if subtleoverlap.InexactOverlap(out, ciphertext) { 179 panic("crypto/cipher: invalid buffer overlap") 180 } 181 if len(ciphertext) > 0 { 182 gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks) 183 } 184 gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data))) 185 186 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { 187 for i := range out { 188 out[i] = 0 189 } 190 return nil, errOpen 191 } 192 193 return ret, nil 194 }