Page MenuHomeFreeBSD

D41509.id142027.diff
No OneTemporary

D41509.id142027.diff

diff --git a/lib/flua/libhash/hash.3lua b/lib/flua/libhash/hash.3lua
--- a/lib/flua/libhash/hash.3lua
+++ b/lib/flua/libhash/hash.3lua
@@ -21,13 +21,15 @@
.Bl -bullet -compact
.It
sha256
+.It
+sha512
.El
.Ss APIs Supported
.Bl -tag -width asdf -compact
.It Fn new data
Compute a digest based on the
.Va data .
-.It Fn update Va data
+.It Fn update data
Using the current digest, process
.Va data
to compute a new digest as if all prior data had been concatenated together.
@@ -47,6 +49,7 @@
.Sh EXAMPLES
.Sh SEE ALSO
.Xr sha256 3
+.Xr sha512 3
.Sh AUTHORS
The
.Nm
diff --git a/lib/flua/libhash/lhash.c b/lib/flua/libhash/lhash.c
--- a/lib/flua/libhash/lhash.c
+++ b/lib/flua/libhash/lhash.c
@@ -9,10 +9,13 @@
#include "lhash.h"
#include <sha256.h>
+#include <sha512.h>
#include <string.h>
#define SHA256_META "SHA256 meta table"
+#define SHA512_META "SHA512 meta table"
#define SHA256_DIGEST_LEN 32
+#define SHA512_DIGEST_LEN 64
/*
* Note C++ comments indicate the before -- after state of the stack, in with a
@@ -41,6 +44,21 @@
return (1);
}
+static int
+lua_sha512_update(lua_State *L)
+{
+ size_t len;
+ const unsigned char *data;
+ SHA512_CTX *ctx;
+
+ ctx = luaL_checkudata(L, 1, SHA512_META);
+ data = luaL_checklstring(L, 2, &len);
+ SHA512_Update(ctx, data, len);
+
+ lua_settop(L, 1);
+
+ return (1);
+}
/*
* Finalizes the digest value and returns it as a 32-byte binary string. The ctx
@@ -58,34 +76,69 @@
return (1);
}
+static int
+lua_sha512_digest(lua_State *L)
+{
+ SHA512_CTX *ctx;
+ unsigned char digest[SHA512_DIGEST_LEN];
+
+ ctx = luaL_checkudata(L, 1, SHA512_META);
+ SHA512_Final(digest, ctx);
+ lua_pushlstring(L, digest, sizeof(digest));
+
+ return(1);
+}
/*
* Finalizes the digest value and returns it as a 64-byte ascii string of hex
* numbers. The ctx is zeroed.
*/
+static void
+hash_hexdigest(char *buf, unsigned char *digest, int len)
+{
+ static const char hex[]="0123456789abcdef";
+ int i;
+ for (i = 0; i < len; i++) {
+ buf[i<<1] = hex[digest[i] >> 4];
+ buf[(i<<1) + 1] = hex[digest[i] & 0x0f];
+ }
+ buf[i<<1] = '\0';
+}
+
static int
lua_sha256_hexdigest(lua_State *L)
{
SHA256_CTX *ctx;
- char buf[SHA256_DIGEST_LEN * 2 + 1];
unsigned char digest[SHA256_DIGEST_LEN];
- static const char hex[]="0123456789abcdef";
- int i;
+ char buf[SHA256_DIGEST_LEN * 2 + 1];
ctx = luaL_checkudata(L, 1, SHA256_META);
+
SHA256_Final(digest, ctx);
- for (i = 0; i < SHA256_DIGEST_LEN; i++) {
- buf[i+i] = hex[digest[i] >> 4];
- buf[i+i+1] = hex[digest[i] & 0x0f];
- }
- buf[i+i] = '\0';
+ hash_hexdigest(buf, digest, SHA256_DIGEST_LEN);
lua_pushstring(L, buf);
return (1);
}
+static int
+lua_sha512_hexdigest(lua_State *L)
+{
+ SHA512_CTX *ctx;
+ unsigned char digest[SHA512_DIGEST_LEN];
+ char buf[SHA512_DIGEST_LEN * 2 + 1];
+
+ ctx = luaL_checkudata(L, 1, SHA512_META);
+
+ SHA512_Final(digest, ctx);
+ hash_hexdigest(buf, digest, SHA512_DIGEST_LEN);
+
+ lua_pushstring(L, buf);
+ return (1);
+}
/*
+
* Zeros out the ctx before garbage collection. Normally this is done in
* obj:digest or obj:hexdigest, but if not, it will be wiped here. Lua
* manages freeing the ctx memory.
@@ -100,9 +153,19 @@
return (0);
}
+static int
+lua_sha512_done(lua_State *L)
+{
+ SHA512_CTX *ctx;
+
+ ctx = luaL_checkudata(L, 1, SHA512_META);
+ memset(ctx, 0, sizeof(*ctx));
+
+ return (0);
+}
/*
- * Create object obj which accumulates the state of the sha256 digest
+ * Create object obj which accumulates the state of the sha256/512 digest
* for its contents and any subsequent obj:update call. It takes zero
* or 1 arguments.
*/
@@ -132,9 +195,35 @@
return (1); // data . ctx
}
+static int
+lua_sha512(lua_State *L)
+{
+ SHA512_CTX *ctx;
+ int top;
+
+ /* We take 0 or 1 args */
+ top = lua_gettop(L); // data -- data
+ if (top > 1) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ ctx = lua_newuserdata(L, sizeof(*ctx)); // data -- data ctx
+ SHA512_Init(ctx);
+ if (top == 1) {
+ size_t len;
+ const unsigned char *data;
+
+ data = luaL_checklstring(L, 1, &len);
+ SHA512_Update(ctx, data, len);
+ }
+ luaL_setmetatable(L, SHA512_META); // data ctx -- data ctx
+
+ return (1); // data . ctx
+}
/*
- * Setup the metatable to manage our userdata that we create in lua_sha256. We
+ * Setup the metatable to manage our userdata that we create in lua_sha256/512. We
* request a finalization call with __gc so we can zero out the ctx buffer so
* that we don't leak secrets if obj:digest or obj:hexdigest aren't called.
*/
@@ -158,10 +247,31 @@
lua_pop(L, 1); // meta --
}
+static void
+register_metatable_sha512(lua_State *L)
+{
+ luaL_newmetatable(L, SHA512_META); // -- meta
+
+ lua_newtable(L); // meta -- meta tbl
+ lua_pushcfunction(L, lua_sha512_update); // meta tbl -- meta tbl fn
+ lua_setfield(L, -2, "update"); // meta tbl fn -- meta tbl
+ lua_pushcfunction(L, lua_sha512_digest); // meta tbl -- meta tbl fn
+ lua_setfield(L, -2, "digest"); // meta tbl fn -- meta tbl
+ lua_pushcfunction(L, lua_sha512_hexdigest); // meta tbl -- meta tbl fn
+ lua_setfield(L, -2, "hexdigest"); // meta tbl fn -- meta tbl
+
+ /* Associate tbl with metatable */
+ lua_setfield(L, -2, "__index"); // meta tbl -- meta
+ lua_pushcfunction(L, lua_sha512_done); // meta -- meta fn
+ lua_setfield(L, -2, "__gc"); // meta fn -- meta
+
+ lua_pop(L, 1); // meta --
+}
#define REG_SIMPLE(n) { #n, lua_ ## n }
static const struct luaL_Reg hashlib[] = {
REG_SIMPLE(sha256),
+ REG_SIMPLE(sha512),
{ NULL, NULL },
};
#undef REG_SIMPLE
@@ -170,6 +280,7 @@
luaopen_hash(lua_State *L)
{
register_metatable_sha256(L);
+ register_metatable_sha512(L);
luaL_newlib(L, hashlib);
diff --git a/stand/common/interp_lua.c b/stand/common/interp_lua.c
--- a/stand/common/interp_lua.c
+++ b/stand/common/interp_lua.c
@@ -93,6 +93,7 @@
{"lfs", luaopen_lfs},
{"loader", luaopen_loader},
{"pager", luaopen_pager},
+ {"hash", luaopen_hash},
{NULL, NULL}
};
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
@@ -219,7 +219,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 passwd
+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
@@ -231,7 +253,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 passwd
+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/liblua/lutils.h b/stand/liblua/lutils.h
--- a/stand/liblua/lutils.h
+++ b/stand/liblua/lutils.h
@@ -30,6 +30,7 @@
int luaopen_loader(lua_State *);
int luaopen_io(lua_State *);
int luaopen_pager(lua_State *);
+int luaopen_hash(lua_State *);
#include <sys/linker_set.h>
diff --git a/stand/lua/Makefile b/stand/lua/Makefile
--- a/stand/lua/Makefile
+++ b/stand/lua/Makefile
@@ -18,6 +18,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,435 @@
+--
+-- SPDX-License-Identifier: BSD-2-Clause
+--
+-- Copyright (c) 2024 David Cross <david@dcrosstech.com>
+-- All rights reserved.
+--
+
+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 _ = 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 ctx = hash.sha256(password)
+ ctx:update(salt)
+
+ local ctx_alt = hash.sha256(password)
+ ctx_alt:update(salt)
+ ctx_alt:update(password)
+
+ local alt_result = ctx_alt:digest()
+ -- for each character of the password, add alt_result (wrapping as needed)
+ for _ = #password, 33, -32 do
+ ctx:update(alt_result)
+ end
+ ctx:update(string.sub(alt_result, 1, #password % 32))
+
+ local count = #password
+ while count > 0 do
+ if (count & 1) ~=0 then
+ ctx:update(alt_result)
+ else
+ ctx:update(password)
+ end
+ count = count >> 1
+ end
+
+ alt_result=ctx:digest()
+
+ -- P sequence
+ ctx = hash.sha256()
+ for _ = 1, #password do
+ ctx:update(password)
+ end
+ local temp_result = ctx:digest()
+ 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
+ ctx = hash.sha256()
+ for _ = 1, 16 + string.byte(alt_result, 1) do
+ ctx:update(salt)
+ end
+ temp_result = ctx:digest()
+
+ 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
+ ctx = hash.sha256()
+ if (cnt & 1) ~= 0 then
+ ctx:update(p_bytes)
+ else
+ ctx:update(alt_result)
+ end
+ if (cnt % 3) ~= 0 then
+ ctx:update(s_bytes)
+ end
+ if (cnt % 7) ~= 0 then
+ ctx:update(p_bytes)
+ end
+ if (cnt & 1) ~= 0 then
+ ctx:update(alt_result)
+ else
+ ctx:update(p_bytes)
+ end
+ alt_result = ctx:digest()
+ 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 ctx = hash.sha512(password)
+ ctx:update(salt)
+
+ local ctx_alt = hash.sha512(password)
+ ctx_alt:update(salt)
+ ctx_alt:update(password)
+
+ local alt_result = ctx_alt:digest()
+ -- for each character of the password add the alt_result (wrapping as needed)
+ for _ = #password, 65, -64 do
+ ctx:update(alt_result)
+ end
+ ctx:update(string.sub(alt_result, 1, #password % 64))
+
+ local count = #password
+ while count > 0 do
+ if (count & 1) ~=0 then
+ ctx:update(alt_result)
+ else
+ ctx:update(password)
+ end
+ count = count >> 1
+ end
+
+ -- P sequence
+ alt_result=ctx:digest()
+ ctx = hash.sha512()
+ for _ = 1, #password do
+ ctx:update(password)
+ end
+ local temp_result = ctx:digest()
+ 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
+ ctx = hash.sha512()
+ for _ = 1, 16 + string.byte(alt_result, 1) do
+ ctx:update(salt)
+ end
+ temp_result = ctx:digest()
+
+ 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
+ ctx = hash.sha512()
+ if (cnt & 1) ~= 0 then
+ ctx:update(p_bytes)
+ else
+ ctx:update(alt_result)
+ end
+ if (cnt % 3) ~= 0 then
+ ctx:update(s_bytes)
+ end
+ if (cnt % 7) ~= 0 then
+ ctx:update(p_bytes)
+ end
+ if (cnt & 1) ~= 0 then
+ ctx:update(alt_result)
+ else
+ ctx:update(p_bytes)
+ end
+ alt_result = ctx:digest()
+ 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 sha512_ctx=hash.sha512()
+ local sha256_ctx=hash.sha256()
+ local string = tests_hash[test].string
+ local expected = tests_hash[test].expected
+ local iterations = tests_hash[test].iterations
+ for _ = 1, iterations do
+ sha256_ctx:update(string)
+ sha512_ctx:update(string)
+ end
+ local sha256_digest = sha256_ctx:hexdigest()
+ local sha512_digest = sha512_ctx:hexdigest()
+ assert(sha256_digest == expected.sha256)
+ assert(sha512_digest == 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
@@ -29,6 +29,7 @@
local core = require("core")
local screen = require("screen")
+local crypt = require("crypt")
local password = {}
@@ -85,6 +86,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
@@ -104,7 +118,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
@@ -114,7 +128,7 @@
loader.delay(3*1000*1000)
end
end
- local function compare(prompt, pwd)
+ local function pwGate(prompt, pwd)
if pwd == nil then
return
end
@@ -122,7 +136,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
@@ -140,7 +154,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
Thu, Jun 25, 7:57 AM (16 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34313863
Default Alt Text
D41509.id142027.diff (25 KB)

Event Timeline