ctrkdf.mx raw

   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  )
  11  
  12  // CounterKDF implements a KDF in Counter Mode instantiated with CMAC-AES,
  13  // according to NIST SP 800-108 Revision 1 Update 1, Section 4.1.
  14  //
  15  // It produces a 256-bit output, and accepts a 8-bit Label and a 96-bit Context.
  16  // It uses a counter of 16 bits placed before the fixed data. The fixed data is
  17  // the sequence Label || 0x00 || Context. The L field is omitted, since the
  18  // output key length is fixed.
  19  //
  20  // It's optimized for use in XAES-256-GCM (https://c2sp.org/XAES-256-GCM),
  21  // rather than for exposing it to applications as a stand-alone KDF.
  22  type CounterKDF struct {
  23  	mac CMAC
  24  }
  25  
  26  // NewCounterKDF creates a new CounterKDF with the given key.
  27  func NewCounterKDF(b *aes.Block) *CounterKDF {
  28  	return &CounterKDF{mac: *NewCMAC(b)}
  29  }
  30  
  31  // DeriveKey derives a key from the given label and context.
  32  func (kdf *CounterKDF) DeriveKey(label byte, context [12]byte) [32]byte {
  33  	fips140.RecordApproved()
  34  	var output [32]byte
  35  
  36  	var input [aes.BlockSize]byte
  37  	input[2] = label
  38  	copy(input[4:], context[:])
  39  
  40  	input[1] = 0x01 // i = 1
  41  	K1 := kdf.mac.MAC(input[:])
  42  
  43  	input[1] = 0x02 // i = 2
  44  	K2 := kdf.mac.MAC(input[:])
  45  
  46  	copy(output[:], K1[:])
  47  	copy(output[aes.BlockSize:], K2[:])
  48  	return output
  49  }
  50