aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/com/zeapo/pwdstore/utils/Totp.java
diff options
context:
space:
mode:
authorWiktor Kwapisiewicz <wiktor@metacode.biz>2017-11-06 12:41:00 +0100
committerMohamed Zenadi <zeapo@users.noreply.github.com>2017-11-19 11:14:45 +0100
commit3d5dd65e306ba3ca560b3c221830ee4cdb4363fb (patch)
tree6a417353098a9dc22093568c7e6c1dd505997512 /app/src/main/java/com/zeapo/pwdstore/utils/Totp.java
parent67a7b124eec9178f8539664bf4d2528a111465b2 (diff)
downloadHardenedPass-3d5dd65e306ba3ca560b3c221830ee4cdb4363fb.tar.gz
HardenedPass-3d5dd65e306ba3ca560b3c221830ee4cdb4363fb.zip
Display TOTP code if entry contains OTP secret
TOTP is calculated on display and on copy to clipboard from secret embedded in entry (either in password or in extra) and the current time.
Diffstat (limited to 'app/src/main/java/com/zeapo/pwdstore/utils/Totp.java')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/Totp.java50
1 files changed, 50 insertions, 0 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/Totp.java b/app/src/main/java/com/zeapo/pwdstore/utils/Totp.java
new file mode 100644
index 00000000..5e4326e2
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/Totp.java
@@ -0,0 +1,50 @@
+package com.zeapo.pwdstore.utils;
+
+import android.util.Log;
+
+import org.apache.commons.codec.binary.Base32;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+public class Totp {
+
+ private static final String ALGORITHM = "HmacSHA1";
+ private static final int TIME_WINDOW = 30;
+ private static final int CODE_DIGITS = 6;
+
+ private static final Base32 BASE_32 = new Base32();
+
+ private Totp() {
+ }
+
+ public static String calculateCode(String secret, long epochSeconds) {
+ SecretKeySpec signingKey = new SecretKeySpec(BASE_32.decode(secret), ALGORITHM);
+
+ Mac mac = null;
+ try {
+ mac = Mac.getInstance(ALGORITHM);
+ mac.init(signingKey);
+ } catch (NoSuchAlgorithmException e) {
+ Log.e("TOTP", ALGORITHM + " unavailable - should never happen", e);
+ return null;
+ } catch (InvalidKeyException e) {
+ Log.e("TOTP", "Key is malformed", e);
+ return null;
+ }
+
+ long time = epochSeconds / TIME_WINDOW;
+ byte[] digest = mac.doFinal(ByteBuffer.allocate(8).putLong(time).array());
+ int offset = digest[digest.length - 1] & 0xf;
+ byte[] code = Arrays.copyOfRange(digest, offset, offset + 4);
+ code[0] = (byte) (0x7f & code[0]);
+ String strCode = new BigInteger(code).toString();
+ return strCode.substring(strCode.length() - CODE_DIGITS);
+ }
+}