KDF API review, round 2
Jamil Nimeh
jamil.j.nimeh at oracle.com
Mon Nov 20 10:12:26 UTC 2017
On 11/19/2017 12:45 PM, Michael StJohns wrote:
> On 11/17/2017 1:07 PM, Adam Petcher wrote:
>> On 11/17/2017 10:04 AM, Michael StJohns wrote:
>>
>>> On 11/16/2017 2:15 PM, Adam Petcher wrote:
>>>> So it seems like they could all be supplied to init. Alternatively,
>>>> algorithm names could specify more concrete algorithms that include
>>>> the mode/PRF/etc. Can you provide more information to explain why
>>>> these existing patterns won't work in this case?
>>> What I need to do is provide a lifecycle diagram, but its hard to do
>>> in text. But basically, the .getInstance() followed by
>>> .setParameters() builds a concrete engine while the .init()
>>> initializes that engine with a key and the derivation parameters.
>>> Think about a TLS 1.2 instance - the PRF is selected once, but the
>>> KDF may be used multiple times.
>>
>> This is the information I was missing. There are two sets of
>> parameters, and the first set should be fixed, but the second set
>> should be changed on each init.
>>
>>>
>>> I considered the mode/PRF/etc stuff but that works for things like
>>> Cipher and Signature because most of those have exactly the same
>>> pattern. For the KDF pattern we;ve got fully specified KDFs (e.g.
>>> TLS 1.1 and before, IPSEC), almost fully specified KDFs (TLS 1.2 and
>>> HDKF needs a PRF) and then the SP800 style KDFs which are defined to
>>> be *very* flexible. So translating that into a naming convention is
>>> going to be restrictive and may not cover all of the possible
>>> approaches. I'd rather do it as an algorithmparameter instead. With
>>> a given KDF implementation having a default if nothing is specified
>>> during instantiation.
>>
>> I agree that this is challenging because there is so much variety in
>> KDFs. But I don't think that SP 800-108 is a good example of
>> something that should be exposed as an algorithm in JCA, because it
>> is too broad. SP 800-108 is more of a toolbox that can be used to
>> construct KDFs. Particular specializations of SP 800-108 are widely
>> used, and they will get names that can be used in getInstance. For
>> example, HKDF-Expand is a particular specialization of SP 800-108.
>
>>
>> So I think the existing pattern of using algorithm names to specify
>> concrete algorithms should work just as well in this API as it does
>> in the rest of JCA. Of course, more flexibility in the API is a nice
>> feature, but supporting this level of generality may be out of scope
>> for this effort.
>
>
> The more I think about it the more I think you're mostly right. But
> let's split this slightly as almost every KDF allows for the
> specification of the PRF. So
>
> <kdfname>/<prf> as the standard naming convention.
>
> Or TLS13/HMAC-SHA256 and HKDF/HMAC-SHA256 (which are different because
> of the mandatory inclusion of "L" in the derivation parameters and
> each component object for TLS13)
>
> Still - let's include the .setParameters() call as a failsafe as
> looking forward I can see the need for flexibility rearing its ugly
> head (e.g. adding PSS parameters to RSA signatures way late in the
> game.....) and it does match the pattern for Signature so its not a
> new concept. A given provider need not support the call, but its there
> if needed.
Signature appears to have setParameter because the initSign and
initVerify didn't have APS parameters in their method signatures. Since
we're talking about providing APS objects through both getInstance() for
those locked to the algorithm and init() for things like salts, info,
etc. that can be changed on successive inits it seems like we're covered
without the need for a setParameter method.
One additional topic for discussion: Late in the week we talked about
the current state of the API internally and one item to revisit is where
the DerivationParameterSpec objects are passed. It was brought up by a
couple people that it would be better to provide the DPS objects
pertaining to keys at the time they are called for through deriveKey()
and deriveKeys() (and possibly deriveData).
Originally we had them all grouped in a List in the init method. One
reason for needing it up there was to know the total length of material
to generate. If we can provide the total length through the
AlgorithmParameterSpec passed in via init() then things like:
Key deriveKey(DerivationParameterSpec param);
List<Key> deriveKeys(List<DerivationParameterSpec> params);
become possible. To my eyes at least it does make it more clear what
DPS you're processing since they're provided at derive time, rather than
the caller having to keep track in their heads where in the DPS list
they might be with each successive deriveKey or deriveKeys calls. And I
think we could do away with deriveKeys(int), too.
--Jamil
More information about the security-dev
mailing list