"Fossies" - the Fresh Open Source Software Archive

Member "go/src/crypto/aes/aes_gcm.go" (9 Sep 2020, 5860 Bytes) of package /windows/misc/go1.14.9.windows-386.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

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