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

Reply via email to