Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F145154920
D41509.id137310.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
27 KB
Referenced Files
None
Subscribers
None
D41509.id137310.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D41509: crypt(3) style password support for lua loader
Attached
Detach File
Event Timeline
Log In to Comment