KDF API review, round 2

Xuelei Fan xuelei.fan at oracle.com
Thu Nov 30 16:42:21 UTC 2017


My apologies to break in the middle of the thread.  The following 
attacking scenarios is a good concern to me for the API design.

On 11/20/2017 8:17 AM, Michael StJohns wrote:
> Example:  a given TLS session may need 2 256 bit AES keys and 2 128 bit 
> IVs.  That is a requirement for 96 bytes of key stream (if I've got my 
> calculation correct).  We have the HSM produce this (see the PKCS11 
> calling sequence for example) and we get out the IVs.  An attacker who 
> has access to the HSM (which may or may not be on the same machine as 
> the TLS instantiation) can call the derivation function with new output 
> parameters (but with the same master key and mixins)  which specifies 
> only IV material and have the function output the same key stream bytes 
> that were previously assigned to the secret key material in the IV 
> output.  A very easy key extraction attack.
I would like to avoid this problem if possible.  But let me start from 
what we can do for the API design.

Per my understanding, the input parameters of a KDF function may include:
I-1. KDF algorithm
I-2. KDF parameters
I-3. derived key algorithm
I-4. derived key parameters

For a service provider framework, we use a service provided by the 
underlying provider as:
P-1. search for the service  (get the KDF function Java object)
P-2. configure the service   (configure the KDF function)
P-3. use the service         (derive the key)

Among P-1 to P-3, where is the appropriate place to have the input 
parameters of a KDF function?

In the current JDK framework, one cannot search for a service for the 
specific parameters except the service name.  We may be able to twist a 
little bit, but I don't think there is too much we can do actually if we 
don't want to touch the provider framework too much.  So, the first set 
of APIs comes out to me:

     KeyDerivation KeyDerivation.getInstance(
             String kdfAlgorithm,        // I-1
             Provider kdfProvider)

and its variants.


For P-2, configure the service, we can name the API as init(), 
serParameters() or configure(), or others.  If we configure all of the 
following input parameters here:
I-2. KDF parameters
I-3. derived key algorithm
I-4. derived key parameters

the APIs may looks like:
     void configure(KDF-Params, Key-Algorithm, Key-Params)   // P-2
     Key deriveKey();                                        // P-3

 From an application developer view of point, I'm uncomfortable to put a 
very hard limit of the P-3 possibilities in P-2 stage.  No parameters 
for the deriveKey() method make me nervous because I don't actually know 
what the key is actually is for the developers and code reviewers.

I would like to keep it simple that, in configuration period, configure 
the KDF function only, but not configure the derived key in general. 
OK, the 2nd set of APIs comes out to me (you can use init/setPara as the 
method name).

      void configure(KDF-Params)    // I-2.

and its variants if needed.

If you agree with the above two stages, there is not much flexible for 
the 3rd stage (P-3).  The 3rd set of APIs may looks like:

      Key deriveKey(Key-Algorithm, Key-Params)	// I-3, I-4

and it variants if needed.


Back to the Michael's attacking scenarios above.  It's a really good 
argue.  The point does not only apply to hardware implementation, it 
applies to software implementation too.  IVs can be public, while secret 
key need to be secret.  If there is a mixin,  the weakness may be able 
to used by delicately designed attacking scenarios.

I would like to use the existing methods above, but customize the 
KDF-Params instead.  In the KDF-Params spec, we can specify the 
insensitive sections of the keying materials so that they can be used 
for IV and other purpose other than keys, if needed.  The derived key is 
extractable only when the key materials is from the insensitive sections.


Xuelei



More information about the security-dev mailing list