Source file src/crypto/internal/fips140/aes/gcm/gcm.go

     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 = make([]byte, total)
   139  		copy(head, in)
   140  	}
   141  	tail = head[len(in):]
   142  	return
   143  }
   144  

View as plain text