X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=src%2Forg%2Ffedorahosted%2Ffreeotp%2FToken.java;fp=src%2Forg%2Ffedorahosted%2Ffreeotp%2FToken.java;h=f087297a8971dc17a9ce3fc202bb666e219a3c9b;hb=7e05ee11ff86b939a2c409802151358d777f4417;hp=35a9576a1539fc1c88d8caa081b4e73bcba04d93;hpb=f4c90af2ef6b21527ba2bb302e4b2d9e58cf795a;p=~andy%2Ffreeotp diff --git a/src/org/fedorahosted/freeotp/Token.java b/src/org/fedorahosted/freeotp/Token.java index 35a9576..f087297 100644 --- a/src/org/fedorahosted/freeotp/Token.java +++ b/src/org/fedorahosted/freeotp/Token.java @@ -42,24 +42,25 @@ public class Token { HOTP, TOTP } - private final String issuerInt; - private final String issuerExt; - private final String label; - private TokenType type; - private String algo; - private byte[] key; - private int digits; - private long counter; - private int period; + private final String mIssuerInt; + private final String mIssuerExt; + private final String mLabel; + private TokenType mType; + private String mAlgorithm; + private byte[] mSecret; + private int mDigits; + private long mCounter; + private int mPeriod; + private long mLastCode; private Token(Uri uri) throws TokenUriInvalidException { if (!uri.getScheme().equals("otpauth")) throw new TokenUriInvalidException(); if (uri.getAuthority().equals("totp")) - type = TokenType.TOTP; + mType = TokenType.TOTP; else if (uri.getAuthority().equals("hotp")) - type = TokenType.HOTP; + mType = TokenType.HOTP; else throw new TokenUriInvalidException(); @@ -74,16 +75,16 @@ public class Token { throw new TokenUriInvalidException(); int i = path.indexOf(':'); - issuerExt = i < 0 ? "" : path.substring(0, i); - issuerInt = uri.getQueryParameter("issuer"); - label = path.substring(i >= 0 ? i + 1 : 0); - - algo = uri.getQueryParameter("algorithm"); - if (algo == null) - algo = "sha1"; - algo = algo.toUpperCase(Locale.US); + mIssuerExt = i < 0 ? "" : path.substring(0, i); + mIssuerInt = uri.getQueryParameter("issuer"); + mLabel = path.substring(i >= 0 ? i + 1 : 0); + + mAlgorithm = uri.getQueryParameter("algorithm"); + if (mAlgorithm == null) + mAlgorithm = "sha1"; + mAlgorithm = mAlgorithm.toUpperCase(Locale.US); try { - Mac.getInstance("Hmac" + algo); + Mac.getInstance("Hmac" + mAlgorithm); } catch (NoSuchAlgorithmException e1) { throw new TokenUriInvalidException(); } @@ -92,20 +93,20 @@ public class Token { String d = uri.getQueryParameter("digits"); if (d == null) d = "6"; - digits = Integer.parseInt(d); - if (digits != 6 && digits != 8) + mDigits = Integer.parseInt(d); + if (mDigits != 6 && mDigits != 8) throw new TokenUriInvalidException(); } catch (NumberFormatException e) { throw new TokenUriInvalidException(); } - switch (type) { + switch (mType) { case HOTP: try { String c = uri.getQueryParameter("counter"); if (c == null) c = "0"; - counter = Long.parseLong(c); + mCounter = Long.parseLong(c) - 1; } catch (NumberFormatException e) { throw new TokenUriInvalidException(); } @@ -115,7 +116,7 @@ public class Token { String p = uri.getQueryParameter("period"); if (p == null) p = "30"; - period = Integer.parseInt(p); + mPeriod = Integer.parseInt(p); } catch (NumberFormatException e) { throw new TokenUriInvalidException(); } @@ -124,7 +125,7 @@ public class Token { try { String s = uri.getQueryParameter("secret"); - key = Base32String.decode(s); + mSecret = Base32String.decode(s); } catch (DecodingException e) { throw new TokenUriInvalidException(); } @@ -137,13 +138,13 @@ public class Token { // Create digits divisor int div = 1; - for (int i = digits; i > 0; i--) + for (int i = mDigits; i > 0; i--) div *= 10; // Create the HMAC try { - Mac mac = Mac.getInstance("Hmac" + algo); - mac.init(new SecretKeySpec(key, "Hmac" + algo)); + Mac mac = Mac.getInstance("Hmac" + mAlgorithm); + mac.init(new SecretKeySpec(mSecret, "Hmac" + mAlgorithm)); // Do the hashing byte[] digest = mac.doFinal(bb.array()); @@ -159,7 +160,7 @@ public class Token { // Zero pad String hotp = Integer.toString(binary); - while (hotp.length() != digits) + while (hotp.length() != mDigits) hotp = "0" + hotp; return hotp; @@ -176,86 +177,88 @@ public class Token { this(Uri.parse(uri)); } + public void increment() { + if (mType == TokenType.HOTP) { + mCounter++; + mLastCode = System.currentTimeMillis(); + } + } + public String getID() { String id; - if (issuerInt != null && !issuerInt.equals("")) - id = issuerInt + ":" + label; - else if (issuerExt != null && !issuerExt.equals("")) - id = issuerExt + ":" + label; + if (mIssuerInt != null && !mIssuerInt.equals("")) + id = mIssuerInt + ":" + mLabel; + else if (mIssuerExt != null && !mIssuerExt.equals("")) + id = mIssuerExt + ":" + mLabel; else - id = label; + id = mLabel; return id; } public String getIssuer() { - return issuerExt != null ? issuerExt : ""; + return mIssuerExt != null ? mIssuerExt : ""; } public String getLabel() { - return label != null ? label : ""; + return mLabel != null ? mLabel : ""; } public String getCode() { - switch (type) { - case HOTP: - return getHOTP(counter); - case TOTP: - return getHOTP(System.currentTimeMillis() / 1000 / period); + if (mType == TokenType.TOTP) + return getHOTP(System.currentTimeMillis() / 1000 / mPeriod); + + long time = System.currentTimeMillis(); + if (time - mLastCode > 60000) { + StringBuilder sb = new StringBuilder(mDigits); + for (int i = 0; i < mDigits; i++) + sb.append('-'); + return sb.toString(); } - return null; + return getHOTP(mCounter); } - public String getPlaceholder() { - StringBuilder sb = new StringBuilder(digits); - for (int i = 0; i < digits; i++) - sb.append('-'); - return sb.toString(); + public TokenType getType() { + return mType; } - public void increment() { - if (type == TokenType.HOTP) - counter++; + // Progress is on a scale from 0 - 1000. + public int getProgress() { + long time = System.currentTimeMillis(); + + if (mType == TokenType.TOTP) + return (int) (time % (mPeriod * 1000) / mPeriod); + + long state = (time - mLastCode) / 60; + return (int) (state > 1000 ? 1000 : state); } public Uri toUri() { - String issuerLabel = !issuerExt.equals("") ? issuerExt + ":" + label : label; + String issuerLabel = !mIssuerExt.equals("") ? mIssuerExt + ":" + mLabel : mLabel; Uri.Builder builder = new Uri.Builder() .scheme("otpauth") .path(issuerLabel) - .appendQueryParameter("secret", Base32String.encode(key)) - .appendQueryParameter("issuer", issuerInt == null ? issuerExt : issuerInt) - .appendQueryParameter("algorithm", algo) - .appendQueryParameter("digits", Integer.toString(digits)); + .appendQueryParameter("secret", Base32String.encode(mSecret)) + .appendQueryParameter("issuer", mIssuerInt == null ? mIssuerExt : mIssuerInt) + .appendQueryParameter("algorithm", mAlgorithm) + .appendQueryParameter("digits", Integer.toString(mDigits)); - switch (type) { + switch (mType) { case HOTP: builder.authority("hotp"); - builder.appendQueryParameter("counter", Long.toString(counter)); + builder.appendQueryParameter("counter", Long.toString(mCounter + 1)); break; case TOTP: builder.authority("totp"); - builder.appendQueryParameter("period", Integer.toString(period)); + builder.appendQueryParameter("period", Integer.toString(mPeriod)); break; } return builder.build(); } - public TokenType getType() { - return type; - } - - // Progress is on a scale from 0 - 1000. - public int getProgress() { - int p = period * 10; - - long time = System.currentTimeMillis() / 100; - return (int) ((time % p) * 1000 / p); - } - @Override public String toString() { return toUri().toString();