Skip to content

Commit

Permalink
Use parameterized tests to avoid repetition.
Browse files Browse the repository at this point in the history
  • Loading branch information
jchambers committed Feb 7, 2018
1 parent 0d623a1 commit 43e135b
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 100 deletions.
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
<version>4.12</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>pl.pragmatists</groupId>
<artifactId>JUnitParams</artifactId>
<version>1.1.1</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@

import javax.crypto.spec.SecretKeySpec;

import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JUnitParamsRunner.class)
public class HmacOneTimePasswordGeneratorTest {

@Test(expected = IllegalArgumentException.class)
Expand Down Expand Up @@ -65,27 +69,22 @@ public void testGetAlgorithm() throws NoSuchAlgorithmException {
* <a href="https://tools.ietf.org/html/rfc4226#appendix-D">RFC&nbsp;4226, Appendix D</a>.
*/
@Test
public void testGetOneTimePassword() throws InvalidKeyException, NoSuchAlgorithmException {
@Parameters({
"0, 755224",
"1, 287082",
"2, 359152",
"3, 969429",
"4, 338314",
"5, 254676",
"6, 287922",
"7, 162583",
"8, 399871",
"9, 520489" })
public void testGenerateOneTimePassword(final int counter, final int expectedOneTimePassword) throws Exception {
final HmacOneTimePasswordGenerator hmacOneTimePasswordGenerator = this.getDefaultGenerator();

final Key key = new SecretKeySpec("12345678901234567890".getBytes(StandardCharsets.US_ASCII), "RAW");

final int[] expectedValues = new int[] {
755224,
287082,
359152,
969429,
338314,
254676,
287922,
162583,
399871,
520489
};

for (int i = 0; i < expectedValues.length; i++) {
assertEquals(expectedValues[i], hmacOneTimePasswordGenerator.generateOneTimePassword(key, i));
}
assertEquals(expectedOneTimePassword, hmacOneTimePasswordGenerator.generateOneTimePassword(key, counter));
}

protected HmacOneTimePasswordGenerator getDefaultGenerator() throws NoSuchAlgorithmException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@

import javax.crypto.spec.SecretKeySpec;

import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JUnitParamsRunner.class)
public class TimeBasedOneTimePasswordGeneratorTest extends HmacOneTimePasswordGeneratorTest {

@Override
Expand All @@ -54,93 +58,40 @@ public void testGetTimeStep() throws NoSuchAlgorithmException {
}

/**
* Tests time-based one-time password generation using HMAC-SHA1 and the test vectors from
* <a href="https://tools.ietf.org/html/rfc6238#appendix-B">RFC&nbsp;6238, Appendix B</a>.
* Tests time-based one-time password generation using the test vectors from
* <a href="https://tools.ietf.org/html/rfc6238#appendix-B">RFC&nbsp;6238, Appendix B</a>. Note that the RFC
* incorrectly states that the same key is used for all test vectors. The
* <a href="https://www.rfc-editor.org/errata_search.php?rfc=6238&eid=2866">>errata</a> correctly points out that
* different keys are used for each of the various HMAC algorithms.
*/
@Test
public void testGenerateOneTimePasswordSha1() throws NoSuchAlgorithmException, InvalidKeyException {
final TimeBasedOneTimePasswordGenerator totp =
new TimeBasedOneTimePasswordGenerator(30, TimeUnit.SECONDS, 8, TimeBasedOneTimePasswordGenerator.TOTP_ALGORITHM_HMAC_SHA1);

final Key key;
{
final String keyString = "12345678901234567890";
key = new SecretKeySpec(keyString.getBytes(StandardCharsets.US_ASCII), "RAW");
}

final Map<Date, Integer> expectedPasswords = new HashMap<>();
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(59)), 94287082);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(1111111109)), 7081804);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(1111111111)), 14050471);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(1234567890)), 89005924);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(2000000000)), 69279037);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(20000000000L)), 65353130);
@Parameters({
"59, 94287082, 12345678901234567890, HmacSHA1",
"1111111109, 7081804, 12345678901234567890, HmacSHA1",
"1111111111, 14050471, 12345678901234567890, HmacSHA1",
"1234567890, 89005924, 12345678901234567890, HmacSHA1",
"2000000000, 69279037, 12345678901234567890, HmacSHA1",
"20000000000, 65353130, 12345678901234567890, HmacSHA1",
"59, 46119246, 12345678901234567890123456789012, HmacSHA256",
"1111111109, 68084774, 12345678901234567890123456789012, HmacSHA256",
"1111111111, 67062674, 12345678901234567890123456789012, HmacSHA256",
"1234567890, 91819424, 12345678901234567890123456789012, HmacSHA256",
"2000000000, 90698825, 12345678901234567890123456789012, HmacSHA256",
"20000000000, 77737706, 12345678901234567890123456789012, HmacSHA256",
"59, 90693936, 1234567890123456789012345678901234567890123456789012345678901234, HmacSHA512",
"1111111109, 25091201, 1234567890123456789012345678901234567890123456789012345678901234, HmacSHA512",
"1111111111, 99943326, 1234567890123456789012345678901234567890123456789012345678901234, HmacSHA512",
"1234567890, 93441116, 1234567890123456789012345678901234567890123456789012345678901234, HmacSHA512",
"2000000000, 38618901, 1234567890123456789012345678901234567890123456789012345678901234, HmacSHA512",
"20000000000, 47863826, 1234567890123456789012345678901234567890123456789012345678901234, HmacSHA512" })
public void testGenerateOneTimePassword(final long epochSeconds, final int expectedOneTimePassword, final String keyString, final String algorithm) throws Exception {

this.validateOneTimePasswords(totp, key, expectedPasswords);
}

