Source file src/crypto/internal/fips140/aes/gcm/ctrkdf.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  )
    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  

View as plain text