package open.dolphin.adm20; import java.nio.ByteBuffer; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.logging.Level; import java.util.logging.Logger; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base32; /** * * @author kazushi Minagawa */ public class OTPHelper { public long getOTP() { try { String secret = getSecret(); byte[] secretBytes = new Base32().decode(secret); return getCode(secretBytes, getTimeIndex()); } catch (NoSuchAlgorithmException | InvalidKeyException ex) { Logger.getLogger(OTPHelper.class.getName()).log(Level.SEVERE, null, ex); } return 0L; } //-------------------------------------------------------------------------- // Google Authenticator thus enabled // https://weblogs.java.net/blog/evanx/archive/2012/11/07/google-authenticator-thus-enabled // Evan Summers //-------------------------------------------------------------------------- private long getTimeIndex() { return System.currentTimeMillis()/1000/30; } private String getSecret() { byte[] buffer = new byte[10]; new SecureRandom().nextBytes(buffer); String secret = new String(new Base32().encode(buffer)); return secret; } private long getCode(byte[] secret, long timeIndex) throws NoSuchAlgorithmException, InvalidKeyException { SecretKeySpec signKey = new SecretKeySpec(secret, "HmacSHA1"); ByteBuffer buffer = ByteBuffer.allocate(8); buffer.putLong(timeIndex); byte[] timeBytes = buffer.array(); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(signKey); byte[] hash = mac.doFinal(timeBytes); int offset = hash[19] & 0xf; long truncatedHash = hash[offset] & 0x7f; for (int i = 1; i < 4; i++) { truncatedHash <<= 8; truncatedHash |= hash[offset + i] & 0xff; } return (truncatedHash %= 1000000); } public boolean verifyCode(String secret, int code, long timeIndex, int variance) throws Exception { byte[] secretBytes = new Base32().decode(secret); for (int i = -variance; i <= variance; i++) { if (getCode(secretBytes, timeIndex + i) == code) { return true; } } return false; } public String getBackupKey() { String secret = getSecret(); StringBuilder sb = new StringBuilder(); sb.append(secret.substring(0, 4)).append("-"); sb.append(secret.substring(4, 8)).append("-"); sb.append(secret.substring(8, 12)).append("-"); sb.append(secret.substring(12, 16)); return sb.toString(); } }