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