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