Add OTP#getNextPin(), clean up code
This commit is contained in:
parent
1896eef707
commit
46acdedb8b
2
pom.xml
2
pom.xml
@ -2,7 +2,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.cringe_studios</groupId>
|
<groupId>com.cringe_studios</groupId>
|
||||||
<artifactId>CringeAuthenticatorLibrary</artifactId>
|
<artifactId>CringeAuthenticatorLibrary</artifactId>
|
||||||
<version>1.6</version>
|
<version>1.7</version>
|
||||||
<name>CringeAuthenticatorLibrary</name>
|
<name>CringeAuthenticatorLibrary</name>
|
||||||
<description>The Library of the Cringe Authenticator</description>
|
<description>The Library of the Cringe Authenticator</description>
|
||||||
<build>
|
<build>
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package com.cringe_studios.cringe_authenticator_library;
|
package com.cringe_studios.cringe_authenticator_library;
|
||||||
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
|
|
||||||
import com.cringe_studios.cringe_authenticator_library.impl.Base32;
|
import com.cringe_studios.cringe_authenticator_library.impl.Base32;
|
||||||
|
import com.cringe_studios.cringe_authenticator_library.impl.TOTP;
|
||||||
|
|
||||||
public abstract class OTP {
|
public abstract class OTP {
|
||||||
//TOTP
|
//TOTP
|
||||||
@ -56,11 +55,18 @@ public abstract class OTP {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return s the current pin, as calculated by the counter or the current time, unless it
|
* @return the current pin, as calculated by the counter or the current time
|
||||||
* @throws an OTPException, which is either thrown, if you somehow create an OTP with an invalid key, despite the checks in the instantiate method, or if your platform does not support the hashing algorithm you selected
|
* @throws OTPException is either thrown, if you somehow create an OTP with an invalid key, despite the checks in the instantiate method, or if your platform does not support the hashing algorithm you selected
|
||||||
*/
|
*/
|
||||||
public abstract String getPin() throws OTPException;
|
public abstract String getPin() throws OTPException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the next pin, as calculated by the counter or the current time
|
||||||
|
* @throws OTPException is either thrown, if you somehow create an OTP with an invalid key, despite the checks in the instantiate method, or if your platform does not support the hashing algorithm you selected
|
||||||
|
*/
|
||||||
|
public abstract String getNextPin() throws OTPException;
|
||||||
|
|
||||||
public abstract void incrementCounter();
|
public abstract void incrementCounter();
|
||||||
|
|
||||||
public String getSecret() {
|
public String getSecret() {
|
||||||
@ -91,8 +97,12 @@ public abstract class OTP {
|
|||||||
return checksum;
|
return checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seconds towards positive infinity means a positive correction into the future (seconds = 2 -> 5 becomes 7)
|
/**
|
||||||
// Seconds towards negative infinity means a negative correction into the past (seconds = -2 -> 5 becomes 3)
|
* Adjusts the timestamps used for OTP calculations in {@link TOTP} codes relative to the system clock.<br>
|
||||||
|
* - A positive value means a positive correction into the future (seconds = 2 -> 5 becomes 7)<br>
|
||||||
|
* - A negative value means a negative correction into the past (seconds = -2 -> 5 becomes 3)
|
||||||
|
* @param seconds The amount to adjust by
|
||||||
|
*/
|
||||||
public static void setTimeCorrection(long seconds) {
|
public static void setTimeCorrection(long seconds) {
|
||||||
timeOffset = seconds;
|
timeOffset = seconds;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
package com.cringe_studios.cringe_authenticator_library.impl;
|
package com.cringe_studios.cringe_authenticator_library.impl;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import com.cringe_studios.cringe_authenticator_library.OTP;
|
import com.cringe_studios.cringe_authenticator_library.OTP;
|
||||||
import com.cringe_studios.cringe_authenticator_library.OTPAlgorithm;
|
import com.cringe_studios.cringe_authenticator_library.OTPAlgorithm;
|
||||||
@ -29,18 +27,19 @@ public class HOTP extends OTP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPin() throws OTPException{
|
public String getPin() throws OTPException {
|
||||||
try {
|
return getPinAtCounter(getCounter());
|
||||||
long movingFactor = this.getCounter();
|
|
||||||
|
|
||||||
byte[] text = new byte[Long.BYTES];
|
|
||||||
for (int i = text.length - 1; i >= 0; i--) {
|
|
||||||
text[i] = (byte) (movingFactor & 0xff);
|
|
||||||
movingFactor >>= 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return generateOTP(-1, text);
|
@Override
|
||||||
|
public String getNextPin() throws OTPException {
|
||||||
|
return getPinAtCounter(getCounter() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPinAtCounter(long counter) throws OTPException {
|
||||||
|
try {
|
||||||
|
byte[] msg = ByteBuffer.allocate(Long.BYTES).putLong(counter).array();
|
||||||
|
return generateOTP(-1, msg);
|
||||||
} catch (InvalidKeyException e) {
|
} catch (InvalidKeyException e) {
|
||||||
throw new OTPException("Your secret is invalid! Please rescan the code!", e);
|
throw new OTPException("Your secret is invalid! Please rescan the code!", e);
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
package com.cringe_studios.cringe_authenticator_library.impl;
|
package com.cringe_studios.cringe_authenticator_library.impl;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
|
|
||||||
import com.cringe_studios.cringe_authenticator_library.OTPAlgorithm;
|
import com.cringe_studios.cringe_authenticator_library.OTPAlgorithm;
|
||||||
import com.cringe_studios.cringe_authenticator_library.OTPException;
|
import com.cringe_studios.cringe_authenticator_library.OTPException;
|
||||||
import com.cringe_studios.cringe_authenticator_library.OTPType;
|
import com.cringe_studios.cringe_authenticator_library.OTPType;
|
||||||
@ -24,48 +20,21 @@ public class TOTP extends HOTP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPin() throws OTPException{
|
public String getPin() throws OTPException {
|
||||||
try {
|
return getPinAtTime(System.currentTimeMillis() / 1000);
|
||||||
return getPinAt(System.currentTimeMillis() / 1000);
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
throw new OTPException("Your secret is invalid! Please rescan the code!", e);
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new OTPException("Your platform does not support the " + this.getAlgorithm().name() + "algorithm!", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getCounter() {
|
public long getCounter() {
|
||||||
return getCounterAt(System.currentTimeMillis() / 1000 - super.getTimeCorrection());
|
return getCounterAt(System.currentTimeMillis() / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getCounterAt(long unixSecond) {
|
private long getCounterAt(long unixSecond) {
|
||||||
return unixSecond / this.getPeriod();
|
return (unixSecond - getTimeCorrection()) / this.getPeriod();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPinAt(long time) throws InvalidKeyException, NoSuchAlgorithmException {
|
public String getPinAtTime(long unixSecond) throws OTPException {
|
||||||
//int codeDigits = this.getDigits();
|
return getPinAtCounter(getCounterAt(unixSecond));
|
||||||
|
|
||||||
// Get the HEX in a Byte[]
|
|
||||||
byte[] msg = ByteBuffer.allocate(Long.BYTES).putLong(this.getCounterAt(time)).array();
|
|
||||||
//byte[] k = this.secret;
|
|
||||||
//byte[] hash = this.getAlgorithm().hash(k, msg);
|
|
||||||
|
|
||||||
// put selected bytes into result int
|
|
||||||
//int offset = hash[hash.length - 1] & 0xf;
|
|
||||||
|
|
||||||
//int binary = ((hash[offset] & 0x7f) << 24) | ((hash[offset + 1] & 0xff) << 16)
|
|
||||||
// | ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff);
|
|
||||||
|
|
||||||
//int otp = binary % DIGITS_POWER[codeDigits];
|
|
||||||
|
|
||||||
//String result = Integer.toString(otp);
|
|
||||||
//while (result.length() < codeDigits) {
|
|
||||||
// result = "0" + result;
|
|
||||||
//}
|
|
||||||
//return result;
|
|
||||||
|
|
||||||
return this.generateOTP(-1, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,6 +18,7 @@ import com.cringe_studios.cringe_authenticator_library.OTPAlgorithm;
|
|||||||
import com.cringe_studios.cringe_authenticator_library.OTPException;
|
import com.cringe_studios.cringe_authenticator_library.OTPException;
|
||||||
import com.cringe_studios.cringe_authenticator_library.OTPType;
|
import com.cringe_studios.cringe_authenticator_library.OTPType;
|
||||||
import com.cringe_studios.cringe_authenticator_library.impl.Base32;
|
import com.cringe_studios.cringe_authenticator_library.impl.Base32;
|
||||||
|
import com.cringe_studios.cringe_authenticator_library.impl.HOTP;
|
||||||
import com.cringe_studios.cringe_authenticator_library.impl.TOTP;
|
import com.cringe_studios.cringe_authenticator_library.impl.TOTP;
|
||||||
|
|
||||||
public class OTPTest {
|
public class OTPTest {
|
||||||
@ -192,9 +193,9 @@ public class OTPTest {
|
|||||||
String fmtTime = String.format("%1$-11s", testTime[i]);
|
String fmtTime = String.format("%1$-11s", testTime[i]);
|
||||||
String utcTime = df.format(new Date(testTime[i] * 1000));
|
String utcTime = df.format(new Date(testTime[i] * 1000));
|
||||||
|
|
||||||
String sha1Pin = testOTP1.getPinAt(testTime[i]);
|
String sha1Pin = testOTP1.getPinAtTime(testTime[i]);
|
||||||
String sha256Pin = testOTP256.getPinAt(testTime[i]);
|
String sha256Pin = testOTP256.getPinAtTime(testTime[i]);
|
||||||
String sha512Pin = testOTP512.getPinAt(testTime[i]);
|
String sha512Pin = testOTP512.getPinAtTime(testTime[i]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -216,6 +217,18 @@ public class OTPTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNextPin() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
String secret = "s3ydtxo35tz3n3ob5dehlh76ciokhmsbbae5zusz4vm3k6wxmt6lsfvt";
|
||||||
|
HOTP testOTP1 = (HOTP) OTP.createNewOTP(OTPType.HOTP, secret, OTPAlgorithm.SHA1, 12, 0, 0, true);
|
||||||
|
TOTP testOTP2 = (TOTP) OTP.createNewOTP(OTPType.TOTP, secret, OTPAlgorithm.SHA1, 12, 0, 60, true);
|
||||||
|
|
||||||
|
assertEquals(testOTP1.getNextPin(), testOTP1.getPinAtCounter(testOTP1.getCounter() + 1));
|
||||||
|
assertEquals(testOTP2.getNextPin(), testOTP2.getPinAtTime(System.currentTimeMillis() / 1000 + testOTP2.getPeriod()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// @org.junit.jupiter.api.Test
|
// @org.junit.jupiter.api.Test
|
||||||
// public void test() {
|
// public void test() {
|
||||||
// hotpTest();
|
// hotpTest();
|
||||||
|
@ -31,16 +31,9 @@
|
|||||||
|
|
||||||
package test;
|
package test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.security.InvalidKeyException;
|
||||||
import java.io.File;
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.lang.reflect.UndeclaredThrowableException;
|
|
||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
|
|
||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package test;
|
package test;
|
||||||
|
|
||||||
import java.lang.reflect.UndeclaredThrowableException;
|
import java.lang.reflect.UndeclaredThrowableException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
public class ogTOTPmod1 {
|
public class ogTOTPmod1 {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user