[prev in list] [next in list] [prev in thread] [next in thread] 

List:       freebsd-hackers
Subject:    crypt(3) style password support for lua-loader
From:       "David E. Cross" <david () crossfamilyweb ! com>
Date:       2023-08-19 22:03:38
Message-ID: 74a1eb5e-64a5-f8e7-c44e-55188539643a () crossfamilyweb ! com
[Download RAW message or body]

I sent this earlier from the wrong account and either -hackers bounced 
it, or -hackers is down, apologies if you get a dupe on this, but I also 
included a reviews.freebsd.org link this time)


Something that has always bothered me is the if you enable boot 
passwords with loader(8) they are stored *plaintext* in the loader.conf, 
so you need to make sure that file is root-only access and is just poor 
security in general.

Well, I decided to fix that.  See attached, also at:

https://reviews.freebsd.org/D41509


It is lua only, I evaluated doing a forth version to maintain parity 
with forth-loader, but that exceeds my available time at this point and 
I'd rather get this out there.

Includes loader.conf.5 documentation update.  This is tested and working 
in boot environment.  (... why doesn't lua-loader have math.*?);

additionally crypt.lua has commented-out test suite and validates 
against all crypt-sha256.c and crypt-sha512.c test vectors.


The only real gotcha with this is that crypt(3) style passwords use '$' 
in them and that must be escaped in loader.conf(5).  I debated switching 
this to ! or another character but decided to stick with $ as no matter 
what you will need to edit between strict crypt(3) format and what is 
placed in the config file, and this makes testing easier if the formats 
are the strictly identical.  That is even if I changed it to not need 
escaping, you'd still need to edit it anyway, so if you still have to 
edit, might as well keep the underlying format the same.


This gotcha is documented in the updated loader.conf(5)


Thanks.

["luahash.diff" (text/x-patch)]

diff --git a/stand/defaults/loader.conf.5 b/stand/defaults/loader.conf.5
index 23a65935c95..ddd327a939d 100644
--- a/stand/defaults/loader.conf.5
+++ b/stand/defaults/loader.conf.5
@@ -178,7 +178,15 @@ is damaged, lost, or read from the wrong partition.
 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 @@ menu.
 .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
index fe6fd6f63c8..c22254eee21 100644
--- a/stand/lua/Makefile
+++ b/stand/lua/Makefile
@@ -17,7 +17,9 @@ FILES=	cli.lua \
 	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
index 00000000000..3e822dfb581
--- /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
index 00000000000..66e219e5169
--- /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
index 8edd4edd7ec..52acbf84769 100644
--- 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 @@ function password.read(prompt_length)
 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 @@ function password.check()
 			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 @@ function password.check()
 			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 @@ function password.check()
 	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 @@ function password.check()
 		-- in the middle of other text.
 		setup_screen()
 	end
-	compare("Loader password:", pwd)
+	pwGate("Loader password:", pwd)
 end
 
 return password



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic