JEP draft: Key Derivation API

OwnerJamil Nimeh
Created2017/10/23 16:56
Updated2017/11/03 23:02
TypeFeature
StatusDraft
Componentsecurity-libs / javax.crypto
ScopeJDK
EffortM
DurationM
Priority3
Issue8189808

Summary

Create new APIs for deriving cryptographic keys.

Goals

Non-Goals

Success Metrics

Most measurable criteria for the KDF feature would reside in individual implementations of key derivation functions and are outside the scope of this JEP.

Motivation

Currently in the JCE we have APIs that cover key generation and key agreement as methods for obtaining secret keys, but we do not have an API for key derivation. What we have done today is take key derivation algorithms such as TLS-PRF or PBKDF2 and made them fit into a KeyGenerator. Long term however, it may make more sense to provide a KeyDerivation family of APIs and implementations which would provide interfaces better suited to these kinds of cryptographic operations.

This API will also let us publicly expose KDF algorithms that have been kept private up to now, such as TLS-PRF. It gives us a derivation framework to implement the key schedule for TLS 1.3, as well as the master-secret and key-and-mac calculations that are done in TLS 1.2 and earlier. The new TLS framework will be one of the first consumers of this API.

Description

The API itself will not modify any existing classes. It will follow a similar form to many of the other cryptographic APIs that are used in the JDK now (e.g. KeyAgreement, KeyGenerator). New classes would include a primary consumer-level class (javax.crypto.KeyDerivation), an underlying Service Provider Interface (javax.crypto.KeyDerivationSpi), and a key-specific derivation parameter class (java.security.spec.DerivedKeyParameterSpec). Other classes may be created as this API evolves. While outside the scope of the Key Derivation API, individual KDF implementations may also create new AlgorithmParameterSpec classes.

The KeyDerivation class would provide the instantiation methods (getInstance) which would also initialize a KDF. It will also provide methods for the derivation of key material (deriveKey, deriveKeys), along with methods to get the algorithm (getAlgorithm) and Provider (getProvider), similar to other cryptographic APIs in JDK. The KeyDerivationSpi will have methods for initialization (engineInit) and derivation (deriveKeys). Finally, the DerivedKeyParameterSpec will have common parameters that would be specified for keys (algorithm name/label, key length), along with accessor methods to return those values.

Use of KDF API

Use of the KDF API follows a similar pattern of calls like most JCE APIs. A KeyDerivation object is instantiated via one of the getInstance() calls, followed by an initialization where the input key and parameters (if needed by the KDF algorithm) is applied. From that point on, keys can be derived singly or in batch form. A sample single-key derivation using HKDF to output a single AES key would look like this:

byte[] salt;
byte[] info;
SecretKey inputKey;

// Populate salt and info arrays and obtain SecretKey object
// (external to this code snippet; not shown)
...
...
// Get a KeyDerivation object
try {
    AlgorithmParameterSpec hkdfSpec = new HkdfParameterSpec(inputKey, salt, info);
    KeyDerivation kdf = KeyDerivation.getInstance("HkdfSHA256", hkdfSpec);
    
    // Next specify type and length of the desired key and place into parameter spec
    DerivedKeyParameterSpec keySpec = new DerivedKeyParameterSpec("AES", 32);

    // Derive the key
    SecretKey derivedAesKey = kdf.deriveKey(keySpec);
} catch (GeneralSecurityException ge) {
    System.out.println("Ouch! Caught " + ge);
} catch (InvalidKeyException ke) {
    System.out.println("Invalid Key: " + ke);
}

Alternatives

One alternative to a new KDF API would be to continue to force KDF algorithms to fit into existing APIs such as KeyGenerator (as TLS-PRF does today) or SecretKeyFactory (PBKDF2).

Testing

Testing will need to be done both with the API itself (JCK testing) to make sure that positive and negative conditions are accurately reflected by the documented behavior. This will most likely require at least one actual implementation in the SunJCE provider (HKDF, TLS-PRF, etc.). Tests should include known-answer vectors to ensure correctness. These need not be exhaustive tests, since exhaustive known answer tests fall within the testing requirements of the KDF implementation. These KAT tests would be done to ensure that processing at the KeyDerivation and KeyDerivationSpi do not corrupt or alter the data, and that multi-key derivations preserve the order that they are requested in.

Risks and Assumptions

One inherent assumption/risk, as discussed above, is that fully testing the API will require at least one implementation. There are implementations that are in prototype states but are working in terms of generating correct output, so that mitigates the risk somewhat. Also this API will be subject to community review and may evolve during that review process.