Skip to content

Commit ee18ade

Browse files
committed
Use JSR-310 types instead of java.util.Date.
1 parent 9f5d094 commit ee18ade

File tree

4 files changed

+37
-39
lines changed

4 files changed

+37
-39
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ final Key key;
2121
{
2222
final KeyGenerator keyGenerator = KeyGenerator.getInstance(totp.getAlgorithm());
2323

24-
// HMAC-SHA1 and HMAC-SHA256 prefer 64-byte (512-bit) keys; HMAC-SHA512 prefers 128-byte (1024-bit) keys
24+
// SHA-1 and SHA-256 prefer 64-byte (512-bit) keys; SHA512 prefers 128-byte (1024-bit) keys
2525
keyGenerator.init(512);
2626

2727
key = keyGenerator.generateKey();
@@ -31,8 +31,8 @@ final Key key;
3131
Armed with a secret key, we can deterministically generate one-time passwords for any timestamp:
3232

3333
```java
34-
final Date now = new Date();
35-
final Date later = new Date(now.getTime() + totp.getTimeStep(TimeUnit.MILLISECONDS));
34+
final Instant now = Instant.now();
35+
final Instant later = now.plus(totp.getTimeStep());
3636

3737
System.out.format("Current password: %06d\n", totp.generateOneTimePassword(key, now));
3838
System.out.format("Future password: %06d\n", totp.generateOneTimePassword(key, later));

src/main/java/com/eatthepath/otp/TimeBasedOneTimePasswordGenerator.java

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
import java.security.InvalidKeyException;
2525
import java.security.Key;
2626
import java.security.NoSuchAlgorithmException;
27-
import java.util.Date;
28-
import java.util.concurrent.TimeUnit;
27+
import java.time.Duration;
28+
import java.time.Instant;
2929

3030
/**
3131
* <p>Generates time-based one-time passwords (TOTP) as specified in
@@ -37,7 +37,12 @@
3737
* @author <a href="https://github.com/jchambers">Jon Chambers</a>
3838
*/
3939
public class TimeBasedOneTimePasswordGenerator extends HmacOneTimePasswordGenerator {
40-
private final long timeStepMillis;
40+
private final Duration timeStep;
41+
42+
/**
43+
* The default time-step for a time-based one-time password generator (30 seconds).
44+
*/
45+
public static final Duration DEFAULT_TIME_STEP = Duration.ofSeconds(30);
4146

4247
/**
4348
* A string identifier for the HMAC-SHA1 algorithm (required by HOTP and allowed by TOTP). HMAC-SHA1 is the default
@@ -65,48 +70,45 @@ public class TimeBasedOneTimePasswordGenerator extends HmacOneTimePasswordGenera
6570
* happen except in cases of serious misconfiguration
6671
*/
6772
public TimeBasedOneTimePasswordGenerator() throws NoSuchAlgorithmException {
68-
this(30, TimeUnit.SECONDS);
73+
this(DEFAULT_TIME_STEP);
6974
}
7075

7176
/**
7277
* Constructs a new time-based one-time password generator with the given time-step and a default password length
7378
* ({@value com.eatthepath.otp.HmacOneTimePasswordGenerator#DEFAULT_PASSWORD_LENGTH} decimal digits) and HMAC
7479
* algorithm ({@value com.eatthepath.otp.HmacOneTimePasswordGenerator#HOTP_HMAC_ALGORITHM}).
7580
*
76-
* @param timeStep the magnitude of the time-step for this generator
77-
* @param timeStepUnit the units for the the given time step
81+
* @param timeStep the time-step for this generator
7882
*
7983
* @throws NoSuchAlgorithmException if the underlying JRE doesn't support the
8084
* {@value com.eatthepath.otp.HmacOneTimePasswordGenerator#HOTP_HMAC_ALGORITHM} algorithm, which should never
8185
* happen except in cases of serious misconfiguration
8286
*/
83-
public TimeBasedOneTimePasswordGenerator(final long timeStep, final TimeUnit timeStepUnit) throws NoSuchAlgorithmException {
84-
this(timeStep, timeStepUnit, HmacOneTimePasswordGenerator.DEFAULT_PASSWORD_LENGTH);
87+
public TimeBasedOneTimePasswordGenerator(final Duration timeStep) throws NoSuchAlgorithmException {
88+
this(timeStep, HmacOneTimePasswordGenerator.DEFAULT_PASSWORD_LENGTH);
8589
}
8690

8791
/**
8892
* Constructs a new time-based one-time password generator with the given time-step and password length and a
8993
* default HMAC algorithm ({@value com.eatthepath.otp.HmacOneTimePasswordGenerator#HOTP_HMAC_ALGORITHM}).
9094
*
91-
* @param timeStep the magnitude of the time-step for this generator
92-
* @param timeStepUnit the units for the the given time step
95+
* @param timeStep the time-step for this generator
9396
* @param passwordLength the length, in decimal digits, of the one-time passwords to be generated; must be between
9497
* 6 and 8, inclusive
9598
*
9699
* @throws NoSuchAlgorithmException if the underlying JRE doesn't support the
97100
* {@value com.eatthepath.otp.HmacOneTimePasswordGenerator#HOTP_HMAC_ALGORITHM} algorithm, which should never
98101
* happen except in cases of serious misconfiguration
99102
*/
100-
public TimeBasedOneTimePasswordGenerator(final long timeStep, final TimeUnit timeStepUnit, final int passwordLength) throws NoSuchAlgorithmException {
101-
this(timeStep, timeStepUnit, passwordLength, TOTP_ALGORITHM_HMAC_SHA1);
103+
public TimeBasedOneTimePasswordGenerator(final Duration timeStep, final int passwordLength) throws NoSuchAlgorithmException {
104+
this(timeStep, passwordLength, TOTP_ALGORITHM_HMAC_SHA1);
102105
}
103106

104107
/**
105108
* Constructs a new time-based one-time password generator with the given time-step, password length, and HMAC
106109
* algorithm.
107110
*
108-
* @param timeStep the magnitude of the time-step for this generator
109-
* @param timeStepUnit the units for the the given time step
111+
* @param timeStep the time-step for this generator
110112
* @param passwordLength the length, in decimal digits, of the one-time passwords to be generated; must be between
111113
* 6 and 8, inclusive
112114
* @param algorithm the name of the {@link javax.crypto.Mac} algorithm to use when generating passwords; TOTP allows
@@ -120,10 +122,10 @@ public TimeBasedOneTimePasswordGenerator(final long timeStep, final TimeUnit tim
120122
* @see com.eatthepath.otp.TimeBasedOneTimePasswordGenerator#TOTP_ALGORITHM_HMAC_SHA256
121123
* @see com.eatthepath.otp.TimeBasedOneTimePasswordGenerator#TOTP_ALGORITHM_HMAC_SHA512
122124
*/
123-
public TimeBasedOneTimePasswordGenerator(final long timeStep, final TimeUnit timeStepUnit, final int passwordLength, final String algorithm) throws NoSuchAlgorithmException {
125+
public TimeBasedOneTimePasswordGenerator(final Duration timeStep, final int passwordLength, final String algorithm) throws NoSuchAlgorithmException {
124126
super(passwordLength, algorithm);
125127

126-
this.timeStepMillis = timeStepUnit.toMillis(timeStep);
128+
this.timeStep = timeStep;
127129
}
128130

129131
/**
@@ -137,18 +139,16 @@ public TimeBasedOneTimePasswordGenerator(final long timeStep, final TimeUnit tim
137139
*
138140
* @throws InvalidKeyException if the given key is inappropriate for initializing the {@link Mac} for this generator
139141
*/
140-
public int generateOneTimePassword(final Key key, final Date timestamp) throws InvalidKeyException {
141-
return this.generateOneTimePassword(key, timestamp.getTime() / this.timeStepMillis);
142+
public int generateOneTimePassword(final Key key, final Instant timestamp) throws InvalidKeyException {
143+
return this.generateOneTimePassword(key, timestamp.toEpochMilli() / this.timeStep.toMillis());
142144
}
143145

144146
/**
145147
* Returns the time step used by this generator.
146148
*
147-
* @param timeUnit the units of time in which to return the time step
148-
*
149-
* @return the time step used by this generator in the given units of time
149+
* @return the time step used by this generator
150150
*/
151-
public long getTimeStep(final TimeUnit timeUnit) {
152-
return timeUnit.convert(this.timeStepMillis, TimeUnit.MILLISECONDS);
151+
public Duration getTimeStep() {
152+
return this.timeStep;
153153
}
154154
}

src/test/java/com/eatthepath/otp/ExampleApp.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
import java.security.InvalidKeyException;
2525
import java.security.Key;
2626
import java.security.NoSuchAlgorithmException;
27-
import java.util.Date;
28-
import java.util.concurrent.TimeUnit;
27+
import java.time.Instant;
2928

3029
public class ExampleApp {
3130
public static void main(final String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
@@ -41,8 +40,8 @@ public static void main(final String[] args) throws NoSuchAlgorithmException, In
4140
key = keyGenerator.generateKey();
4241
}
4342

44-
final Date now = new Date();
45-
final Date later = new Date(now.getTime() + totp.getTimeStep(TimeUnit.MILLISECONDS));
43+
final Instant now = Instant.now();
44+
final Instant later = now.plus(totp.getTimeStep());
4645

4746
System.out.format("Current password: %06d\n", totp.generateOneTimePassword(key, now));
4847
System.out.format("Future password: %06d\n", totp.generateOneTimePassword(key, later));

src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
import java.nio.charset.StandardCharsets;
3030
import java.security.Key;
3131
import java.security.NoSuchAlgorithmException;
32-
import java.util.Date;
33-
import java.util.concurrent.TimeUnit;
32+
import java.time.Duration;
33+
import java.time.Instant;
3434
import java.util.stream.Stream;
3535

3636
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -58,13 +58,12 @@ protected HmacOneTimePasswordGenerator getDefaultGenerator() throws NoSuchAlgori
5858

5959
@Test
6060
void testGetTimeStep() throws NoSuchAlgorithmException {
61-
final long timeStepSeconds = 97;
61+
final Duration timeStep = Duration.ofSeconds(97);
6262

6363
final TimeBasedOneTimePasswordGenerator totp =
64-
new TimeBasedOneTimePasswordGenerator(timeStepSeconds, TimeUnit.SECONDS);
64+
new TimeBasedOneTimePasswordGenerator(timeStep);
6565

66-
assertEquals(timeStepSeconds, totp.getTimeStep(TimeUnit.SECONDS));
67-
assertEquals(timeStepSeconds * 1000, totp.getTimeStep(TimeUnit.MILLISECONDS));
66+
assertEquals(timeStep, totp.getTimeStep());
6867
}
6968

7069
/**
@@ -79,11 +78,11 @@ void testGetTimeStep() throws NoSuchAlgorithmException {
7978
void testGenerateOneTimePassword(final String algorithm, final Key key, final long epochSeconds, final int expectedOneTimePassword) throws Exception {
8079

8180
final TimeBasedOneTimePasswordGenerator totp =
82-
new TimeBasedOneTimePasswordGenerator(30, TimeUnit.SECONDS, 8, algorithm);
81+
new TimeBasedOneTimePasswordGenerator(Duration.ofSeconds(30), 8, algorithm);
8382

84-
final Date date = new Date(TimeUnit.SECONDS.toMillis(epochSeconds));
83+
final Instant timestamp = Instant.ofEpochSecond(epochSeconds);
8584

86-
assertEquals(expectedOneTimePassword, totp.generateOneTimePassword(key, date));
85+
assertEquals(expectedOneTimePassword, totp.generateOneTimePassword(key, timestamp));
8786
}
8887

8988
static Stream<Arguments> totpTestVectorSource() {

0 commit comments

Comments
 (0)