/**
* Tests time-based one-time password generation using HMAC-SHA256 and the test vectors from
* <a href="https://tools.ietf.org/html/rfc6238#appendix-B">RFC&nbsp;6238, Appendix B</a>.
*/
@Test
public void testGenerateOneTimePasswordSha256() throws NoSuchAlgorithmException, InvalidKeyException {
final TimeBasedOneTimePasswordGenerator totp =
new TimeBasedOneTimePasswordGenerator(30, TimeUnit.SECONDS, 8, TimeBasedOneTimePasswordGenerator.TOTP_ALGORITHM_HMAC_SHA256);

final Key key;
{
// The RFC incorrectly states that the same key is used for all test vectors, but that's not actually true;
// see the errata (https://www.rfc-editor.org/errata_search.php?rfc=6238&eid=2866) for details
final String keyString = "12345678901234567890123456789012";
key = new SecretKeySpec(keyString.getBytes(StandardCharsets.US_ASCII), "RAW");
}

final Map<Date, Integer> expectedPasswords = new HashMap<>();
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(59)), 46119246);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(1111111109)), 68084774);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(1111111111)), 67062674);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(1234567890)), 91819424);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(2000000000)), 90698825);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(20000000000L)), 77737706);

this.validateOneTimePasswords(totp, key, expectedPasswords);
}

/**
* Tests time-based one-time password generation using HMAC-SHA512 and the test vectors from
* <a href="https://tools.ietf.org/html/rfc6238#appendix-B">RFC&nbsp;6238, Appendix B</a>.
*/
@Test
public void testGenerateOneTimePasswordSha512() throws NoSuchAlgorithmException, InvalidKeyException {
final TimeBasedOneTimePasswordGenerator totp =
new TimeBasedOneTimePasswordGenerator(30, TimeUnit.SECONDS, 8, TimeBasedOneTimePasswordGenerator.TOTP_ALGORITHM_HMAC_SHA512);

final Key key;
{
// The RFC incorrectly states that the same key is used for all test vectors, but that's not actually true;
// see the errata (https://www.rfc-editor.org/errata_search.php?rfc=6238&eid=2866) for details
final String keyString = "1234567890123456789012345678901234567890123456789012345678901234";
key = new SecretKeySpec(keyString.getBytes(StandardCharsets.US_ASCII), "RAW");
}

final Map<Date, Integer> expectedPasswords = new HashMap<>();
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(59)), 90693936);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(1111111109)), 25091201);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(1111111111)), 99943326);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(1234567890)), 93441116);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(2000000000)), 38618901);
expectedPasswords.put(new Date(TimeUnit.SECONDS.toMillis(20000000000L)), 47863826);

this.validateOneTimePasswords(totp, key, expectedPasswords);
}
new TimeBasedOneTimePasswordGenerator(30, TimeUnit.SECONDS, 8, algorithm);

private void validateOneTimePasswords(final TimeBasedOneTimePasswordGenerator totp, final Key key, final Map<Date, Integer> expectedPasswords) throws InvalidKeyException {
for (final Map.Entry<Date, Integer> entry : expectedPasswords.entrySet()) {
final Date date = entry.getKey();
final int expectedPassword = entry.getValue();
final Key key = new SecretKeySpec(keyString.getBytes(StandardCharsets.US_ASCII), "RAW");
final Date date = new Date(TimeUnit.SECONDS.toMillis(epochSeconds));

assertEquals(expectedPassword, totp.generateOneTimePassword(key, date));
}
assertEquals(expectedOneTimePassword, totp.generateOneTimePassword(key, date));
}
}

0 comments on commit 43e135b

Please sign in to comment.