gcm.mx raw

   1  // Copyright 2013 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 gcm
   6  
   7  import (
   8  	"crypto/internal/fips140"
   9  	"crypto/internal/fips140/aes"
  10  	"crypto/internal/fips140/alias"
  11  	"errors"
  12  )
  13  
  14  // GCM represents a Galois Counter Mode with a specific key.
  15  type GCM struct {
  16  	cipher    aes.Block
  17  	nonceSize int
  18  	tagSize   int
  19  	gcmPlatformData
  20  }
  21  
  22  func New(cipher *aes.Block, nonceSize, tagSize int) (*GCM, error) {
  23  	// This function is outlined to let the allocation happen on the parent stack.
  24  	return newGCM(&GCM{}, cipher, nonceSize, tagSize)
  25  }
  26  
  27  // newGCM is marked go:noinline to avoid it inlining into New, and making New
  28  // too complex to inline itself.
  29  //
  30  //go:noinline
  31  func newGCM(g *GCM, cipher *aes.Block, nonceSize, tagSize int) (*GCM, error) {
  32  	if tagSize < gcmMinimumTagSize || tagSize > gcmBlockSize {
  33  		return nil, errors.New("cipher: incorrect tag size given to GCM")
  34  	}
  35  	if nonceSize <= 0 {
  36  		return nil, errors.New("cipher: the nonce can't have zero length")
  37  	}
  38  	if cipher.BlockSize() != gcmBlockSize {
  39  		return nil, errors.New("cipher: NewGCM requires 128-bit block cipher")
  40  	}
  41  	g.cipher = *cipher
  42  	g.nonceSize = nonceSize
  43  	g.tagSize = tagSize
  44  	initGCM(g)
  45  	return g, nil
  46  }
  47  
  48  const (
  49  	gcmBlockSize         = 16
  50  	gcmTagSize           = 16
  51  	gcmMinimumTagSize    = 12 // NIST SP 800-38D recommends tags with 12 or more bytes.
  52  	gcmStandardNonceSize = 12
  53  )
  54  
  55  func (g *GCM) NonceSize() int {
  56  	return g.nonceSize
  57  }
  58  
  59  func (g *GCM) Overhead() int {
  60  	return g.tagSize
  61  }
  62  
  63  func (g *GCM) Seal(dst, nonce, plaintext, data []byte) []byte {
  64  	fips140.RecordNonApproved()
  65  	return g.sealAfterIndicator(dst, nonce, plaintext, data)
  66  }
  67  
  68  func (g *GCM) sealAfterIndicator(dst, nonce, plaintext, data []byte) []byte {
  69  	if len(nonce) != g.nonceSize {
  70  		panic("crypto/cipher: incorrect nonce length given to GCM")
  71  	}
  72  	if g.nonceSize == 0 {
  73  		panic("crypto/cipher: incorrect GCM nonce size")
  74  	}
  75  	if uint64(len(plaintext)) > uint64((1<<32)-2)*gcmBlockSize {
  76  		panic("crypto/cipher: message too large for GCM")
  77  	}
  78  
  79  	ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
  80  	if alias.InexactOverlap(out, plaintext) {
  81  		panic("crypto/cipher: invalid buffer overlap of output and input")
  82  	}
  83  	if alias.AnyOverlap(out, data) {
  84  		panic("crypto/cipher: invalid buffer overlap of output and additional data")
  85  	}
  86  
  87  	seal(out, g, nonce, plaintext, data)
  88  	return ret
  89  }
  90  
  91  var errOpen = errors.New("cipher: message authentication failed")
  92  
  93  func (g *GCM) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
  94  	if len(nonce) != g.nonceSize {
  95  		panic("crypto/cipher: incorrect nonce length given to GCM")
  96  	}
  97  	// Sanity check to prevent the authentication from always succeeding if an
  98  	// implementation leaves tagSize uninitialized, for example.
  99  	if g.tagSize < gcmMinimumTagSize {
 100  		panic("crypto/cipher: incorrect GCM tag size")
 101  	}
 102  
 103  	if len(ciphertext) < g.tagSize {
 104  		return nil, errOpen
 105  	}
 106  	if uint64(len(ciphertext)) > uint64((1<<32)-2)*gcmBlockSize+uint64(g.tagSize) {
 107  		return nil, errOpen
 108  	}
 109  
 110  	ret, out := sliceForAppend(dst, len(ciphertext)-g.tagSize)
 111  	if alias.InexactOverlap(out, ciphertext) {
 112  		panic("crypto/cipher: invalid buffer overlap of output and input")
 113  	}
 114  	if alias.AnyOverlap(out, data) {
 115  		panic("crypto/cipher: invalid buffer overlap of output and additional data")
 116  	}
 117  
 118  	fips140.RecordApproved()
 119  	if err := open(out, g, nonce, ciphertext, data); err != nil {
 120  		// We sometimes decrypt and authenticate concurrently, so we overwrite
 121  		// dst in the event of a tag mismatch. To be consistent across platforms
 122  		// and to avoid releasing unauthenticated plaintext, we clear the buffer
 123  		// in the event of an error.
 124  		clear(out)
 125  		return nil, err
 126  	}
 127  	return ret, nil
 128  }
 129  
 130  // sliceForAppend takes a slice and a requested number of bytes. It returns a
 131  // slice with the contents of the given slice followed by that many bytes and a
 132  // second slice that aliases into it and contains only the extra bytes. If the
 133  // original slice has sufficient capacity then no allocation is performed.
 134  func sliceForAppend(in []byte, n int) (head, tail []byte) {
 135  	if total := len(in) + n; cap(in) >= total {
 136  		head = in[:total]
 137  	} else {
 138  		head = []byte{:total}
 139  		copy(head, in)
 140  	}
 141  	tail = head[len(in):]
 142  	return
 143  }
 144