Wed, 16 Feb 2011 20:29:33 +0000
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; |