diff --git a/pom.xml b/pom.xml index 9b97070..68e64e2 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,13 @@ 4.12 test + + + pl.pragmatists + JUnitParams + 1.1.1 + test + diff --git a/src/test/java/com/eatthepath/otp/HmacOneTimePasswordGeneratorTest.java b/src/test/java/com/eatthepath/otp/HmacOneTimePasswordGeneratorTest.java index 8eb80ba..2f7962e 100644 --- a/src/test/java/com/eatthepath/otp/HmacOneTimePasswordGeneratorTest.java +++ b/src/test/java/com/eatthepath/otp/HmacOneTimePasswordGeneratorTest.java @@ -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) @@ -65,27 +69,22 @@ public void testGetAlgorithm() throws NoSuchAlgorithmException { * RFC 4226, Appendix D. */ @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 { diff --git a/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java b/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java index b8d4f09..f011064 100644 --- a/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java +++ b/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java @@ -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 @@ -54,93 +58,40 @@ public void testGetTimeStep() throws NoSuchAlgorithmException { } /** - * Tests time-based one-time password generation using HMAC-SHA1 and the test vectors from - * RFC 6238, Appendix B. + * Tests time-based one-time password generation using the test vectors from + * RFC 6238, Appendix B. Note that the RFC + * incorrectly states that the same key is used for all test vectors. The + * >errata 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 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 - * RFC 6238, Appendix B. - */ - @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 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 - * RFC 6238, Appendix B. - */ - @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 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 expectedPasswords) throws InvalidKeyException { - for (final Map.Entry 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)); } }