package net.unicon.cas.addons.authentication.strong.oath.totp;
import org.apache.commons.codec.binary.Base32;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Random;
/**
* Copied from @{link https://github.com/parkghost/TOTP-authentication-demo}
*
* <strong>NOTE: </strong> in order to use this class in CAS maven war overlays, exclude the following jar in the
* maven-war-plugin->configuration->overlays->excludes section of local maven overlay pom.xml: WEB-INF/lib/commons-codec-1.4.jar
*
* @since 0.5
*/
public class TOTPUtils {
private static final int SECRET_SIZE = 10;
private static final int PASS_CODE_LENGTH = 6;
private static final String CRYPTO = "HmacSHA1";
private static final Random rand = new Random();
public static String generateSecret() {
// Allocating the buffer
byte[] buffer = new byte[SECRET_SIZE];
// Filling the buffer with random numbers.
rand.nextBytes(buffer);
// Getting the key and converting it to Base32
Base32 codec = new Base32();
byte[] secretKey = Arrays.copyOf(buffer, SECRET_SIZE);
byte[] encodedKey = codec.encode(secretKey);
return new String(encodedKey);
}
public static boolean checkCode(String secret, long code, int interval, int window) throws NoSuchAlgorithmException, InvalidKeyException {
Base32 codec = new Base32();
byte[] decodedKey = codec.decode(secret);
// Window is used to check codes generated in the near past.
// You can use this value to tune how far you're willing to go.
//int window = WINDOW;
long currentInterval = getCurrentInterval(interval);
for (int i = -window; i <= window; ++i) {
long hash = TOTP.generateTOTP(decodedKey, currentInterval + i, PASS_CODE_LENGTH, CRYPTO);
if (hash == code) {
return true;
}
}
// The validation code is invalid.
return false;
}
private static long getCurrentInterval(int interval) {
long currentTimeSeconds = System.currentTimeMillis() / 1000;
return currentTimeSeconds / interval;
}
}