| // Copyright 2024 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package gcm |
| |
| import ( |
| "crypto/internal/fips140" |
| "crypto/internal/fips140/aes" |
| "crypto/internal/fips140/subtle" |
| ) |
| |
| // CMAC implements the CMAC mode from NIST SP 800-38B. |
| // |
| // It is optimized for use in Counter KDF (SP 800-108r1) and XAES-256-GCM |
| // (https://c2sp.org/XAES-256-GCM), rather than for exposing it to applications |
| // as a stand-alone MAC. |
| type CMAC struct { |
| b aes.Block |
| k1 [aes.BlockSize]byte |
| k2 [aes.BlockSize]byte |
| } |
| |
| func NewCMAC(b *aes.Block) *CMAC { |
| c := &CMAC{b: *b} |
| c.deriveSubkeys() |
| return c |
| } |
| |
| func (c *CMAC) deriveSubkeys() { |
| aes.EncryptBlockInternal(&c.b, c.k1[:], c.k1[:]) |
| msb := shiftLeft(&c.k1) |
| c.k1[len(c.k1)-1] ^= msb * 0b10000111 |
| |
| c.k2 = c.k1 |
| msb = shiftLeft(&c.k2) |
| c.k2[len(c.k2)-1] ^= msb * 0b10000111 |
| } |
| |
| func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte { |
| fips140.RecordApproved() |
| _ = c.b // Hoist the nil check out of the loop. |
| var x [aes.BlockSize]byte |
| if len(m) == 0 { |
| // Special-cased as a single empty partial final block. |
| x = c.k2 |
| x[len(m)] ^= 0b10000000 |
| aes.EncryptBlockInternal(&c.b, x[:], x[:]) |
| return x |
| } |
| for len(m) >= aes.BlockSize { |
| subtle.XORBytes(x[:], m[:aes.BlockSize], x[:]) |
| if len(m) == aes.BlockSize { |
| // Final complete block. |
| subtle.XORBytes(x[:], c.k1[:], x[:]) |
| } |
| aes.EncryptBlockInternal(&c.b, x[:], x[:]) |
| m = m[aes.BlockSize:] |
| } |
| if len(m) > 0 { |
| // Final incomplete block. |
| subtle.XORBytes(x[:], m, x[:]) |
| subtle.XORBytes(x[:], c.k2[:], x[:]) |
| x[len(m)] ^= 0b10000000 |
| aes.EncryptBlockInternal(&c.b, x[:], x[:]) |
| } |
| return x |
| } |
| |
| // shiftLeft sets x to x << 1, and returns MSB₁(x). |
| func shiftLeft(x *[aes.BlockSize]byte) byte { |
| var msb byte |
| for i := len(x) - 1; i >= 0; i-- { |
| msb, x[i] = x[i]>>7, x[i]<<1|msb |
| } |
| return msb |
| } |