Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbcryptlua.lua
More file actions
Latest commit
74 lines (66 loc) · 2.57 KB
/
Copy pathbcryptlua.lua
File metadata and controls
74 lines (66 loc) · 2.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
--- bcrypt password hashing, powered by Rust.
---
--- Hashes are standard `$2b$` modular-crypt strings, 60 characters,
--- interchangeable with every other bcrypt implementation. `verify`
--- also accepts `$2a$`, `$2x$` and `$2y$` hashes (PHP, passlib, older
--- libraries), so existing password databases keep working.
localcore=require("bcryptlua_core")
localbcrypt= {}
localDEFAULT_COST=12
localMIN_COST, MAX_COST=4, 31
-- bcrypt only feeds the first 72 bytes of the password into the hash.
-- Truncating silently would make long passwords sharing a 72-byte
-- prefix collide, so oversized input is an error the caller must
-- handle (validate the length up front, or hash a digest instead).
localMAX_PASSWORD_BYTES=72
--- Hashes a password with a freshly generated random salt.
---@parampasswordstring up to 72 bytes
---@paramcost?integer log2 of the number of rounds, 4..31 (default 12)
---@returnstring hash 60-character `$2b$` hash
functionbcrypt.hash(password, cost)
iftype(password) ~="string" then
error("Password must be a string", 2)
end
if#password>MAX_PASSWORD_BYTESthen
error(("Password exceeds bcrypt's 72-byte limit (%d bytes)"):format(#password), 2)
end
ifcost==nilthen
cost=DEFAULT_COST
elseiftype(cost) ~="number" orcost%1~=0then
error("Cost must be an integer", 2)
elseifcost<MIN_COSTorcost>MAX_COSTthen
error(("Cost must be between %d and %d, got %d"):format(MIN_COST, MAX_COST, cost), 2)
end
returncore.hash(password, cost)
end
--- Checks a password against a stored hash. Constant-time comparison.
--- A malformed hash returns `false`, indistinguishable from a wrong
--- password on purpose.
---@parampasswordstring
---@paramhashstring
---@returnboolean
functionbcrypt.verify(password, hash)
iftype(password) ~="string" then
error("Password must be a string", 2)
end
iftype(hash) ~="string" then
error("Hash must be a string", 2)
end
returncore.verify(password, hash)
end
--- Extracts the cost from a stored hash — the rehash-on-login check:
--- `if bcrypt.cost(stored) < 12 then rehash() end`.
---@paramhashstring
---@returninteger|nil cost
---@returnstring?err "Malformed bcrypt hash" when it cannot be parsed
functionbcrypt.cost(hash)
iftype(hash) ~="string" then
error("Hash must be a string", 2)
end
localcost=hash:match("^%$2[abxy]%$(%d%d)%$[./A-Za-z0-9]+$")
ifnotcostor#hash~=60then
returnnil, "Malformed bcrypt hash"
end
returntonumber(cost)
end
returnbcrypt