Skip to content

Commit

Permalink
Add some more tests and simple micro benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickfav committed Oct 2, 2017
1 parent ad4f19c commit 8105c01
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 12 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG
@@ -1,5 +1,10 @@
# Releases

## v0.1.0
## v1.0.0

* refactor 'expand' byte handling to use byte buffer


## v0.2.1

initial version
12 changes: 2 additions & 10 deletions src/main/java/at/favre/crypto/HKDF.java
Expand Up @@ -98,7 +98,7 @@ public static HKDF from(HkdfMacFactory macFactory) {
* @param inputKeyingMaterial data to be extracted (IKM)
* @param salt optional salt value (a non-secret random value);
* 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
* @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) {
Expand All @@ -125,7 +125,7 @@ public byte[] extract(byte[] inputKeyingMaterial, byte[] salt) {
* different contexts).
* </blockquote>
*
* @param pseudoRandomKey a pseudorandom key of at least hmac hash length in bytes (usually, the output from the extract step)
* @param pseudoRandomKey a pseudo random key of at least hmac hash length in bytes (usually, the output from the extract step)
* @param info optional context and application specific information; may be null
* @param outLengthBytes length of output keying material in bytes
* @return new byte array of output keying material (OKM)
Expand Down Expand Up @@ -168,10 +168,6 @@ static final class Extractor {

/**
* Step 1 of RFC 5869
* <p>
* The first stage takes the input keying material and "extracts" from it a fixed-length pseudorandom
* key K. The goal of the "extract" stage is to "concentrate" the possibly dispersed entropy of the input
* keying material into a short, but cryptographically strong, pseudorandom key.
*
* @param inputKeyingMaterial data to be extracted (IKM)
* @param salt optional salt value (a non-secret random value);
Expand Down Expand Up @@ -202,10 +198,6 @@ static final class Expander {

/**
* Step 2 of RFC 5869.
* <p>
* The second stage "expands" the pseudorandom key to the desired
* length; the number and lengths of the output keys depend on the
* specific cryptographic algorithms for which the keys are needed.
*
* @param pseudoRandomKey a pseudorandom key of at least hmac hash length in bytes (usually, the output from the extract step)
* @param info optional context and application specific information; may be null
Expand Down
60 changes: 60 additions & 0 deletions src/test/java/at/favre/crypto/HKDFBenchmarkTest.java
@@ -0,0 +1,60 @@
package at.favre.crypto;

import org.apache.commons.lang3.RandomUtils;
import org.junit.Ignore;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.assertTrue;

public class HKDFBenchmarkTest {

// i7-7700k, 16GB DDR4, Java 8.131
// count: 2042
// Run (0): 3873013044ns
// Run (1): 3602475691ns
// Run (2): 3602419370ns
// Run (3): 3613280596ns
// Run (4): 3609781686ns

@Ignore
@Test
public void quickStarTest() throws Exception {

Map<Integer, Long> runsMap = new HashMap<>();

int rounds = 5;
byte[] input;
for (int i = 0; i < rounds; i++) {
int count = 0;
long start = System.nanoTime();

//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[] outputKeyingMaterial = HKDF.fromHmacSha256().expand(pseudoRandomKey, null, 32);
assertTrue(outputKeyingMaterial.length > 0);
count++;
}

//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[] outputKeyingMaterial = HKDF.fromHmacSha512().expand(pseudoRandomKey, null, j);
assertTrue(outputKeyingMaterial.length > 0);
count++;
}

runsMap.put(i, System.nanoTime() - start);
System.out.println("count (" + i + "):" + count);
}

for (Map.Entry<Integer, Long> entry : runsMap.entrySet()) {
System.out.println("Run (" + entry.getKey() + "): " + entry.getValue() + "ns");
}
}
}
24 changes: 23 additions & 1 deletion src/test/java/at/favre/crypto/HKDFTest.java
Expand Up @@ -52,12 +52,19 @@ public void simpleUseCase() throws Exception {

//Example boilerplate encrypting a simple string with created key/iv
SecretKey key = new SecretKeySpec(expandedAesKey, "AES"); //AES-128 key
byte[] message = "my secret message".getBytes(StandardCharsets.UTF_8);
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));
byte[] encrypted = cipher.doFinal(message);

assertNotNull(encrypted);
assertTrue(encrypted.length > 0);

cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(expandedIv));
byte[] decrypted = cipher.doFinal(encrypted);

assertArrayEquals(message, decrypted);
assertFalse(Arrays.equals(encrypted, decrypted));
}

@Test
Expand Down Expand Up @@ -172,6 +179,21 @@ public void extractAndExpand() throws Exception {
checkLength(HKDF.fromHmacSha512().extractAndExpand(RandomUtils.nextBytes(250), RandomUtils.nextBytes(64), null, 80), 80);
}

@Test
public void testLongInputExpand() throws Exception {
byte[] longInput = RandomUtils.nextBytes(1024 * 1024); //1 MiB
checkLength(HKDF.fromHmacSha256().extract(longInput, null), 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);

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

@Test
public void multiThreadParallelTest() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(32);
Expand Down

0 comments on commit 8105c01

Please sign in to comment.