[git commit] libbb/yescrypt: disable code which accepts unusual yescrypt parameters
Denys Vlasenko
vda.linux at googlemail.com
Tue Jul 8 03:34:41 UTC 2025
commit: https://git.busybox.net/busybox/commit/?id=d0f0874d573f33f9f14372a4513f22f76c559479
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master
Almost any reasonable yescrypt hashes in /etc/shadow should only ever use
"jXY" parameters which set N and r. Fancy multi-byte-encoded
wide integers are not needed for that.
function old new delta
static.yescrypt_kdf32_body - 899 +899
static.PBKDF2_SHA256 213 219 +6
decode64_uint32 141 - -141
yescrypt_r 990 805 -185
yescrypt_kdf32_body 1423 - -1423
------------------------------------------------------------------------------
(add/remove: 1/2 grow/shrink: 1/1 up/down: 905/-1749) Total: -844 bytes
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
libbb/yescrypt/alg-yescrypt-common.c | 25 +++++++-
libbb/yescrypt/alg-yescrypt.h | 120 ++++++++++++++++++++---------------
2 files changed, 92 insertions(+), 53 deletions(-)
diff --git a/libbb/yescrypt/alg-yescrypt-common.c b/libbb/yescrypt/alg-yescrypt-common.c
index c85b2a0b9..e48be6581 100644
--- a/libbb/yescrypt/alg-yescrypt-common.c
+++ b/libbb/yescrypt/alg-yescrypt-common.c
@@ -18,6 +18,23 @@
* SUCH DAMAGE.
*/
+#if RESTRICTED_PARAMS
+
+#define decode64_uint32(dst, src, min) \
+({ \
+ uint32_t d32 = a2i64(*(src)); \
+ if (d32 > 47) \
+ goto fail; \
+ *(dst) = d32 + (min); \
+ ++src; \
+})
+#define test_decode64_uint32() ((void)0)
+#define FULL_PARAMS(...)
+
+#else
+
+#define FULL_PARAMS(...) __VA_ARGS__
+
/* Not inlining:
* de/encode64 functions are only used to read
* yescrypt_params_t field, and convert salt to binary -
@@ -128,6 +145,8 @@ static void test_decode64_uint32(void)
# define test_decode64_uint32() ((void)0)
#endif
+#endif /* !RESTRICTED_PARAMS */
+
#if 1
static const uint8_t *decode64(
uint8_t *dst, size_t *dstlen,
@@ -283,7 +302,7 @@ char *yescrypt_r(
test_decode64_uint32();
memset(yctx, 0, sizeof(yctx));
- yctx->param.p = 1;
+ FULL_PARAMS(yctx->param.p = 1;)
/* we assume setting starts with "$y$" (caller must ensure this) */
src = setting + 3;
@@ -324,6 +343,9 @@ char *yescrypt_r(
if (!src)
goto fail;
if (*src != '$') {
+#if RESTRICTED_PARAMS
+ goto fail;
+#else
src = decode64_uint32(&u32, src, 1);
dbg("yescrypt has extended params:0x%x", (unsigned)u32);
if (u32 & 1)
@@ -342,6 +364,7 @@ char *yescrypt_r(
goto fail;
if (*src != '$')
goto fail;
+#endif
}
yctx->saltlen = sizeof(yctx->salt);
diff --git a/libbb/yescrypt/alg-yescrypt.h b/libbb/yescrypt/alg-yescrypt.h
index e558cfdc5..a1d540c08 100644
--- a/libbb/yescrypt/alg-yescrypt.h
+++ b/libbb/yescrypt/alg-yescrypt.h
@@ -29,6 +29,8 @@
*/
#ifdef YESCRYPT_INTERNAL
+// busybox debug and size-reduction configuration
+
# if 1
# define dbg(...) ((void)0)
# else
@@ -42,6 +44,68 @@
#endif
#define TEST_DECODE64 0
+/* Only accept one-char parameters in hash, and only first three?
+ * Almost any reasonable yescrypt hashes in /etc/shadow should
+ * only ever use "jXY" parameters which set N and r.
+ * Fancy multi-byte-encoded wide integers are not needed for that.
+ */
+#define RESTRICTED_PARAMS 1
+/* Note: if you enable the above, please also enable
+ * YCTX_param_p, YCTX_param_t, YCTX_param_g, YCTX_param_NROM
+ * optimizations.
+ */
+
+// How much we save by forcing "standard" value by commenting the next line:
+// 160 bytes
+//#define YCTX_param_flags yctx->param.flags
+// 260 bytes
+//#define flags___YESCRYPT_RW (flags & YESCRYPT_RW)
+// 140 bytes
+//#define flags___YESCRYPT_MODE_MASK (flags & YESCRYPT_MODE_MASK)
+// ^^^^ forcing the above since the code already requires (checks for) this
+// 50 bytes
+#define YCTX_param_N yctx->param.N
+// -100 bytes (negative!!!)
+#define YCTX_param_r yctx->param.r
+// 400 bytes
+//#define YCTX_param_p yctx->param.p
+// 130 bytes
+//#define YCTX_param_t yctx->param.t
+// 2 bytes
+//#define YCTX_param_g yctx->param.g
+// 1 bytes
+// ^^^^ this looks wrong, compiler should be able to constant-propagate the fact that NROM code is dead
+//#define YCTX_param_NROM yctx->param.NROM
+
+#ifndef YCTX_param_flags
+#define YCTX_param_flags (YESCRYPT_RW | YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K)
+#endif
+#ifndef flags___YESCRYPT_RW
+#define flags___YESCRYPT_RW ((void)flags, YESCRYPT_RW)
+#endif
+#ifndef flags___YESCRYPT_MODE_MASK
+#define flags___YESCRYPT_MODE_MASK ((void)flags, YESCRYPT_RW)
+#endif
+// standard ("j9T") values:
+#ifndef YCTX_param_N
+#define YCTX_param_N 4096
+#endif
+#ifndef YCTX_param_r
+#define YCTX_param_r 32
+#endif
+#ifndef YCTX_param_p
+#define YCTX_param_p 1
+#endif
+#ifndef YCTX_param_t
+#define YCTX_param_t 0
+#endif
+#ifndef YCTX_param_g
+#define YCTX_param_g 0
+#endif
+#ifndef YCTX_param_NROM
+#define YCTX_param_NROM 0
+#endif
+
/**
* Type and possible values for the flags argument of yescrypt_kdf(),
* yescrypt_encode_params_r(), yescrypt_encode_params(). Most of these may be
@@ -129,9 +193,12 @@ typedef struct {
*/
typedef struct {
uint32_t flags;
+ uint32_t r;
uint64_t N;
- uint32_t r, p, t, g;
+#if !RESTRICTED_PARAMS
+ uint32_t p, t, g;
uint64_t NROM;
+#endif
} yescrypt_params_t;
typedef struct {
@@ -147,57 +214,6 @@ typedef struct {
yescrypt_region_t local[1];
} yescrypt_ctx_t;
-// How much can save by forcing "standard" value by commenting the next line:
-// 160 bytes
-//#define YCTX_param_flags yctx->param.flags
-// 260 bytes
-//#define flags___YESCRYPT_RW (flags & YESCRYPT_RW)
-// 140 bytes
-//#define flags___YESCRYPT_MODE_MASK (flags & YESCRYPT_MODE_MASK)
-// ^^^^ forcing the above since the code already requires (checks for) this
-// 50 bytes
-#define YCTX_param_N yctx->param.N
-// -100 bytes (negative!!!)
-#define YCTX_param_r yctx->param.r
-// 400 bytes
-#define YCTX_param_p yctx->param.p
-// 130 bytes
-#define YCTX_param_t yctx->param.t
-// 2 bytes
-#define YCTX_param_g yctx->param.g
-// 1 bytes
-// ^^^^ this looks wrong, compiler should be able to constant-propagate the fact that NROM code is dead
-#define YCTX_param_NROM yctx->param.NROM
-
-// standard ("j9T") values:
-#ifndef YCTX_param_flags
-#define YCTX_param_flags (YESCRYPT_RW | YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K)
-#endif
-#ifndef flags___YESCRYPT_RW
-#define flags___YESCRYPT_RW ((void)flags, YESCRYPT_RW)
-#endif
-#ifndef flags___YESCRYPT_MODE_MASK
-#define flags___YESCRYPT_MODE_MASK ((void)flags, YESCRYPT_RW)
-#endif
-#ifndef YCTX_param_N
-#define YCTX_param_N 4096
-#endif
-#ifndef YCTX_param_r
-#define YCTX_param_r 32
-#endif
-#ifndef YCTX_param_p
-#define YCTX_param_p 1
-#endif
-#ifndef YCTX_param_t
-#define YCTX_param_t 0
-#endif
-#ifndef YCTX_param_g
-#define YCTX_param_g 0
-#endif
-#ifndef YCTX_param_NROM
-#define YCTX_param_NROM 0
-#endif
-
/**
* yescrypt_r(shared, local, passwd, passwdlen, setting, key, buf, buflen):
* Compute and encode an scrypt or enhanced scrypt hash of passwd given the
More information about the busybox-cvs
mailing list