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.
See above - the key stream is logically produced in its entirety
before any assignment of that stream is made to any cryptographic
objects because the mixins (except for the round differentiator) are
the same for each key stream production round. Simply passing in the
total length may not give you the right result if the KDF requires a
per component length (and it should to defeat (5) or it should only
produce a single key).
From looking at 800-108, I don't see any place where the KDF needs a
per-component length. It looks like it takes L (total length) as an
input and that is applied to each round of the PRF. HKDF takes L
up-front as an input too, though it doesn't use it as an input to the
HMAC function itself. For TLS 1.3 that component length becomes part of
the context info (HkdfLabel) through the HKDF-Expand-Label
function...and it's only doing one key for a given label which is also
part of that context specific info, necessitating an init() call. Seems
like the length can go into the APS provided via init (for those KDFs
that need it at least) and you shouldn't need a DPS list up-front.
As far as your (5) scenario goes, I can see how you can twiddle the
lengths to get the keystream output with zero-length keys and large IV
buffers. But that scenario really glosses over what should be a big
hurdle and a major access control issue that stands outside the KDF API:
That the attacker shouldn't have access to the input keying material in
the first place. Protect the input keying material properly and their
attack cannot be done.
I would rather see the DPS provided in the deriveKey. It couples what
you want out with the call that makes the object and it makes a lot more
sense to keep those two together than try to remember where in the
submitted list of DPS objects you are.
95% of the time this will be a call to produce a single key. 4% of
the time it will be a call to produce multiple keys. Only 1% of the
time will it need to intermix key, data and object productions.
Anybody who is doing that is going to write a wrapper around this
class to make sure they get the key and data production order correct
for each call. So I'm not all that bothered by keeping the complexity
as a price for keeping flexibility.
You could have a Key deriveKey(Key k, DerivationParameterSpec param)
for some things like TLS1.3 (where you can only make a single call to
derive key between inits) , but then you'd also need at least a byte[]
deriveData (Key k, DerivationParameterSpec param) and an Object
deriveObject(Key k, DerivationParameterSpec param).
I don't think those are necessary. If you're just doing HKDF-Expand
(for the HKDF-Expand-Label TLS 1.3 key derivation) then you can provide
the input key, label and max length and any other context info that goes
into that HkdfLabel structure...all of that would go into init(). Then
provide the key alg and desired length via the DPS at deriveKey time.
Any subsequent keys in the TLS 1.3 key schedule would need a new init
call anyway since the labels change and possibly the output length.
Over the next day or so I'm going to have to make some final decisions
on this API as there are internal projects that are waiting on this API
to proceed. I'm already past the cut-off date I set, but I recognize
these discussions are important to have and I appreciate the input you
and others have provided.
--Jamil
- Re: KDF API review, round 2 Michael StJohns
- Re: KDF API review, round 2 Adam Petcher
- Re: KDF API review, round 2 Michael StJohns
- Re: KDF API review, round 2 Jamil Nimeh
- Re: KDF API review, round 2 Adam Petcher
- Re: KDF API review, round 2 Michael StJohns
- Re: KDF API review, round 2 Adam Petcher
- Re: KDF API review, round 2 Jamil Nimeh
- Re: KDF API review, round 2 Michael StJohns
- Re: KDF API review, round 2 Jamil Nimeh
- Re: KDF API review, round 2 Jamil Nimeh
- Re: KDF API review, round 2 Michael StJohns
- Re: KDF API review, round 2 Jamil Nimeh
- Re: KDF API review, round 2 Anthony Scarpino
- Re: KDF API review, round 2 Michael StJohns
- Re: KDF API review, round 2 Jamil Nimeh
- Re: KDF API review, round 2 Weijun Wang
- Re: KDF API review, round 2 Jamil Nimeh
- Re: KDF API review, round 2 Michael StJohns
- Re: KDF API review, round 2 Jamil Nimeh
- Re: KDF API review, round 2 Michael StJohns