util.hmac: Some optimisations
[prosody.git] / util / hmac.lua
1 local hashes = require "util.hashes"
2 local xor = require "bit".bxor
3
4 local t_insert, t_concat = table.insert, table.concat;
5 local s_char = string.char;
6
7 module "hmac"
8
9 local function arraystr(array)
10     local t = {}
11     for i = 1,#array do
12         t_insert(t, s_char(array[i]))
13     end
14
15     return t_concat(t)
16 end
17
18 --[[
19 key
20     the key to use in the hash
21 message
22     the message to hash
23 hash
24     the hash function
25 blocksize
26     the blocksize for the hash function in bytes
27 hex
28   return raw hash or hexadecimal string
29 --]]
30 function hmac(key, message, hash, blocksize, hex)
31     local opad = {}
32     local ipad = {}
33     
34     for i = 1,blocksize do
35         opad[i] = 0x5c
36         ipad[i] = 0x36
37     end
38
39     if #key > blocksize then
40         key = hash(key)
41     end
42
43     for i = 1,#key do
44         ipad[i] = xor(ipad[i],key:sub(i,i):byte())
45         opad[i] = xor(opad[i],key:sub(i,i):byte())
46     end
47
48     opad = arraystr(opad)
49     ipad = arraystr(ipad)
50
51     if hex then
52         return hash(opad..hash(ipad..message), true)
53     else
54         return hash(opad..hash(ipad..message))
55     end
56 end
57
58 function md5(key, message, hex)
59     return hmac(key, message, hashes.md5, 64, hex)
60 end
61
62 function sha1(key, message, hex)
63     return hmac(key, message, hashes.sha1, 64, hex)
64 end
65
66 function sha256(key, message, hex)
67     return hmac(key, message, hashes.sha256, 64, hex)
68 end
69
70 return _M