Skip to content

Commit

Permalink
change api from extract(ikm,salt) to a more RFC compliant extract(sal…
Browse files Browse the repository at this point in the history
…t,ikm)
  • Loading branch information
patrickfav committed Oct 3, 2017
1 parent ce526ba commit cd31ee0
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 35 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
# Releases

## v0.4.0

* change api from `extract(ikm,salt)` to a more RFC compliant `extract(salt,ikm)` (also `extractAndExpand()`)

## v0.3.0

* refactor 'expand' byte handling to use byte buffer
* rename package to `at.favre.lib.crypto`


## v0.2.1

initial version
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>at.favre.lib</groupId>
<artifactId>hkdf</artifactId>
<version>0.3.0</version>
<version>0.4.0</version>
<packaging>jar</packaging>

<name>HKDF-RFC5869</name>
Expand Down
18 changes: 9 additions & 9 deletions src/main/java/at/favre/lib/crypto/HKDF.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* <p>
* Simple Example:
* <pre>
* byte[] pseudoRandomKey = HKDF.fromHmacSha256().extract(lowEntropyInput, null);
* byte[] pseudoRandomKey = HKDF.fromHmacSha256().extract(null, lowEntropyInput);
* byte[] outputKeyingMaterial = HKDF.fromHmacSha256().expand(pseudoRandomKey, null, 64);
* </pre>
*
Expand Down Expand Up @@ -95,14 +95,14 @@ public static HKDF from(HkdfMacFactory macFactory) {
* strengthening the analytical results that back the HKDF design.
* </blockquote>
*
* @param inputKeyingMaterial data to be extracted (IKM)
* @param salt optional salt value (a non-secret random value);
* @param inputKeyingMaterial data to be extracted (IKM)
* if not provided, it is set to a array of hash length of zeros.
* @return a new byte array pseudo random key (of hash length in bytes) (PRK) which can be used to expand
* @see <a href="https://tools.ietf.org/html/rfc5869#section-2.2">RFC 5869 Section 2.2</a>
*/
public byte[] extract(byte[] inputKeyingMaterial, byte[] salt) {
return new Extractor(macFactory).execute(inputKeyingMaterial, salt);
public byte[] extract(byte[] salt, byte[] inputKeyingMaterial) {
return new Extractor(macFactory).execute(salt, inputKeyingMaterial);
}

/**
Expand Down Expand Up @@ -138,14 +138,14 @@ public byte[] expand(byte[] pseudoRandomKey, byte[] info, int outLengthBytes) {
/**
* Convenience method for extract &amp; expand in a single method
*
* @param inputKeyingMaterial data to be extracted (IKM)
* @param saltExtract optional salt value (a non-secret random value);
* @param inputKeyingMaterial data to be extracted (IKM)
* @param infoExpand optional context and application specific information; may be null
* @param outLengthByte length of output keying material in bytes
* @return new byte array of output keying material (OKM)
*/
public byte[] extractAndExpand(byte[] inputKeyingMaterial, byte[] saltExtract, byte[] infoExpand, int outLengthByte) {
return new Expander(macFactory).execute(new Extractor(macFactory).execute(inputKeyingMaterial, saltExtract), infoExpand, outLengthByte);
public byte[] extractAndExpand(byte[] saltExtract, byte[] inputKeyingMaterial, byte[] infoExpand, int outLengthByte) {
return new Expander(macFactory).execute(new Extractor(macFactory).execute(saltExtract, inputKeyingMaterial), infoExpand, outLengthByte);
}

/**
Expand All @@ -169,12 +169,12 @@ static final class Extractor {
/**
* Step 1 of RFC 5869
*
* @param inputKeyingMaterial data to be extracted (IKM)
* @param salt optional salt value (a non-secret random value);
* @param inputKeyingMaterial data to be extracted (IKM)
* if not provided, it is set to a array of hash length of zeros.
* @return a new byte array pseudorandom key (of hash length in bytes) (PRK) which can be used to expand
*/
byte[] execute(byte[] inputKeyingMaterial, byte[] salt) {
byte[] execute(byte[] salt, byte[] inputKeyingMaterial) {
if (salt == null || salt.length == 0) {
salt = new byte[macFactory.createInstance(new byte[1]).getMacLength()];
}
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/at/favre/lib/crypto/HKDFBenchmarkTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void benchmark() throws Exception {
//benchmark different input sizes
for (int j = 1024; j < 1024 * 1024; j += 1024) {
input = RandomUtils.nextBytes(j);
byte[] pseudoRandomKey = HKDF.fromHmacSha256().extract(input, new byte[]{0x62, 0x58, (byte) 0x84, 0x2C});
byte[] pseudoRandomKey = HKDF.fromHmacSha256().extract(new byte[]{0x62, 0x58, (byte) 0x84, 0x2C}, input);
byte[] outputKeyingMaterial = HKDF.fromHmacSha256().expand(pseudoRandomKey, null, 32);
assertTrue(outputKeyingMaterial.length > 0);
count++;
Expand All @@ -43,7 +43,7 @@ public void benchmark() throws Exception {
//benchmark different input sizes
for (int j = 16; j < 255 * 64; j += 16) {
input = RandomUtils.nextBytes(128);
byte[] pseudoRandomKey = HKDF.fromHmacSha512().extract(input, new byte[]{0x62, 0x58, (byte) 0x84, 0x2C});
byte[] pseudoRandomKey = HKDF.fromHmacSha512().extract(new byte[]{0x62, 0x58, (byte) 0x84, 0x2C}, input);
byte[] outputKeyingMaterial = HKDF.fromHmacSha512().expand(pseudoRandomKey, null, j);
assertTrue(outputKeyingMaterial.length > 0);
count++;
Expand Down
40 changes: 20 additions & 20 deletions src/test/java/at/favre/lib/crypto/HKDFTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void setUp() throws Exception {
public void quickStarTest() throws Exception {
byte[] lowEntropyInput = new byte[]{0x62, 0x58, (byte) 0x84, 0x2C};

byte[] pseudoRandomKey = HKDF.fromHmacSha256().extract(lowEntropyInput, null);
byte[] pseudoRandomKey = HKDF.fromHmacSha256().extract(null, lowEntropyInput);
byte[] outputKeyingMaterial = HKDF.fromHmacSha256().expand(pseudoRandomKey, null, 64);

assertEquals(64, outputKeyingMaterial.length);
Expand All @@ -44,7 +44,7 @@ public void simpleUseCase() throws Exception {
HKDF hkdf = HKDF.fromHmacSha256();

//extract the "raw" data to create output with concentrated entropy
byte[] pseudoRandomKey = hkdf.extract(userInput.getBytes(StandardCharsets.UTF_8), staticSalt32Byte);
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);
Expand Down Expand Up @@ -73,7 +73,7 @@ public void customHmac() throws Exception {
HKDF hkdfMd5 = HKDF.from(new HkdfMacFactory.Default("HmacMD5", 16, Security.getProvider("SunJCE")));

byte[] lowEntropyInput = new byte[]{0x62, 0x58, (byte) 0x84, 0x2C};
byte[] outputKeyingMaterial = hkdfMd5.extractAndExpand(lowEntropyInput, null, null, 32);
byte[] outputKeyingMaterial = hkdfMd5.extractAndExpand(null, lowEntropyInput, null, 32);

assertEquals(32, outputKeyingMaterial.length);
}
Expand All @@ -87,16 +87,16 @@ public void checkLength() throws Exception {
for (int i : counts) {
ikm = RandomUtils.nextBytes(i);
salt = RandomUtils.nextBytes(i * 2);
checkLength(HKDF.fromHmacSha256().extract(ikm, salt), 32);
checkLength(HKDF.fromHmacSha256().extract(ikm, null), 32);
checkLength(HKDF.fromHmacSha256().extract(ikm, new byte[0]), 32);
checkLength(HKDF.fromHmacSha512().extract(ikm, salt), 64);
checkLength(HKDF.fromHmacSha512().extract(ikm, null), 64);
checkLength(HKDF.from(HkdfMacFactory.Default.hmacSha1()).extract(ikm, salt), 20);
checkLength(HKDF.fromHmacSha256().extract(salt, ikm), 32);
checkLength(HKDF.fromHmacSha256().extract(null, ikm), 32);
checkLength(HKDF.fromHmacSha256().extract(new byte[0], ikm), 32);
checkLength(HKDF.fromHmacSha512().extract(salt, ikm), 64);
checkLength(HKDF.fromHmacSha512().extract(null, ikm), 64);
checkLength(HKDF.from(HkdfMacFactory.Default.hmacSha1()).extract(salt, ikm), 20);
checkLength(HKDF.from(new HkdfMacFactory.Default("HmacMD5", 16)).extract(ikm, salt), 16);

assertFalse(Arrays.equals(HKDF.fromHmacSha256().extract(ikm, salt), HKDF.fromHmacSha512().extract(ikm, salt)));
assertFalse(Arrays.equals(HKDF.fromHmacSha256().extract(ikm, salt), HKDF.from(HkdfMacFactory.Default.hmacSha1()).extract(ikm, salt)));
assertFalse(Arrays.equals(HKDF.fromHmacSha256().extract(salt, ikm), HKDF.fromHmacSha512().extract(salt, ikm)));
assertFalse(Arrays.equals(HKDF.fromHmacSha256().extract(salt, ikm), HKDF.from(HkdfMacFactory.Default.hmacSha1()).extract(salt, ikm)));
}
}

Expand All @@ -107,13 +107,13 @@ private void checkLength(byte[] prk, int refOutLength) {
@Test
public void testExtractFailures() throws Exception {
try {
HKDF.fromHmacSha256().extract(null, RandomUtils.nextBytes(10));
HKDF.fromHmacSha256().extract(RandomUtils.nextBytes(10), null);
fail();
} catch (Exception ignored) {
}

try {
HKDF.fromHmacSha512().extract(new byte[0], null);
HKDF.fromHmacSha512().extract(null, new byte[0]);
fail();
} catch (Exception ignored) {
}
Expand Down Expand Up @@ -174,24 +174,24 @@ public void testExpandFailures() throws Exception {

@Test
public void extractAndExpand() throws Exception {
checkLength(HKDF.from(HkdfMacFactory.Default.hmacSha1()).extractAndExpand(RandomUtils.nextBytes(16), RandomUtils.nextBytes(20), null, 80), 80);
checkLength(HKDF.fromHmacSha256().extractAndExpand(RandomUtils.nextBytes(16), RandomUtils.nextBytes(32), null, 80), 80);
checkLength(HKDF.fromHmacSha512().extractAndExpand(RandomUtils.nextBytes(250), RandomUtils.nextBytes(64), null, 80), 80);
checkLength(HKDF.from(HkdfMacFactory.Default.hmacSha1()).extractAndExpand(RandomUtils.nextBytes(20), RandomUtils.nextBytes(16), null, 80), 80);
checkLength(HKDF.fromHmacSha256().extractAndExpand(RandomUtils.nextBytes(32), RandomUtils.nextBytes(16), null, 80), 80);
checkLength(HKDF.fromHmacSha512().extractAndExpand(RandomUtils.nextBytes(64), RandomUtils.nextBytes(250), null, 80), 80);
}

@Test
public void testLongInputExpand() throws Exception {
byte[] longInput = RandomUtils.nextBytes(1024 * 1024); //1 MiB
checkLength(HKDF.fromHmacSha256().extract(longInput, null), 32);
checkLength(HKDF.fromHmacSha256().extract(null, longInput), 32);
}

@Test
public void testLongOutputExtract() throws Exception {
int outLengthSha512 = 255 * 64;
checkLength(HKDF.fromHmacSha512().expand(HKDF.fromHmacSha512().extract(new byte[16], null), null, outLengthSha512), outLengthSha512);
checkLength(HKDF.fromHmacSha512().expand(HKDF.fromHmacSha512().extract(null, new byte[16]), null, outLengthSha512), outLengthSha512);

int outLengthSha256 = 255 * 32;
checkLength(HKDF.fromHmacSha256().expand(HKDF.fromHmacSha256().extract(new byte[16], null), null, outLengthSha256), outLengthSha256);
checkLength(HKDF.fromHmacSha256().expand(HKDF.fromHmacSha256().extract(null, new byte[16]), null, outLengthSha256), outLengthSha256);
}

@Test
Expand All @@ -214,7 +214,7 @@ public void run() {

byte[] ikm = RandomUtils.nextBytes(r.nextInt(12) + 12);
byte[] salt = RandomUtils.nextBytes(r.nextInt(32));
byte[] prk = hkdf.extract(ikm, salt);
byte[] prk = hkdf.extract(salt, ikm);

assertTrue(hkdf.getMacFactory().createInstance(new byte[1]).getMacLength() == prk.length);

Expand Down
4 changes: 2 additions & 2 deletions src/test/java/at/favre/lib/crypto/RFC5869TestCases.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ private void checkStep2Sha1(String prk, String info, int l, String okm) throws E
}

private void checkStep1(HkdfMacFactory macFactory, String ikm, String salt, String prk) throws Exception {
byte[] currentPrk = HKDF.from(macFactory).extract(Hex.decodeHex(ikm.toCharArray()),
Hex.decodeHex(salt.toCharArray()));
byte[] currentPrk = HKDF.from(macFactory).extract(Hex.decodeHex(salt.toCharArray()),
Hex.decodeHex(ikm.toCharArray()));
assertArrayEquals(Hex.decodeHex(prk.toCharArray()), currentPrk);
}

Expand Down

0 comments on commit cd31ee0

Please sign in to comment.