yubikey/init.lua

Wed, 16 Feb 2011 20:29:33 +0000

author
Matthew Wild <mwild1@gmail.com>
date
Wed, 16 Feb 2011 20:29:33 +0000
changeset 0
598d09faf89c
permissions
-rw-r--r--

There are no secrets better kept than the secrets that everybody guesses.

0
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1 local _M = {};
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
2
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
3 local aeslua = require "aeslua";
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
4 local ciphermode = require "aeslua.ciphermode";
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
5 local crc16 = require "crc16";
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
6
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
7 local modhex2hex;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
8 do
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
9 local modhex_map = {};
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
10 local modhex_chars = "cbdefghijklnrtuv";
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
11 for i=1,16 do
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
12 modhex_map[modhex_chars:sub(i,i)] = ("%x"):format(i-1);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
13 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
14 function modhex2hex(modhex)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
15 if modhex then
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
16 return (modhex:gsub(".", modhex_map));
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
17 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
18 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
19 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
20 _M.modhex2hex = modhex2hex;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
21
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
22 local function hex2bin(hex)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
23 if hex then
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
24 return (hex:gsub("..", function (c) return string.char(tonumber(c, 16)); end));
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
25 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
26 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
27 _M.hex2bin = hex2bin;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
28
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
29 local function bin2hex(bin)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
30 if bin then
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
31 return (bin:gsub(".", function (b) return ("%02x"):format(b:byte()); end));
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
32 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
33 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
34 _M.bin2hex = bin2hex;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
35
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
36 local otp_parser = {};
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
37 local otp_parser_mt = { __index = otp_parser };
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
38
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
39 function _M.new_fetch_key_hex(fetchkeyhex)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
40 return function (...) return hex2bin(fetchkeyhex(...)); end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
41 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
42
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
43 function _M.new_otp_parser(config)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
44 return setmetatable({
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
45 config = config,
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
46 }, otp_parser_mt);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
47 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
48
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
49 function otp_parser:parse(otp, key)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
50 -- Password is any extra data before the real OTP
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
51 local password;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
52 if #otp > 32 + self.config.prefix_length then
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
53 password = otp:sub(1, #otp - (32 + self.config.prefix_length));
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
54 otp = otp:sub(#password+1);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
55 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
56 local prefix = otp:sub(1, self.config.prefix_length);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
57 local token = otp:sub(#prefix+1);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
58 if not key then
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
59 key = self.config.fetch_key(prefix);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
60 else
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
61 key = hex2bin(key);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
62 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
63 if not key then return false, "no-key"; end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
64 key = {key:byte(1,#key)}
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
65 local decrypted = ciphermode.decryptString(key, hex2bin(modhex2hex(token)), ciphermode.decryptCBC);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
66 if not decrypted then return false, "decrypt-failed"; end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
67 -- Extract private UID
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
68 local uid = decrypted:sub(1,6);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
69 -- Build insertion counter (2 bytes)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
70 local use1, use2 = decrypted:sub(7,8):byte(1,2);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
71 local use_ctr = use1 + math.pow(2, 8)*use2;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
72 -- Build timestamp (3 bytes)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
73 local time1, time2, time3 = decrypted:sub(9,11):byte(1,3);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
74 local timestamp = time1 + math.pow(2,8)*time2 + math.pow(2, 16)*time3;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
75 -- Extract session counter (1 byte)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
76 local session_ctr = decrypted:sub(12, 12):byte();
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
77
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
78 if crc16.hash(decrypted) ~= 0xf0b8 then
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
79 return false, "invalid-checksum";
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
80 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
81
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
82 -- Return parsed fields
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
83 return true, {
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
84 password = password;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
85 public_id = prefix;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
86 token = token;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
87 private_id = bin2hex(uid);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
88 session_counter = session_ctr;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
89 use_counter = use_ctr;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
90 timestamp = timestamp;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
91 };
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
92 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
93
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
94 function _M.new_authenticator(config)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
95 local parser = _M.new_otp_parser(config);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
96 local function authenticate(self, otp, key, device_info, userdata)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
97 -- Parse OTP, get device data (from config callback)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
98 local ok, ret = parser:parse(otp, key);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
99 if not ok then return ok, ret; end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
100
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
101 if not device_info then
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
102 device_info = config.fetch_device_info(ret);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
103 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
104
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
105 if ret.use_counter < (device_info.use_counter or 0)
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
106 or ((ret.use_counter == (device_info.use_counter or 0))
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
107 and (ret.session_counter <= (device_info.session_counter or 0))) then
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
108 return false, "otp-already-used";
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
109 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
110
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
111 local authed, err = config.check_credentials(ret, device_info, userdata);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
112 if not authed then return authed, err; end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
113
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
114 device_info.use_counter = ret.use_counter;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
115 device_info.session_counter = ret.session_counter;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
116
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
117 config.store_device_info(device_info, userdata);
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
118
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
119 return true, ret;
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
120 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
121 return { authenticate = authenticate };
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
122 end
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
123
598d09faf89c There are no secrets better kept than the secrets that everybody guesses.
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
124 return _M;

mercurial