/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator; import org.bouncycastle.crypto.Digest; import org.cryptacular.spec.DigestSpec; import org.cryptacular.spec.Spec; /** * OTP generator component that implements the TOTP scheme described in <a href="https://tools.ietf.org/html/rfc6238"> * RFC 6238</a>. * * @author Middleware Services */ public class TOTPGenerator extends AbstractOTPGenerator { /** Digest algorithm specification. */ private Spec<Digest> digestSpecification = new DigestSpec("SHA1"); /** Reference start time, T0. Default 0, i.e. 1970-01-01T00:00:00. */ private int startTime; /** Time step in seconds, X. Default is 30 seconds. */ private int timeStep = 30; /** @return Digest algorithm used with the HMAC function. */ public Spec<Digest> getDigestSpecification() { return digestSpecification; } /** * Sets the digest algorithm used with the HMAC function. * * @param specification SHA-1, SHA-256, or SHA-512 digest specification. */ public void setDigestSpecification(final Spec<Digest> specification) { if ("SHA1".equalsIgnoreCase(specification.getAlgorithm()) || "SHA-1".equalsIgnoreCase(specification.getAlgorithm()) || "SHA256".equalsIgnoreCase(specification.getAlgorithm()) || "SHA-256".equalsIgnoreCase(specification.getAlgorithm()) || "SHA512".equalsIgnoreCase(specification.getAlgorithm()) || "SHA-512".equalsIgnoreCase(specification.getAlgorithm())) { this.digestSpecification = specification; return; } throw new IllegalArgumentException("Unsupported digest algorithm " + specification); } /** @return Reference start time. */ public int getStartTime() { return startTime; } /** * Sets the reference start time, T0. Default 0, i.e. 1970-01-01T00:00:00. * * @param seconds Start time in seconds. */ public void setStartTime(final int seconds) { this.startTime = seconds; } /** @return Time step in seconds. */ public int getTimeStep() { return timeStep; } /** * Sets the time step, X. * * @param seconds Time step in seconds. Default is 30. This value determines the validity window of generated OTP * values. */ public void setTimeStep(final int seconds) { this.timeStep = seconds; } /** * Generates the OTP given a per-user key. * * @param key Per-user key. * * @return Integer OTP. */ public int generate(final byte[] key) { final int unixTime = (int) (System.currentTimeMillis() / 1000); final int t = (unixTime - startTime) / timeStep; return generateInternal(key, t); } @Override protected Digest getDigest() { return digestSpecification.newInstance(); } }