Source file src/crypto/internal/fips140/aes/gcm/cmac.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"
     9  	"crypto/internal/fips140/aes"
    10  	"crypto/internal/fips140/subtle"
    11  )
    12  
    13  // CMAC implements the CMAC mode from NIST SP 800-38B.
    14  //
    15  // It is optimized for use in Counter KDF (SP 800-108r1) and XAES-256-GCM
    16  // (https://c2sp.org/XAES-256-GCM), rather than for exposing it to applications
    17  // as a stand-alone MAC.
    18  type CMAC struct {
    19  	b  aes.Block
    20  	k1 [aes.BlockSize]byte
    21  	k2 [aes.BlockSize]byte
    22  }
    23  
    24  func NewCMAC(b *aes.Block) *CMAC {
    25  	c := &CMAC{b: *b}
    26  	c.deriveSubkeys()
    27  	return c
    28  }
    29  
    30  func (c *CMAC) deriveSubkeys() {
    31  	aes.EncryptBlockInternal(&c.b, c.k1[:], c.k1[:])
    32  	msb := shiftLeft(&c.k1)
    33  	c.k1[len(c.k1)-1] ^= msb * 0b10000111
    34  
    35  	c.k2 = c.k1
    36  	msb = shiftLeft(&c.k2)
    37  	c.k2[len(c.k2)-1] ^= msb * 0b10000111
    38  }
    39  
    40  func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
    41  	fips140.RecordApproved()
    42  	_ = c.b // Hoist the nil check out of the loop.
    43  	var x [aes.BlockSize]byte
    44  	if len(m) == 0 {
    45  		// Special-cased as a single empty partial final block.
    46  		x = c.k2
    47  		x[len(m)] ^= 0b10000000
    48  		aes.EncryptBlockInternal(&c.b, x[:], x[:])
    49  		return x
    50  	}
    51  	for len(m) >= aes.BlockSize {
    52  		subtle.XORBytes(x[:], m[:aes.BlockSize], x[:])
    53  		if len(m) == aes.BlockSize {
    54  			// Final complete block.
    55  			subtle.XORBytes(x[:], c.k1[:], x[:])
    56  		}
    57  		aes.EncryptBlockInternal(&c.b, x[:], x[:])
    58  		m = m[aes.BlockSize:]
    59  	}
    60  	if len(m) > 0 {
    61  		// Final incomplete block.
    62  		subtle.XORBytes(x[:], m, x[:])
    63  		subtle.XORBytes(x[:], c.k2[:], x[:])
    64  		x[len(m)] ^= 0b10000000
    65  		aes.EncryptBlockInternal(&c.b, x[:], x[:])
    66  	}
    67  	return x
    68  }
    69  
    70  // shiftLeft sets x to x << 1, and returns MSB₁(x).
    71  func shiftLeft(x *[aes.BlockSize]byte) byte {
    72  	var msb byte
    73  	for i := len(x) - 1; i >= 0; i-- {
    74  		msb, x[i] = x[i]>>7, x[i]<<1|msb
    75  	}
    76  	return msb
    77  }
    78  

View as plain text