On 11/16/2017 2:15 PM, Adam Petcher wrote:
On 11/16/2017 12:47 AM, Michael StJohns wrote:
This is pretty close, but I think you need to add an
AlgorithmParameters argument to each of the getInstance calls in
KeyDerivation - or require each KDF to specify a default model - not
all KDFs are fully specified in a given document.
Alternately, you could use the .setParameter/.getParameter model of
signature, but it may be that underlying code will actually be
creating a whole new instance. (E.g. getInstance("NIST-SP800-108")
vs getInstance("NIST-SP800-108-Counter") vs
getInstance("NIST-SP800-108/Counter"))
Here's the model I'm thinking about:
SP800-108 is a parameterized set of Key derivation functions
which goes something like:
Pick either Counter or Feedback
Pick the PRF (e.g. HMAC-SHA256, AES-128-CMAC, etc)
Pick the size of the counter and endianness: (e.g. Big
endian Uint16)
Pick the size and endianness of L
Pick whether the counter precedes or follows the fixed data
(for counter mode).
Pick whether the counter is included and whether it precedes
or follows the fixed data (for feedback mode)
Taken together those instantiation parameters define a particular KDF
model.
Then for the .init() call, the kdfParams is where the Label and
Context data go (what HKDF calls 'info'). For most KDFs this could
just be a byte array.
For HKDF the getInstance must specify an underlying hash function -
by definition mode is feedback, the size of the counter is fixed, L
is not included in the base calculation. (TLS1.3 uses HKDF and makes
L a mandatory part of the HKDF).
I don't like the idea of putting algorithm parameters in getInstance,
because we don't have this pattern in JCA, and it doesn't seem like it
is necessary here.
Which is why I mentioned the Signature.setParameter() pattern as an
alternative.
In your example above, the first set of parameters are somehow
different from the second set, but it is not clear how.
The first set configures HOW the kdf operations, the second (.init())
gives the parameters needed for a specific set of invocations.
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.
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.
Mike