Subject: [tcpm] More on KDFs and PRFs

From: Eric Rescorla <[email-masked]>
Date: Sun, 26 Jul 2009 18:02:05 -0700

Greg and I spent a while discussing the construction of the
KDF in draft-lebovitz-ietf-tcpm-ao-crypto-01, and I think 
there's some confusion about what the right interfaces are.

This document does two things:

- Defines the interface and requirements for all KDFs
- Provides two specific KDFs.

INTERFACE REQUIREMENTS
As far as the first job goes, the basic interface you want for a KDF is:

     KDF(Master_Key, Context, Output_Length)

Where Output_Length describes the size of the key you're deriving with
the KDF. A KDF of this sort can be used in a mix-and-match fashion
with any target cryptographic algorithm (i.e., can generate keys for
any algorithm) because it can generate an arbitrary length key.  For
instance, you could use an HMAC-SHA based KDF to generate keys for AES
or RC4. In fact, this is precisely what both TLS and IPsec do because
they need to generate keys for both a MAC algorithm and an encryption
algorithm. 

So, KDFs for TCP-AO need to meet the above interface, with:

- Master_Key      == the key from the MKT
- Context         == the data block
- Output_length   == the right size key for the target integrity
  		     algorithm.

Aside from the security requirements for a KDF, this is all you need
to say in terms of requirements on future KDFs.

SPECIFIC KDFS
With that in mind, we now need to define concrete KDFs that meet the
above interface spec. For concreteness, let's focus on the
HMAC-SHA-1-based KDF.

This KDF needs to match the above interface but we're otherwise
unconstrained. However, there seems to be a desire to have a
KDF that matches the (IMHO over-engineered) SP800-108 definitions, and this
is quite possible within this framework. We simply need to arrange for
the correct input values for the PRF that is the core of the KDF.

The pseudocode for this looks like:

    hmac_sha1_kdf(MK, context, output_length) {
      needed = output_length
      i = 0
      result = ""
    
      while(needed) {
        blk = i + "TCP-AO" + context + output_length
     
        result += HMAC-SHA1(MK, blk)
        needed -= 160
      } 
      
      return result
    }

Note that if you generate a 160-bit key, this is computationally
compatible with what's defined in 3.1.1. We just hide the Input
construction under the covers of the KDF. This means we could do
a non SP800-108 KDF, such as the TLS PRF, simply by saying

TLS_PRF_KDF(MK, context, output_length) = TLS_PRF(MK, context)[0..output_length-1]

Is this clear to people? Are there objections to this overall strategy?
If not, I can provide text that implements it.

-Ekr