Added One Time Password support.
authorRyan C. Gordon <icculus@icculus.org>
Sun, 18 Jun 2017 19:40:30 -0400
changeset 56 a573346e6f7b
parent 55 0aaf56a96d21
child 57 4974e5368a29
Added One Time Password support.

This is only for time-based OTP for now ("TOPT" algorithm), but that's more
or less what one expects to see in the wild anyhow.

This is sort of a placeholder UI until I replace the entire existing UI with
something better.
1pass.c
1pass.lua
CMakeLists.txt
otp.c
otp.h
--- a/1pass.c	Sun Jun 18 01:57:23 2017 -0400
+++ b/1pass.c	Sun Jun 18 19:40:30 2017 -0400
@@ -18,6 +18,7 @@
 #include "md5.h"
 #include "sha256.h"
 #include "keyhook.h"
+#include "otp.h"
 
 #include <gtk/gtk.h>
 #include <gdk/gdk.h>
@@ -364,6 +365,15 @@
 } // decryptBase64UsingKey
 
 
+static int decryptTopt(lua_State *L)
+{
+    const char *base32_secret = luaL_checkstring(L, 1);
+    char otpstr[16];
+    const int rc = totp(base32_secret, otpstr, sizeof (otpstr));
+    return retvalString(L, (rc == -1) ? NULL : otpstr);
+} // decryptTopt
+
+
 static void calcSha256(const BYTE *buf, const size_t len, BYTE *hash)
 {
     SHA256_CTX sha256;
@@ -766,6 +776,7 @@
     // Set up initial C functions, etc we want to expose to Lua code...
     luaSetCFunc(luaState, decryptUsingPBKDF2, "decryptUsingPBKDF2");
     luaSetCFunc(luaState, decryptBase64UsingKey, "decryptBase64UsingKey");
+    luaSetCFunc(luaState, decryptTopt, "decryptTopt");
     luaSetCFunc(luaState, giveControlToGui, "giveControlToGui");
     luaSetCFunc(luaState, runGuiPasswordPrompt, "runGuiPasswordPrompt");
     luaSetCFunc(luaState, copyToClipboard, "copyToClipboard");
--- a/1pass.lua	Sun Jun 18 01:57:23 2017 -0400
+++ b/1pass.lua	Sun Jun 18 19:40:30 2017 -0400
@@ -140,7 +140,7 @@
 end
 
 
-local function build_secret_menuitem(menu, type, str, hidden)
+local function build_secret_menuitem(menu, type, str, hidden, transform)
     if str == nil then
         return nil
     end
@@ -152,6 +152,9 @@
     local text = type .. " " .. valuestr
 
     local callback = function()
+        if transform ~= nil then
+            str = transform(str)
+        end
         copyToClipboard(str)
         --print("Copied data [" .. str .. "] to clipboard.")
         guiDestroyMenu(keyhookGuiMenus[1])
@@ -159,6 +162,47 @@
     return appendMenuItem(menu, text, callback)
 end
 
+local function transform_otp(str)
+    local algorithm, name, argstr = string.match(str, "^otpauth://(.-)/(.-)?(.+)$")
+    if algorithm == nil then algorithm = "" end
+    if algorithm ~= "totp" then
+        print("FIXME: don't know how to handle One Time Passwords using the '" .. algorithm .. "' algorithm!")
+        return "000000"
+    end
+
+    local args = {}
+    while argstr ~= nil and argstr ~= "" do
+        local arg
+        local idx = string.find(argstr, "&")
+        if idx == nil then
+            arg = argstr
+            argstr = nil
+        else
+            arg = string.sub(argstr, 0, idx);
+            argstr = string.sub(argstr, idx + 1);
+        end
+
+        local key, val = string.match(arg, "^(.-)=(.*)$")
+        if (key ~= nil) and (val ~= nil) then
+            args[key] = val
+        end
+    end
+
+    --dumptable("otpauth://" .. algorithm .. "/" .. name, args);
+
+    if args["secret"] == nil then
+        print("FIXME: this One Time Password doesn't seem to have a secret key!")
+        return "000000"
+    end
+
+    local retval = decryptTopt(args["secret"]);
+    if retval == nil then
+        print("FIXME: failed to generate One Time Password; is the secret key bogus?")
+        retval = "000000"
+    end
+    return retval
+end
+
 
 local secret_menuitem_builders = {}
 
@@ -166,6 +210,7 @@
     local addthis = false
     local username = nil
     local password = nil
+    local otp = nil
     local designated_password = nil
     local designated_username = nil
     local email = nil
@@ -199,6 +244,20 @@
         end
     end
 
+    -- this is probably all wrong.
+    if secure.sections ~= nil then
+        for i,v in ipairs(secure.sections) do
+            if v.fields ~= nil then
+                for i2,v2 in ipairs(v.fields) do
+                    if (type(v2.v) == "string") and (string.sub(v2.v, 0, 10) == "otpauth://") then
+                        otp = v2.v
+                        addthis = true
+                    end
+                end
+            end
+        end
+    end
+
     if addthis then
         -- designated fields always win out.
         if (designated_username ~= nil) then
@@ -216,6 +275,7 @@
         build_secret_menuitem(menu, "username", username)
         build_secret_menuitem(menu, "email", email)
         build_secret_menuitem(menu, "password", password, true)
+        build_secret_menuitem(menu, "otp", otp, true, transform_otp)
     end
 end
 secret_menuitem_builders["webforms.WebForm"] = build_secret_menuitem_webform
--- a/CMakeLists.txt	Sun Jun 18 01:57:23 2017 -0400
+++ b/CMakeLists.txt	Sun Jun 18 19:40:30 2017 -0400
@@ -82,6 +82,7 @@
     sha1.c
     sha256.c
     base64.c
+    otp.c
     lua/lapi.c
     lua/ldebug.c
     lua/ldo.c
--- a/otp.c	Sun Jun 18 01:57:23 2017 -0400
+++ b/otp.c	Sun Jun 18 19:40:30 2017 -0400
@@ -3,6 +3,7 @@
 #include <string.h>
 #include <time.h>
 #include "sha1.h"
+#include "otp.h"
 
 static int base32_decode(const char *src, const int srclen, uint8_t *dst, const int dstlen)
 {
@@ -56,7 +57,7 @@
     return retval;
 }
 
-static int totp(const char *base32_secret, char *dst, int dstlen)
+int totp(const char *base32_secret, char *dst, int dstlen)
 {
     uint8_t decoded[64];
     int decodedlen;
@@ -88,21 +89,5 @@
     return 0;
 }
 
-int main(int argc, char **argv)
-{
-    char result[16];
-    int i;
-    for (i = 1; i < argc; i++) {
-        printf("%s: ", argv[i]);
-        if (totp(argv[i], result, sizeof (result)) == -1) {
-            printf("[FAILED!]");
-        } else {
-            printf("%s (valid for %d more seconds)", result, 30 - ((int) (time(NULL) % 30)));
-        }
-        printf("\n");
-    }
-    return 0;
-}
-
 /* end of otp.c ... */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/otp.h	Sun Jun 18 19:40:30 2017 -0400
@@ -0,0 +1,9 @@
+#ifndef _OTP_H_
+#define _OTP_H_
+
+int totp(const char *base32_secret, char *dst, int dstlen);
+
+#endif
+
+/* end of otp.h ... */
+