Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is HKDF implemented in Java Cryptography Architecture?

Tags:

java

hmac

hkdf

In the application I'm writing I need to do HKDF to derive two different keys from one password. Searching for examples on how to it in Java I found these two:

  • https://github.com/WhisperSystems/libsignal-protocol-java/blob/master/java/src/main/java/org/whispersystems/libsignal/kdf/HKDF.java
  • https://www.javatips.net/api/keywhiz-master/hkdf/src/main/java/keywhiz/hkdf/Hkdf.java

In both cases HKDF is implemented on top of the HMAC provided by JCA. I haven't read those implementations in detail yet but I was wondering, is this not implemented anywhere in JCA or itself? Do I have to implement my own HKDF?

The part that worries me the most, is making a mistake in applying the info argument. It looks non-trivial and critical.

like image 830
pupeno Avatar asked Aug 31 '17 15:08

pupeno


1 Answers

HKDF Implementations in Java

No, Hashed Message Authentication Code (HMAC)-based key derivation function (HKDF) has, like most KDFs, no standard implementation in JCA (as of 2020).

There are some implementations embedded in other projects (like you already said):

  • mozilla-services/sync-crypto
  • WhisperSystems/libsignal-protocol-java
  • square/keywhiz

Also there is, of course, Bouncy Castle which use their own Hmac/Mac implementations and APIs. BC is however a massive dependency, and may be unpractical for e.g. embedded or mobile use case. For this I implemented a standalone, lightweight java lib (passing all of the RFC 5869 test vectors), which works with any javax.crypto.Mac instance:

  • https://github.com/patrickfav/hkdf

If you prefer, you could, of course implement it on your own, it's a fairly straight forward spec, when using the built-in JCA Hmac implementation.

Info Parameter in HKDF

From the RFC 5869:

While the 'info' value is optional in the definition of HKDF, it is
often of great importance in applications. Its main objective is to
bind the derived key material to application- and context-specific
information. (...) In particular, it may prevent the derivation of the same keying material for different contexts.

So for example if you want to derive an Secret Key and IV from the same source material you would use the info parameter (using this lib):

//example input
String userInput = "this is a user input with bad entropy";

HKDF hkdf = HKDF.fromHmacSha256();

//extract the "raw" data to create output with concentrated entropy
byte[] pseudoRandomKey = hkdf.extract(staticSalt32Byte, userInput.getBytes(StandardCharsets.UTF_8));

//create expanded bytes for e.g. AES secret key and IV
byte[] expandedAesKey = hkdf.expand(pseudoRandomKey, "aes-key".getBytes(StandardCharsets.UTF_8), 16);
byte[] expandedIv = hkdf.expand(pseudoRandomKey, "aes-iv".getBytes(StandardCharsets.UTF_8), 16);

//Example boilerplate encrypting a simple string with created key/iv
SecretKey key = new SecretKeySpec(expandedAesKey, "AES"); //AES-128 key
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(expandedIv));
byte[] encrypted = cipher.doFinal("my secret message".getBytes(StandardCharsets.UTF_8));
like image 75
Patrick Favre Avatar answered Oct 30 '22 18:10

Patrick Favre