Page MenuHomeFreeBSD

D41509.id137310.diff
No OneTemporary

D41509.id137310.diff

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,29 @@
Protect boot menu with a password without interrupting
.Ic autoboot
process.
-The password should be in clear text format.
+.Pp
+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).
+To use
+.Xr crypt 3
+format passwords prefix the stored password with
+.Dq Li crypt:
+and escape any
+.Dq Li \[Do]
+with
+.Dq Li \e .
+.Xr crypt 3
+passwords may be generated with
+.Xr openssl 1
+in
+.Dq Li password
+mode by specifying
+.Dq Li -5
+or
+.Dq Li -6
+for algorithm 5 or 6 passwords respectively.
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 +212,29 @@
.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.
+.Pp
+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).
+To use
+.Xr crypt 3
+format passwords prefix the stored password with
+.Dq Li crypt:
+and escape any
+.Dq Li \[Do]
+with
+.Dq Li \e .
+.Xr crypt 3
+passwords may be generated with
+.Xr openssl 1
+in
+.Dq Li password
+mode by specifying
+.Dq Li -5
+or
+.Dq Li -6
+for algorithm 5 or 6 passwords respectively.
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,6 +17,7 @@
color.lua \
config.lua \
core.lua \
+ crypt.lua \
drawer.lua \
hook.lua \
loader.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,696 @@
+--
+-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+--
+-- Copyright (c) 2024 David Cross <david@dcrosstech.com>
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+-- 1. Redistributions of source code must retain the above copyright
+-- notice, this list of conditions and the following disclaimer.
+-- 2. Redistributions in binary form must reproduce the above copyright
+-- notice, this list of conditions and the following disclaimer in the
+-- documentation and/or other materials provided with the distribution.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+-- SUCH DAMAGE.
+--
+-- $FreeBSD$
+--
+
+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 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 x = i, i + len - 1 do
+ n = (n<<8) + string.byte(s, x)
+ 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 _ = 1, length do
+ local rem = n % 256
+ s = string.char(rem) .. s
+ n = n >> 8
+ end
+ return s
+end
+
+--
+-- For use by crypt routines only
+-- do not re-export without further discussion
+--
+local hashes = {
+ sha256 = function (message)
+ local buffer = ""
+ local length = 0
+ local H = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f,
+ 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }
+ local function update(msg)
+ if msg then
+ local endrange = 64 - #buffer
+ length = length + #msg
+ buffer = buffer..string.sub(msg, 1, endrange)
+ local 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 message then
+ return update(message)()
+ else
+ return update
+ end
+ end,
+
+ sha512 = function (message)
+ local length = 0
+ local buffer = ""
+ local H = {0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b,
+ 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f,
+ 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179}
+ local function update(msg)
+ if msg then
+ local endrange = 128 - #buffer
+ length = length + #msg
+ buffer = buffer..string.sub(msg, 1, endrange)
+ local 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 message then
+ return update(message)()
+ else
+ return update
+ end
+ end,
+
+ string2hex = function (s)
+ local h = string.gsub(s, ".", function(c) return string.format("%02x", string.byte(c))
+ end)
+ return h
+ end
+}
+
+local function b64_from_24bit(b2, b1, b0, n)
+ local w = ((b2 & 0xff) << 16) | ((b1 & 0xff) << 8) | (b0 & 0xff)
+ local s = ""
+ for _ = 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 _ = #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 _ = 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 _ = 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 _ = #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 _ = 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 _ = 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)
+ local algorithm = string.sub(stored, 1, 3)
+ local salthash = string.sub(stored, 4)
+ local hashed
+ if algorithm == '$5$' then hashed = crypt.sha256(salthash, entered)
+ elseif algorithm == '$6$' then hashed = crypt.sha512(salthash, entered)
+ end
+ if hashed ~= nil then
+ return hashed == stored
+ end
+ return nil
+end
+
+-- luacheck: push no max line length
+-- hash tests
+-- warning: these tests take about 24 minutes to run
+--[[
+local tests_hash = {
+ { string = "abc",
+ iterations = 1,
+ expected = {
+ sha256 = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
+ sha512 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" }
+ } ,
+ { string = "",
+ iterations = 1,
+ expected = {
+ sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ sha512 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" }
+ },
+ { string = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ iterations = 1,
+ expected = {
+ sha256 = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
+ sha512 = "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445" }
+ } ,
+ { string = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+ iterations = 1,
+ expected = {
+ sha256 = "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1",
+ sha512 = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" }
+ },
+ { string = "a",
+ iterations = 1000000,
+ expected = {
+ sha256 = "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0",
+ sha512 = "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" }
+ },
+ { string = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno",
+ iterations = 16777216,
+ expected = {
+ sha256 = "50e72a0e26442fe2552dc3938ac58658228c0cbfb1d2ca872ae435266fcd055e",
+ sha512 = "b47c933421ea2db149ad6e10fce6c7f93d0752380180ffd7f4629a712134831d77be6091b819ed352c2967a2e2d4fa5050723c9630691f1a05a7281dbe6c1086" }
+ }
+}
+
+print("WARNING: you have enabled hash validation tests")
+for test = 1, #tests_hash do
+ local sha512test=hashes.sha512()
+ local sha256test=hashes.sha256()
+ local string = tests_hash[test].string
+ local expected = tests_hash[test].expected
+ local iterations = tests_hash[test].iterations
+ for _ = 1, iterations do
+ sha256test(string)
+ sha512test(string)
+ end
+ assert(hashes.string2hex(sha256test()) == expected.sha256)
+ assert(hashes.string2hex(sha512test()) == expected.sha512)
+end
+--]]
+
+-- crypt(3) tests
+-- warning: These tests take about 1 minute to run
+--[[
+local tests_crypt = {
+ { salt = "saltstring",
+ string = "Hello world!",
+ expected = {
+ sha512 = "$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJuesI68u4OTLiBFdcbYEdFCoEOfaS35inz1",
+ sha256 = "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5"}},
+ { salt = "rounds=10000$saltstringsaltstring",
+ string = "Hello world!",
+ expected = {
+ sha512 = "$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sbHbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v.",
+ sha256 = "$5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2.opqey6IcA"}},
+ { salt = "rounds=5000$toolongsaltstring",
+ string = "This is just a test",
+ expected = {
+ sha512 = "$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQzQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0",
+ sha256 = "$5$rounds=5000$toolongsaltstrin$Un/5jzAHMgOGZ5.mWJpuVolil07guHPvOW8mGRcvxa5"}},
+ { salt = "rounds=1400$anotherlongsaltstring",
+ string = "a very much longer text to encrypt. This one even stretches over morethan one line.",
+ expected = {
+ sha512 = "$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wPvMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1",
+ sha256 = "$5$rounds=1400$anotherlongsalts$Rx.j8H.h8HjEDGomFU8bDkXm3XIUnzyxf12oP84Bnq1" }},
+ { salt = "rounds=77777$short",
+ string = "we have a short salt string but not a short password",
+ expected = {
+ sha512 = "$6$rounds=77777$short$WuQyW2YR.hBNpjjRhpYD/ifIw05xdfeEyQoMxIXbkvr0gge1a1x3yRULJ5CCaUeOxFmtlcGZelFl5CxtgfiAc0",
+ sha256 = "$5$rounds=77777$short$JiO1O3ZpDAxGJeaDIuqCoEFysAe1mZNJRs3pw0KQRd/" }},
+ { salt = "rounds=123456$asaltof16chars..",
+ string = "a short string",
+ expected = {
+ sha512 = "$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwcelCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1",
+ sha256 = "$5$rounds=123456$asaltof16chars..$gP3VQ/6X7UUEW3HkBn2w1/Ptq2jxPyzV/cZKmF/wJvD" }},
+ { salt = "rounds=10$roundstoolow",
+ string = "the minimum number is still observed",
+ expected = {
+ sha512 = "$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1xhLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX.",
+ sha256 = "$5$rounds=1000$roundstoolow$yfvwcWrQ8l/K0DAWyuPMDNHpIVlTQebY9l/gL972bIC" }}
+}
+
+print("WARNING: you have enabled crypt(3) validation tests")
+for test = 1, #tests_crypt do
+ local salt = tests_crypt[test].salt
+ local string = tests_crypt[test].string
+ local expected = tests_crypt[test].expected
+ assert(crypt.sha256(salt, string) == expected.sha256)
+ assert(crypt.sha512(salt, string) == expected.sha512)
+end
+--]]
+-- luacheck: pop
+return crypt
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,19 @@
end
function password.check()
+ local function compare(entered, stored)
+ if stored == nil then
+ return true
+ end
+ local result
+ if string.sub(stored, 1, 6) == "crypt:" then
+ result = crypt.compare(entered, string.sub(stored, 7))
+ end
+ 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 +120,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 +130,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 +138,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 +155,7 @@
-- in the middle of other text.
setup_screen()
end
- compare("Loader password:", pwd)
+ pwGate("Loader password:", pwd)
end
return password

File Metadata

Mime Type
text/plain
Expires
Tue, Feb 17, 1:32 PM (9 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28814387
Default Alt Text
D41509.id137310.diff (27 KB)

Event Timeline