diff --git a/stand/defaults/loader.conf.5 b/stand/defaults/loader.conf.5 --- a/stand/defaults/loader.conf.5 +++ b/stand/defaults/loader.conf.5 @@ -178,7 +178,15 @@ Protect boot menu with a password without interrupting .Ic autoboot process. -The password should be in clear text format. +The password may be in clear text format or the +lua-loader additionally supports +.Xr crypt 3 +format with algorithms 5 (SHA-256) or 6 (SHA-512). When using +.Xr crypt 3 +format passwords remember to escape any +.Dq Li \[Do] +with +.Dq Li \e . If a password is set, boot menu will not appear until any key is pressed during countdown period specified by .Va autoboot_delay @@ -190,7 +198,15 @@ .It Ar bootlock_password Provides a password to be required by check-password before execution is allowed to continue. -The password should be in clear text format. +The password may be in clear text format or the +lua-loader additionally supports +.Xr crypt 3 +format with algorithms 5 (SHA-256) or 6 (SHA-512). When using +.Xr crypt 3 +format passwords remember to escape any +.Dq Li \[Do] +with +.Dq Li \e . If a password is set, the user must provide specified password to boot. .It Ar verbose_loading If set to diff --git a/stand/lua/Makefile b/stand/lua/Makefile --- a/stand/lua/Makefile +++ b/stand/lua/Makefile @@ -17,7 +17,9 @@ color.lua \ config.lua \ core.lua \ + crypt.lua \ drawer.lua \ + hashes.lua \ hook.lua \ loader.lua \ gfx-beastie.lua \ diff --git a/stand/lua/crypt.lua b/stand/lua/crypt.lua new file mode 100644 --- /dev/null +++ b/stand/lua/crypt.lua @@ -0,0 +1,326 @@ +local hashes = require("hashes") + +local tcpser="$6$2pbcyRkgg8MvJ.K8$b7P4JodZgxezWBIE1xiUPY9a//9NOpTfGWqDLa1Wd37kcZrQN/s0hP/tI.dS2E/Etw7xETK5TmU9IS9lkModf1" + +local b64_alphabet = {'.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', + 'v', 'w', 'x', 'y', 'z'} + +local shaX_rounds_prefix = "rounds=" +local shaX_rounds_default = 5000 +local shaX_rounds_min = 1000 +local shaX_rounds_max = 999999999 +local shaX_salt_max = 16 + +local function b64_from_24bit(b2, b1, b0, n) + local w = ((b2 & 0xff) << 16) | ((b1 & 0xff) << 8) | (b0 & 0xff) + local s = "" + for i = 1, n do + s = s .. b64_alphabet[ (w & 0x3f) + 1] + w = w >> 6 + end + return s +end + +local function min(a, b) + if a < b then + return a + end + return b +end + +local function max(a, b) + if a > b then + return a + end + return b +end + +local crypt = {} + +function crypt.sha256(salthash, password) + local rounds = shaX_rounds_default + local custom_rounds=false + + if string.sub(salthash, 1, #shaX_rounds_prefix) == shaX_rounds_prefix then + local end_rounds = string.find(salthash, "%$") + if end_rounds ~= nil then + local new_rounds = tonumber(string.sub(salthash, #shaX_rounds_prefix + 1, end_rounds - 1)) + if new_rounds ~= nil then + rounds = max(shaX_rounds_min, min(new_rounds, shaX_rounds_max)); + custom_rounds=true + salthash = string.sub(salthash, end_rounds + 1) + end + end + end + local saltsplit = string.find(salthash, '%$') + if saltsplit == nil then + saltsplit = #salthash+1 + end + if saltsplit > (shaX_salt_max + 1) then + saltsplit = shaX_salt_max + 1 + end + local salt = string.sub(salthash, 1, saltsplit-1) + + local sha256 = hashes.sha256() + sha256(password) + sha256(salt) + + local sha256_alt = hashes.sha256() + sha256_alt(password) + sha256_alt(salt) + sha256_alt(password) + + local alt_result = sha256_alt() + -- for each character of the password, add alt_result (wrapping as needed) + for cnt = #password, 33, -32 do + sha256(alt_result) + end + sha256(string.sub(alt_result, 1, #password % 32)) + + local count = #password + while count > 0 do + if (count & 1) ~=0 then + sha256(alt_result) + else + sha256(password) + end + count = count >> 1 + end + + alt_result=sha256() + + -- P sequence + sha256 = hashes.sha256() + for cnt=1,#password do + sha256(password) + end + local temp_result = sha256() + local p_bytes = "" + + while #p_bytes ~= #password do + p_bytes = p_bytes .. string.sub(temp_result, 1, + min(#temp_result, #password-#p_bytes)) + end + + -- S sequence + sha256 = hashes.sha256() + for cnt=1, 16 + string.byte(alt_result, 1) do + sha256(salt) + end + temp_result = sha256() + + local s_bytes = "" + while #s_bytes ~= #salt do + s_bytes = s_bytes .. string.sub(temp_result, 1, + min(#temp_result, #salt - #s_bytes)) + end + + for cnt=0, rounds-1 do + sha256 = hashes.sha256() + if (cnt & 1) ~= 0 then + sha256(p_bytes) + else + sha256(alt_result) + end + if (cnt % 3) ~= 0 then + sha256(s_bytes) + end + if (cnt % 7) ~= 0 then + sha256(p_bytes) + end + if (cnt & 1) ~= 0 then + sha256(alt_result) + else + sha256(p_bytes) + end + alt_result = sha256() + end + local s = "$5$" + if custom_rounds then + s = s .. "rounds=" .. rounds .. "$" + end + + s = s .. salt .. "$" + s = s .. b64_from_24bit(string.byte(alt_result, 1), string.byte(alt_result, 11), string.byte(alt_result, 21), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 22), string.byte(alt_result, 2), string.byte(alt_result, 12), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 13), string.byte(alt_result, 23), string.byte(alt_result, 3), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 4), string.byte(alt_result, 14), string.byte(alt_result, 24), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 25), string.byte(alt_result, 5), string.byte(alt_result, 15), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 16), string.byte(alt_result, 26), string.byte(alt_result, 6), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 7), string.byte(alt_result, 17), string.byte(alt_result, 27), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 28), string.byte(alt_result, 8), string.byte(alt_result, 18), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 19), string.byte(alt_result, 29), string.byte(alt_result, 9), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 10), string.byte(alt_result, 20), string.byte(alt_result, 30), 4); + s = s .. b64_from_24bit(0, string.byte(alt_result, 32), string.byte(alt_result, 31), 3); + + return s +end + +function crypt.sha512(salthash, password) + local rounds = shaX_rounds_default + local custom_rounds=false + if string.sub(salthash, 1, #shaX_rounds_prefix) == shaX_rounds_prefix then + local end_rounds = string.find(salthash, "%$") + if end_rounds ~= nil then + local new_rounds = tonumber(string.sub(salthash, #shaX_rounds_prefix + 1, end_rounds - 1)) + if new_rounds ~= nil then + rounds = max(shaX_rounds_min, min(new_rounds, shaX_rounds_max)); + custom_rounds=true + salthash = string.sub(salthash, end_rounds + 1) + end + end + end + local saltsplit = string.find(salthash, '%$') + if saltsplit == nil then + saltsplit = #salthash+1 + end + if saltsplit > (shaX_salt_max + 1) then + saltsplit = shaX_salt_max + 1 + end + local salt = string.sub(salthash, 1, saltsplit-1) + local sha512 = hashes.sha512() + + sha512(password) + + sha512(salt) + + local alt_sha512 = hashes.sha512() + alt_sha512(password) + alt_sha512(salt) + alt_sha512(password) + local alt_result = alt_sha512() + -- for each character of the password add the alt_result (wrapping as needed) + for cnt = #password, 65, -64 do + sha512(alt_result) + end + sha512(string.sub(alt_result, 1, #password % 64)) + + local count = #password + while count > 0 do + if (count & 1) ~=0 then + sha512(alt_result) + else + sha512(password) + end + count = count >> 1 + end + + -- P sequence + alt_result=sha512() + sha512 = hashes.sha512() + for cnt=1,#password do + sha512(password) + end + local temp_result = sha512() + local p_bytes = "" + + while #p_bytes ~= #password do + p_bytes = p_bytes .. string.sub(temp_result, 1, + min(#temp_result, #password-#p_bytes)) + end + + -- S sequence + sha512 = hashes.sha512() + for cnt=1, 16 + string.byte(alt_result, 1) do + sha512(salt) + end + temp_result = sha512() + + local s_bytes = "" + while #s_bytes ~= #salt do + s_bytes = s_bytes .. string.sub(temp_result, 1, + min(#temp_result, #salt - #s_bytes)) + end + + for cnt=0, rounds-1 do + sha512 = hashes.sha512() + if (cnt & 1) ~= 0 then + sha512(p_bytes) + else + sha512(alt_result) + end + if (cnt % 3) ~= 0 then + sha512(s_bytes) + end + if (cnt % 7) ~= 0 then + sha512(p_bytes) + end + if (cnt & 1) ~= 0 then + sha512(alt_result) + else + sha512(p_bytes) + end + alt_result = sha512() + end + local s = "$6$" + if custom_rounds then + s = s .. "rounds=" .. rounds .. "$" + end + s = s .. salt .. "$" + s = s .. b64_from_24bit(string.byte(alt_result, 1), string.byte(alt_result, 22), string.byte(alt_result, 43), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 23), string.byte(alt_result, 44), string.byte(alt_result, 2), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 45), string.byte(alt_result, 3), string.byte(alt_result, 24), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 4), string.byte(alt_result, 25), string.byte(alt_result, 46), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 26), string.byte(alt_result, 47), string.byte(alt_result, 5), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 48), string.byte(alt_result, 6), string.byte(alt_result, 27), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 7), string.byte(alt_result, 28), string.byte(alt_result, 49), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 29), string.byte(alt_result, 50), string.byte(alt_result, 8), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 51), string.byte(alt_result, 9), string.byte(alt_result, 30), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 10), string.byte(alt_result, 31), string.byte(alt_result, 52), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 32), string.byte(alt_result, 53), string.byte(alt_result, 11), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 54), string.byte(alt_result, 12), string.byte(alt_result, 33), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 13), string.byte(alt_result, 34), string.byte(alt_result, 55), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 35), string.byte(alt_result, 56), string.byte(alt_result, 14), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 57), string.byte(alt_result, 15), string.byte(alt_result, 36), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 16), string.byte(alt_result, 37), string.byte(alt_result, 58), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 38), string.byte(alt_result, 59), string.byte(alt_result, 17), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 60), string.byte(alt_result, 18), string.byte(alt_result, 39), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 19), string.byte(alt_result, 40), string.byte(alt_result, 61), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 41), string.byte(alt_result, 62), string.byte(alt_result, 20), 4); + s = s .. b64_from_24bit(string.byte(alt_result, 63), string.byte(alt_result, 21), string.byte(alt_result, 42), 4); + s = s .. b64_from_24bit(0, 0, string.byte(alt_result, 64), 2); + + return s +end + +function crypt.compare(entered, stored) + algorithm = string.sub(stored, 1, 3) + salthash = string.sub(stored,4) + if algorithm == '$5$' then hashed = crypt.sha256(salthash, entered) + elseif algorithm == '$6$' then hashed = crypt.sha512(salthash, entered) + else return nil + end + if hashed ~= nil then + return hashed == stored + end + return nil +end + +--[[ +-- tests + +--sha512 -- copied from crypt-sha512.c +assert(crypt.sha512("saltstring", "Hello world!") == "$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJuesI68u4OTLiBFdcbYEdFCoEOfaS35inz1") +assert(crypt.sha512("rounds=10000$saltstringsaltstring", "Hello world!") == "$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sbHbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v.") +assert(crypt.sha512("rounds=5000$toolongsaltstring", "This is just a test") == "$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQzQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0") +assert(crypt.sha512("rounds=1400$anotherlongsaltstring", "a very much longer text to encrypt. This one even stretches over morethan one line.") == "$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wPvMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1") +assert(crypt.sha512("rounds=77777$short", "we have a short salt string but not a short password") == "$6$rounds=77777$short$WuQyW2YR.hBNpjjRhpYD/ifIw05xdfeEyQoMxIXbkvr0gge1a1x3yRULJ5CCaUeOxFmtlcGZelFl5CxtgfiAc0") +assert(crypt.sha512("rounds=123456$asaltof16chars..", "a short string") == "$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwcelCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1") +assert(crypt.sha512("rounds=10$roundstoolow", "the minimum number is still observed") == "$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1xhLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX.") + +-- sha256 -- copied from crypt-sha256.c +assert(crypt.sha256("saltstring", "Hello world!") == "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5") +assert(crypt.sha256("rounds=10000$saltstringsaltstring", "Hello world!") == "$5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2.opqey6IcA") +assert(crypt.sha256("rounds=5000$toolongsaltstring", "This is just a test") == "$5$rounds=5000$toolongsaltstrin$Un/5jzAHMgOGZ5.mWJpuVolil07guHPvOW8mGRcvxa5") +assert(crypt.sha256("rounds=1400$anotherlongsaltstring", "a very much longer text to encrypt. This one even stretches over morethan one line.") == "$5$rounds=1400$anotherlongsalts$Rx.j8H.h8HjEDGomFU8bDkXm3XIUnzyxf12oP84Bnq1") +assert(crypt.sha256("rounds=77777$short", "we have a short salt string but not a short password") == "$5$rounds=77777$short$JiO1O3ZpDAxGJeaDIuqCoEFysAe1mZNJRs3pw0KQRd/") +assert(crypt.sha256("rounds=123456$asaltof16chars..", "a short string") == "$5$rounds=123456$asaltof16chars..$gP3VQ/6X7UUEW3HkBn2w1/Ptq2jxPyzV/cZKmF/wJvD") +assert(crypt.sha256("rounds=10$roundstoolow", "the minimum number is still observed") == "$5$rounds=1000$roundstoolow$yfvwcWrQ8l/K0DAWyuPMDNHpIVlTQebY9l/gL972bIC") + +--]] + +return crypt diff --git a/stand/lua/hashes.lua b/stand/lua/hashes.lua new file mode 100644 --- /dev/null +++ b/stand/lua/hashes.lua @@ -0,0 +1,240 @@ +local sha256_k = {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, + 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, + 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, + 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, + 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, + 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, + 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, + 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, + 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 } + + +local sha512_k = {0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, + 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, + 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, + 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, + 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, + 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, + 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, + 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, + 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, + 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, + 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, + 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, + 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, + 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, + 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 } + +local function maskn(size) + return ~(~0 << size) +end + +local function ror(n, bits, size) + return (n >> bits) | ((n << size - bits) & maskn(size)) +end + +local function string2number(s, i, len) + local n = 0 + for i = i, i + len - 1 do + n = (n<<8) + string.byte(s, i) + end + return n +end + +local function sha512_block(H, chunk) + local w = {} + for i = 1, 16 do + w[i] = string2number(chunk, ((i-1) * 8)+1, 8) + end + + for i = 17, 80 do + local v = w[i - 15] + local s0 = ror(v, 1, 64) ~ ror(v, 8, 64) ~ (v >> 7) + v = w[i - 2] + local s1 = ror(v, 19, 64) ~ ror(v, 61, 64) ~ (v >> 6) + w[i] = (w[i - 16] + s0 + w[i - 7] + s1) & maskn(64) + end + local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] + + for i=1, 80 do + local s0 = ror(a, 28, 64) ~ ror(a, 34, 64) ~ ror(a, 39, 64) + local maj = (a & b) ~ (a & c) ~ (b & c) + local t2 = s0 + maj + local s1 = ror(e, 14, 64) ~ ror(e, 18, 64) ~ ror(e, 41, 64) + local ch = (e & f) ~ (~e & g) + local t1 = h + s1 + ch + sha512_k[i] + w[i] + + h = g + g = f + f = e + e = (d + t1) & maskn(64) + d = c + c = b + b = a + a = (t1 + t2) & maskn(64) + end + H[1] = maskn(64) & (H[1] + a) + H[2] = maskn(64) & (H[2] + b) + H[3] = maskn(64) & (H[3] + c) + H[4] = maskn(64) & (H[4] + d) + H[5] = maskn(64) & (H[5] + e) + H[6] = maskn(64) & (H[6] + f) + H[7] = maskn(64) & (H[7] + g) + H[8] = maskn(64) & (H[8] + h) +end + +local function sha256_block(H, chunk) + local w = {} + for i = 1, 16 do + w[i] = string2number(chunk, ((i-1) * 4)+1, 4) + end + + for i = 17, 64 do + local v = w[i - 15] + local s0 = ror(v, 7, 32) ~ ror(v, 18, 32) ~ (v >> 3) + v = w[i - 2] + local s1 = ror(v, 17, 32) ~ ror(v, 19, 32) ~ (v >> 10) + w[i] = (w[i - 16] + s0 + w[i - 7] + s1) & maskn(32) + end + local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] + + for i=1, 64 do + local s0 = ror(a, 2, 32) ~ ror(a, 13, 32) ~ ror(a, 22, 32) + local maj = (a & b) ~ (a & c) ~ (b & c) + local t2 = s0 + maj + local s1 = ror(e, 6, 32) ~ ror(e, 11, 32) ~ ror(e, 25, 32) + local ch = (e & f) ~ (~e & g) + local t1 = h + s1 + ch + sha256_k[i] + w[i] + + h = g + g = f + f = e + e = (d + t1) & maskn(32) + d = c + c = b + b = a + a = (t1 + t2) & maskn(32) + end + H[1] = maskn(32) & (H[1] + a) + H[2] = maskn(32) & (H[2] + b) + H[3] = maskn(32) & (H[3] + c) + H[4] = maskn(32) & (H[4] + d) + H[5] = maskn(32) & (H[5] + e) + H[6] = maskn(32) & (H[6] + f) + H[7] = maskn(32) & (H[7] + g) + H[8] = maskn(32) & (H[8] + h) +end + +local function number2string(n, length) + local s = "" + for i=1, length do + local rem = n % 256 + s = string.char(rem) .. s + n = n >> 8 + end + return s +end + +local function sha256(msg) + local buffer = "" + local length = 0 + local H = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, + 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 } + local function update(msg) + if msg then + local offset = 1 + local endrange = 64 - #buffer + length = length + #msg + buffer = buffer..string.sub(msg, 1, endrange) + offset = endrange + 1 + while (#buffer == 64) do + sha256_block(H, buffer) + buffer = string.sub(msg, offset, offset + 63) + offset = offset + 64 + end + return update + else + local padding = -(length + 1 + 8) % 64 + update("\128" .. string.rep("\0", padding) .. number2string(length*8, 8)) + buffer = nil + local result = "" + for i=1, 8 do + result = result .. number2string(H[i], 4) + end + return result; + end + end + if msg then + return update(msg)() + else + return update + end +end + +local function sha512(msg) + local length = 0 + local buffer = "" + local H = {0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, + 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179} + local function update(msg) + if msg then + local offset = 1 + local endrange = 128 - #buffer + length = length + #msg + buffer = buffer..string.sub(msg, 1, endrange) + offset = endrange + 1 + while (#buffer == 128) do + sha512_block(H, buffer) + buffer = string.sub(msg, offset, offset + 127) + offset = offset + 128 + end + return update + else + local padding = (-(length + 1 + 16) % 128) + 8 + local padstring = "\128" .. string.rep("\0", padding) .. number2string(length*8, 8) + update(padstring) + buffer = nil + local result = "" + for i=1, 8 do + result = result .. number2string(H[i], 8) + end + return result + end + end + if msg then + return update(msg)() + else + return update + end +end + +local function string2hex(s) + local h = string.gsub(s, ".", function(c) return string.format("%02x", string.byte(c)) + end) + return h +end + +local hashes = { + sha256= sha256, + sha512= sha512, + string2hex= string2hex +} + +return hashes diff --git a/stand/lua/password.lua b/stand/lua/password.lua --- a/stand/lua/password.lua +++ b/stand/lua/password.lua @@ -31,6 +31,7 @@ local core = require("core") local screen = require("screen") +local crypt = require("crypt") local password = {} @@ -87,6 +88,16 @@ end function password.check() + local function compare(entered, stored) + if stored == nil then + return true + end + local result = crypt.compare(entered, stored) + if result == nil then + return entered == stored + end + return result + end -- pwd is optionally supplied if we want to check it local function doPrompt(prompt, pwd) local attempts = 1 @@ -106,7 +117,7 @@ screen.defcursor() printc(prompt) local read_pwd = password.read(#prompt) - if pwd == nil or pwd == read_pwd then + if compare(read_pwd, pwd) then -- Clear the prompt + twiddle printc(string.rep(" ", #prompt + 5)) return read_pwd @@ -116,7 +127,7 @@ loader.delay(3*1000*1000) end end - local function compare(prompt, pwd) + local function pwGate(prompt, pwd) if pwd == nil then return end @@ -124,7 +135,7 @@ end local boot_pwd = loader.getenv("bootlock_password") - compare("Bootlock password:", boot_pwd) + pwGate("Bootlock password:", boot_pwd) local geli_prompt = loader.getenv("geom_eli_passphrase_prompt") if geli_prompt ~= nil and geli_prompt:lower() == "yes" then @@ -141,7 +152,7 @@ -- in the middle of other text. setup_screen() end - compare("Loader password:", pwd) + pwGate("Loader password:", pwd) end return password