From 0e1ae317e364bcfe24654816b41ad889e8e75f3f Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 18 Jun 2017 19:40:30 -0400 Subject: [PATCH] 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 | 11 +++++++++ 1pass.lua | 62 +++++++++++++++++++++++++++++++++++++++++++++++++- CMakeLists.txt | 1 + otp.c | 19 ++-------------- otp.h | 9 ++++++++ 5 files changed, 84 insertions(+), 18 deletions(-) create mode 100644 otp.h diff --git a/1pass.c b/1pass.c index 02c69e7..c6b98ad 100644 --- a/1pass.c +++ b/1pass.c @@ -18,6 +18,7 @@ #include "md5.h" #include "sha256.h" #include "keyhook.h" +#include "otp.h" #include #include @@ -364,6 +365,15 @@ static int decryptBase64UsingKey(lua_State *L) } // 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 @@ static int initLua(const int argc, char **argv) // 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"); diff --git a/1pass.lua b/1pass.lua index 3d91ddb..9b794a1 100644 --- a/1pass.lua +++ b/1pass.lua @@ -140,7 +140,7 @@ local function setMenuItemChecked(menuitem, ischecked) 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 function build_secret_menuitem(menu, type, str, hidden) 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 @@ local function build_secret_menuitem(menu, type, str, hidden) 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 function build_secret_menuitem_webform(menu, info, secure) 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 @@ local function build_secret_menuitem_webform(menu, info, secure) 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 @@ local function build_secret_menuitem_webform(menu, info, secure) 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 diff --git a/CMakeLists.txt b/CMakeLists.txt index e2925bc..5d5916f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,7 @@ add_executable(1pass sha1.c sha256.c base64.c + otp.c lua/lapi.c lua/ldebug.c lua/ldo.c diff --git a/otp.c b/otp.c index 1ca3e38..828680d 100644 --- a/otp.c +++ b/otp.c @@ -3,6 +3,7 @@ #include #include #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 @@ static int base32_decode(const char *src, const int srclen, uint8_t *dst, const 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 @@ static int totp(const char *base32_secret, char *dst, int dstlen) 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 ... */ diff --git a/otp.h b/otp.h new file mode 100644 index 0000000..2827f57 --- /dev/null +++ b/otp.h @@ -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 ... */ +