diff --git a/README.md b/README.md index d9eb8b8..80e16ea 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ java-otp is a library for generating one-time passwords using the [HOTP (RFC 422 ## Usage -To demonstrate generating one-time passwords, we'll focus on the TOTP algorithm. To create a TOTP generator with a default password length, time step, and HMAC algorithm: +To demonstrate generating one-time passwords, we'll focus on the TOTP algorithm. To create a TOTP generator with a default password length (6 digits), time step (30 seconds), and HMAC algorithm (HMAC-SHA1): ```java final TimeBasedOneTimePasswordGenerator totp = new TimeBasedOneTimePasswordGenerator(); @@ -17,7 +17,7 @@ final Key secretKey; { final KeyGenerator keyGenerator = KeyGenerator.getInstance(totp.getAlgorithm()); - // SHA-1 and SHA-256 prefer 64-byte (512-bit) keys; SHA512 prefers 128-byte keys + // HMAC-SHA1 and HMAC-SHA256 prefer 64-byte (512-bit) keys; HMAC-SHA512 prefers 128-byte (1024-bit) keys keyGenerator.init(512); secretKey = keyGenerator.generateKey(); @@ -28,12 +28,19 @@ Armed with a secret key, we can deterministically generate one-time passwords fo ```java final Date now = new Date(); -final Date later = new Date(now.getTime() + TimeUnit.SECONDS.toMillis(30)); +final Date later = new Date(now.getTime() + totp.getTimeStep(TimeUnit.MILLISECONDS)); System.out.format("Current password: %06d\n", totp.generateOneTimePassword(secretKey, now)); System.out.format("Future password: %06d\n", totp.generateOneTimePassword(secretKey, later)); ``` +…which produces (for one randomly-generated key): + +``` +Current password: 164092 +Future password: 046148 +``` + ## License and copyright java-otp is published under the [MIT License](https://opensource.org/licenses/MIT). diff --git a/src/main/java/com/eatthepath/otp/TimeBasedOneTimePasswordGenerator.java b/src/main/java/com/eatthepath/otp/TimeBasedOneTimePasswordGenerator.java index ad3f8ba..3174beb 100644 --- a/src/main/java/com/eatthepath/otp/TimeBasedOneTimePasswordGenerator.java +++ b/src/main/java/com/eatthepath/otp/TimeBasedOneTimePasswordGenerator.java @@ -20,14 +20,13 @@ package com.eatthepath.otp; +import javax.crypto.Mac; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.concurrent.TimeUnit; -import javax.crypto.Mac; - /** *
Generates time-based one-time passwords (TOTP) as specified in * RFC 6238.
@@ -99,7 +98,7 @@ public TimeBasedOneTimePasswordGenerator(final long timeStep, final TimeUnit tim * happen except in cases of serious misconfiguration */ public TimeBasedOneTimePasswordGenerator(final long timeStep, final TimeUnit timeStepUnit, final int passwordLength) throws NoSuchAlgorithmException { - this(timeStep, timeStepUnit, passwordLength, HmacOneTimePasswordGenerator.HOTP_HMAC_ALGORITHM); + this(timeStep, timeStepUnit, passwordLength, TOTP_ALGORITHM_HMAC_SHA1); } /** diff --git a/src/test/java/com/eatthepath/otp/ExampleApp.java b/src/test/java/com/eatthepath/otp/ExampleApp.java index f0dc957..ba25ccf 100644 --- a/src/test/java/com/eatthepath/otp/ExampleApp.java +++ b/src/test/java/com/eatthepath/otp/ExampleApp.java @@ -20,14 +20,13 @@ package com.eatthepath.otp; +import javax.crypto.KeyGenerator; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.concurrent.TimeUnit; -import javax.crypto.KeyGenerator; - public class ExampleApp { public static void main(final String[] args) throws NoSuchAlgorithmException, InvalidKeyException { final TimeBasedOneTimePasswordGenerator totp = new TimeBasedOneTimePasswordGenerator(); @@ -36,14 +35,14 @@ public static void main(final String[] args) throws NoSuchAlgorithmException, In { final KeyGenerator keyGenerator = KeyGenerator.getInstance(totp.getAlgorithm()); - // SHA-1 and SHA-256 prefer 64-byte (512-bit) keys; SHA512 prefers 128-byte keys + // SHA-1 and SHA-256 prefer 64-byte (512-bit) keys; SHA512 prefers 128-byte (1024-bit) keys keyGenerator.init(512); secretKey = keyGenerator.generateKey(); } final Date now = new Date(); - final Date later = new Date(now.getTime() + TimeUnit.SECONDS.toMillis(30)); + final Date later = new Date(now.getTime() + totp.getTimeStep(TimeUnit.MILLISECONDS)); System.out.format("Current password: %06d\n", totp.generateOneTimePassword(secretKey, now)); System.out.format("Future password: %06d\n", totp.generateOneTimePassword(secretKey, later)); diff --git a/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java b/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java index 69fd3c2..d7e3d7d 100644 --- a/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java +++ b/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java @@ -20,23 +20,19 @@ package com.eatthepath.otp; -import static org.junit.Assert.*; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; +import org.junit.Test; +import org.junit.runner.RunWith; +import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.util.Date; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.TimeUnit; -import javax.crypto.spec.SecretKeySpec; - -import junitparams.JUnitParamsRunner; -import junitparams.Parameters; -import org.junit.Test; -import org.junit.runner.RunWith; +import static org.junit.Assert.assertEquals; @RunWith(JUnitParamsRunner.class) public class TimeBasedOneTimePasswordGeneratorTest extends HmacOneTimePasswordGeneratorTest { @@ -61,7 +57,7 @@ public void testGetTimeStep() throws NoSuchAlgorithmException { * 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 + * errata correctly points out that * different keys are used for each of the various HMAC algorithms. */ @Test