1 -- vim:set st=4 sw=4 sts=4 et:
2 local ffi = require "ffi"
5 local ffi_new = ffi.new
6 local ffi_str = ffi.string
7 local find = string.find
16 typedef enum Argon2_type {
22 const char *argon2_error_message(int error_code);
24 size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost,
25 uint32_t parallelism, uint32_t saltlen,
26 uint32_t hashlen, argon2_type type);
28 int argon2i_hash_encoded(const uint32_t t_cost,
29 const uint32_t m_cost,
30 const uint32_t parallelism,
31 const void *pwd, const size_t pwdlen,
32 const void *salt, const size_t saltlen,
33 const size_t hashlen, char *encoded,
34 const size_t encodedlen);
36 int argon2d_hash_encoded(const uint32_t t_cost,
37 const uint32_t m_cost,
38 const uint32_t parallelism,
39 const void *pwd, const size_t pwdlen,
40 const void *salt, const size_t saltlen,
41 const size_t hashlen, char *encoded,
42 const size_t encodedlen);
44 int argon2id_hash_encoded(const uint32_t t_cost,
45 const uint32_t m_cost,
46 const uint32_t parallelism,
47 const void *pwd, const size_t pwdlen,
48 const void *salt, const size_t saltlen,
49 const size_t hashlen, char *encoded,
50 const size_t encodedlen);
52 int argon2_verify(const char *encoded,
59 local lib = ffi.load "argon2"
63 local ARGON2_VERIFY_MISMATCH = -35
66 local argon2_i, argon2_d, argon2_id
70 local argon2_t = ffi.typeof(ffi.new "argon2_type")
72 argon2_i = ffi_new(argon2_t, "Argon2_i")
73 argon2_d = ffi_new(argon2_t, "Argon2_d")
74 argon2_id = ffi_new(argon2_t, "Argon2_id")
80 _AUTHOR = "Thibault Charbonnier",
82 _URL = "https://github.com/thibaultcha/lua-argon2-ffi",
86 argon2_id = argon2_id,
91 function _M.hash_encoded(pwd, salt, opts)
92 if type(pwd) ~= "string" then
93 return error("bad argument #1 to 'hash_encoded' (string expected, got "
94 .. type(pwd) .. ")", 2)
97 if type(salt) ~= "string" then
98 return error("bad argument #2 to 'hash_encoded' (string expected, got "
99 .. type(salt) .. ")", 2)
106 if type(opts) ~= "table" then
107 return error("bad argument #3 to 'hash_encoded' (expected to be a "
112 local t_cost = opts.t_cost or 3
113 local m_cost = opts.m_cost or 4096
114 local parallelism = opts.parallelism or 1
115 local hash_len = opts.hash_len or 32
116 local variant = opts.variant or argon2_i
118 if type(variant) ~= "cdata" then
119 return error("bad argument #3 to 'hash_encoded' (expected " ..
120 "variant to be an argon2_type, got " ..
121 type(opts.variant) .. ")", 2)
124 if type(t_cost) ~= "number" then
125 return error("bad argument #3 to 'hash_encoded' (expected " ..
126 "t_cost to be a number, got " ..
127 type(t_cost) .. ")", 2)
130 if type(m_cost) ~= "number" then
131 return error("bad argument #3 to 'hash_encoded' (expected " ..
132 "m_cost to be a number, got " ..
133 type(m_cost) .. ")", 2)
136 if type(parallelism) ~= "number" then
137 return error("bad argument #3 to 'hash_encoded' (expected " ..
138 "parallelism to be a number, got " ..
139 type(parallelism) .. ")", 2)
142 if type(hash_len) ~= "number" then
143 return error("bad argument #3 to 'hash_encoded' (expected " ..
144 "hash_len to be a number, got " ..
145 type(hash_len) .. ")", 2)
148 local buf_len = lib.argon2_encodedlen(t_cost, m_cost,
152 local buf = ffi_new("char[?]", buf_len)
155 if opts.variant == argon2_d then
156 ret_code = lib.argon2d_hash_encoded(t_cost, m_cost,
157 parallelism, pwd, #pwd, salt,
158 #salt, hash_len, buf, buf_len)
160 elseif opts.variant == argon2_id then
161 ret_code = lib.argon2id_hash_encoded(t_cost, m_cost,
162 parallelism, pwd, #pwd, salt,
163 #salt, hash_len, buf, buf_len)
166 ret_code = lib.argon2i_hash_encoded(t_cost, m_cost,
167 parallelism, pwd, #pwd, salt,
168 #salt, hash_len, buf, buf_len)
171 if ret_code ~= ARGON2_OK then
172 local c_msg = lib.argon2_error_message(ret_code)
173 return nil, ffi_str(c_msg)
180 function _M.verify(encoded, plain)
181 if type(encoded) ~= "string" then
182 return error("bad argument #1 to 'verify' (string expected, got "
183 .. type(encoded) .. ")", 2)
186 if type(plain) ~= "string" then
187 return error("bad argument #2 to 'verify' (string expected, got "
188 .. type(plain) .. ")", 2)
193 if find(encoded, "argon2d", nil, true) then
196 elseif find(encoded, "argon2id", nil, true) then
203 local ret_code = lib.argon2_verify(encoded, plain, #plain, variant)
205 if ret_code == ARGON2_VERIFY_MISMATCH then
209 if ret_code ~= ARGON2_OK then
210 local c_msg = lib.argon2_error_message(ret_code)
211 return nil, ffi_str(c_msg)