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

     1  // Copyright 2024 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/aes"
     9  	"crypto/internal/fips140/subtle"
    10  	"crypto/internal/fips140deps/byteorder"
    11  )
    12  
    13  func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
    14  	var H, counter, tagMask [gcmBlockSize]byte
    15  	aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
    16  	deriveCounterGeneric(&H, &counter, nonce)
    17  	gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
    18  
    19  	gcmCounterCryptGeneric(&g.cipher, out, plaintext, &counter)
    20  
    21  	var tag [gcmTagSize]byte
    22  	gcmAuthGeneric(tag[:], &H, &tagMask, out[:len(plaintext)], additionalData)
    23  	copy(out[len(plaintext):], tag[:])
    24  }
    25  
    26  func openGeneric(out []byte, g *GCM, nonce, ciphertext, additionalData []byte) error {
    27  	var H, counter, tagMask [gcmBlockSize]byte
    28  	aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
    29  	deriveCounterGeneric(&H, &counter, nonce)
    30  	gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
    31  
    32  	tag := ciphertext[len(ciphertext)-g.tagSize:]
    33  	ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
    34  
    35  	var expectedTag [gcmTagSize]byte
    36  	gcmAuthGeneric(expectedTag[:], &H, &tagMask, ciphertext, additionalData)
    37  	if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
    38  		return errOpen
    39  	}
    40  
    41  	gcmCounterCryptGeneric(&g.cipher, out, ciphertext, &counter)
    42  
    43  	return nil
    44  }
    45  
    46  // deriveCounterGeneric computes the initial GCM counter state from the given nonce.
    47  // See NIST SP 800-38D, section 7.1. This assumes that counter is filled with
    48  // zeros on entry.
    49  func deriveCounterGeneric(H, counter *[gcmBlockSize]byte, nonce []byte) {
    50  	// GCM has two modes of operation with respect to the initial counter
    51  	// state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path"
    52  	// for nonces of other lengths. For a 96-bit nonce, the nonce, along
    53  	// with a four-byte big-endian counter starting at one, is used
    54  	// directly as the starting counter. For other nonce sizes, the counter
    55  	// is computed by passing it through the GHASH function.
    56  	if len(nonce) == gcmStandardNonceSize {
    57  		copy(counter[:], nonce)
    58  		counter[gcmBlockSize-1] = 1
    59  	} else {
    60  		lenBlock := make([]byte, 16)
    61  		byteorder.BEPutUint64(lenBlock[8:], uint64(len(nonce))*8)
    62  		ghash(counter, H, nonce, lenBlock)
    63  	}
    64  }
    65  
    66  // gcmCounterCryptGeneric encrypts src using AES in counter mode with 32-bit
    67  // wrapping (which is different from AES-CTR) and places the result into out.
    68  // counter is the initial value and will be updated with the next value.
    69  func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSize]byte) {
    70  	var mask [gcmBlockSize]byte
    71  
    72  	for len(src) >= gcmBlockSize {
    73  		aes.EncryptBlockInternal(b, mask[:], counter[:])
    74  		gcmInc32(counter)
    75  
    76  		subtle.XORBytes(out, src, mask[:])
    77  		out = out[gcmBlockSize:]
    78  		src = src[gcmBlockSize:]
    79  	}
    80  
    81  	if len(src) > 0 {
    82  		aes.EncryptBlockInternal(b, mask[:], counter[:])
    83  		gcmInc32(counter)
    84  		subtle.XORBytes(out, src, mask[:])
    85  	}
    86  }
    87  
    88  // gcmInc32 treats the final four bytes of counterBlock as a big-endian value
    89  // and increments it.
    90  func gcmInc32(counterBlock *[gcmBlockSize]byte) {
    91  	ctr := counterBlock[len(counterBlock)-4:]
    92  	byteorder.BEPutUint32(ctr, byteorder.BEUint32(ctr)+1)
    93  }
    94  
    95  // gcmAuthGeneric calculates GHASH(additionalData, ciphertext), masks the result
    96  // with tagMask and writes the result to out.
    97  func gcmAuthGeneric(out []byte, H, tagMask *[gcmBlockSize]byte, ciphertext, additionalData []byte) {
    98  	checkGenericIsExpected()
    99  	lenBlock := make([]byte, 16)
   100  	byteorder.BEPutUint64(lenBlock[:8], uint64(len(additionalData))*8)
   101  	byteorder.BEPutUint64(lenBlock[8:], uint64(len(ciphertext))*8)
   102  	var S [gcmBlockSize]byte
   103  	ghash(&S, H, additionalData, ciphertext, lenBlock)
   104  	subtle.XORBytes(out, S[:], tagMask[:])
   105  }
   106  

View as plain text