[git commit] add libbb/yescrypt/PARAMETERS
Denys Vlasenko
vda.linux at googlemail.com
Mon Jul 7 19:36:31 UTC 2025
commit: https://git.busybox.net/busybox/commit/?id=7798f651a48926636944d556a158a9b569a56367
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
libbb/yescrypt/PARAMETERS | 196 +++++++++++++++++++++++++++++++++++
libbb/yescrypt/alg-sha256.c | 9 +-
libbb/yescrypt/alg-yescrypt-common.c | 3 +-
3 files changed, 202 insertions(+), 6 deletions(-)
diff --git a/libbb/yescrypt/PARAMETERS b/libbb/yescrypt/PARAMETERS
new file mode 100644
index 000000000..d9f5d24e6
--- /dev/null
+++ b/libbb/yescrypt/PARAMETERS
@@ -0,0 +1,196 @@
+ Optimal yescrypt configuration.
+
+yescrypt is very flexible, but configuring it optimally is complicated.
+Here are some guidelines to simplify near-optimal configuration. We
+start by listing the parameters and their typical values, and then give
+currently recommended parameter sets by use case.
+
+
+ Parameters and their typical values.
+
+Set flags (yescrypt flavor) to YESCRYPT_DEFAULTS to use the currently
+recommended flavor. (Other flags values exist for compatibility and for
+specialized cases where you think you know what you're doing.)
+
+Set N (block count) based on target memory usage and running time, as
+well as on the value of r (block size in 128 byte units). N must be a
+power of two.
+
+Set r (block size) to 8 (so that N is in KiB, which is convenient) or to
+another small value (if more optimal or for fine-tuning of the total
+size and/or running time). Reasonable values for r are from 8 to 96.
+
+Set p (parallelism) to 1 meaning no thread-level parallelism within one
+computation of yescrypt. (Use of thread-level parallelism within
+yescrypt makes sense for ROM initialization and for key derivation at
+high memory usage, but usually not for password hashing where
+parallelism is available through concurrent authentication attempts.
+Don't use p > 1 unnecessarily.)
+
+Set t (time) to 0 to use the optimal running time for a given memory
+usage. This will allow you to maximize the memory usage (the value of
+N*r) while staying within your running time constraints. (Non-zero t
+makes sense in specialized cases where you can't afford higher memory
+usage but can afford more time.)
+
+Set g (upgrades) to 0 because there have been no hash upgrades yet.
+
+Set NROM (block count of ROM) to 0 unless you use a ROM (see below).
+NROM must be a power of two.
+
+
+ Password hashing for user authentication, no ROM.
+
+Small and fast (memory usage 2 MiB, performance like bcrypt cost 2^5 -
+latency 2-3 ms and throughput 10,000+ per second on a 16-core server):
+
+flags = YESCRYPT_DEFAULTS, N = 2048, r = 8, p = 1, t = 0, g = 0, NROM = 0
+
+Large and slow (memory usage 16 MiB, performance like bcrypt cost 2^8 -
+latency 10-30 ms and throughput 1000+ per second on a 16-core server):
+
+flags = YESCRYPT_DEFAULTS, N = 4096, r = 32, p = 1, t = 0, g = 0, NROM = 0
+
+Of course, even heavier and slower settings are possible, if affordable.
+Simply double the value of N as many times as needed. Since N must be a
+power of two, you may use r (in the range of 8 to 32) or/and t (in the
+range of 0 to 2) for fine-tuning the running time, but first bring N to
+the maximum you can afford. If this feels too complicated, just use one
+of the two parameter sets given above (preferably the second) as-is.
+
+
+ Password hashing for user authentication, with ROM.
+
+It's similar to the above, except that you need to adjust r, set NROM,
+and initialize the ROM.
+
+First decide on a ROM size, such as making it a large portion of your
+dedicated authentication servers' RAM sizes. Since NROM (block count)
+must be a power of two, you might need to choose r (block size) based on
+how your desired ROM size corresponds to a power of two. Also tuning
+for performance on current hardware, you'll likely end up with r in the
+range from slightly below 16 to 32. For example, to use 15/16 of a
+server's 256 GiB RAM as ROM (thus, making it 240 GiB), you could use
+r=15 or r=30. To use 23/24 of a server's 384 GiB RAM as ROM (thus,
+making it 368 GiB), you'd use r=23. Then set NROM to your desired ROM
+size in KiB divided by 128*r. Note that these examples might (or might
+not) be too extreme, leaving little memory for the rest of the system.
+You could as well opt for 7/8 with r=14 or 11/12 with r=11 or r=22.
+
+Note that higher r may make placing of ROM in e.g. NVMe flash memory
+instead of in RAM more reasonable (or less unreasonable) than it would
+have been with a lower r. If this is a concern as it relates to
+possible attacks and you do not intend to ever do it defensively, you
+might want to keep r lower (e.g., prefer r=15 over r=30 in the example
+above, even if 30 performs slightly faster).
+
+Your adjustments to r, if you deviate from powers of two, will also
+result in weirder memory usage per hash. Like 1.75 MiB at r=14 instead
+of 2 MiB at r=8 that you would have used without a ROM. That's OK.
+
+For ROM initialization, which you do with yescrypt_init_shared(), use
+the same r and NROM that you'd later use for password hashing, choose p
+based on your servers' physical and/or logical CPU count (maybe
+considering eventual upgrades as you won't be able to change this later,
+but without going unnecessarily high - e.g., p=28, p=56, or p=112 make
+sense on servers that currently have 28 physical / 56 logical CPUs), and
+set the rest of the parameters to:
+
+flags = YESCRYPT_DEFAULTS, N = 0, t = 0, g = 0
+
+N is set to 0 because it isn't relevant during ROM initialization (you
+can use different values of N for hashing passwords with the same ROM).
+
+To keep the ROM in e.g. SysV shared memory and reuse it across your
+authentication service restarts, you'd need to allocate the memory and
+set the flags to "YESCRYPT_DEFAULTS | YESCRYPT_SHARED_PREALLOCATED".
+
+For actual password hashing, you'd use your chosen values for N, r,
+NROM, and set the rest of the parameters to:
+
+flags = YESCRYPT_DEFAULTS, p = 1, t = 0, g = 0
+
+Note that although you'd use a large p for ROM initialization, you
+should use p=1 for actual password hashing like you would without a ROM.
+
+Do not forget to pass the ROM into the actual password hashing (and keep
+r and NROM set accordingly).
+
+Since N must be a power of two and r is dependent on ROM size, you may
+use t (in the range of 0 to 2) for fine-tuning the running time, but
+first bring N to the maximum you can afford.
+
+If this feels too complicated, or even if it doesn't, please consider
+engaging Openwall for your yescrypt deployment. We'd be happy to help.
+
+
+ Password-based key derivation.
+
+(Or rather passphrase-based.)
+
+Use settings similar to those for password hashing without a ROM, but
+adjusted for higher memory usage and running time, and optionally with
+thread-level parallelism.
+
+Small and fast (memory usage 128 MiB, running time under 100 ms on a
+fast desktop):
+
+flags = YESCRYPT_DEFAULTS, N = 32768, r = 32, p = 1, t = 0, g = 0, NROM = 0
+
+Large and fast (memory usage 1 GiB, running time under 200 ms on a fast
+quad-core desktop not including memory allocation overhead, under 250 ms
+with the overhead included), but requires build with OpenMP support (or
+otherwise will run as slow as yet be weaker than its p=1 alternative):
+
+flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 4, t = 0, g = 0, NROM = 0
+
+Large and slower (memory usage 1 GiB, running time under 300 ms on a
+fast quad-core desktop not including memory allocation overhead, under
+350 ms with the overhead included), also requires build with OpenMP
+support (or otherwise will run slower than the p=1 alternative below):
+
+flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 4, t = 2, g = 0, NROM = 0
+
+Large and slow (memory usage 1 GiB, running time under 600 ms on a fast
+desktop not including memory allocation overhead, under 650 ms with the
+overhead included):
+
+flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 1, t = 0, g = 0, NROM = 0
+
+Just like with password hashing, even heavier and slower settings are
+possible, if affordable, and you achieve them by adjusting N, r, t in
+the same way and in the same preferred ranges (please see the section on
+password hashing without a ROM, above). Unlike with password hashing,
+it makes some sense to go above t=2 if you expect that your users might
+not be able to afford more memory but can afford more time. However,
+increasing the memory usage provides better protection, and we don't
+recommend forcing your users to wait for more than 1 second as they
+could as well type more characters in that time. If this feels too
+complicated, just use one of the above parameter sets as-is.
+
+
+ Amortization of memory allocation overhead.
+
+It takes a significant fraction of yescrypt's total running time to
+allocate memory from the operating system, especially considering that
+the kernel zeroizes the memory before handing it over to your program.
+
+Unless you naturally need to compute yescrypt just once per process, you
+may achieve greater efficiency by fully using advanced yescrypt APIs
+that let you preserve and reuse the memory allocation across yescrypt
+invocations. This is done by reusing the structure pointed to by the
+"yescrypt_local_t *local" argument of yescrypt_r() or yescrypt_kdf()
+without calling yescrypt_free_local() inbetween the repeated invocations
+of yescrypt.
+
+
+ YESCRYPT_DEFAULTS macro.
+
+Please note that the value of the YESCRYPT_DEFAULTS macro might change
+later, so if you use the macro like it's recommended here then for
+results reproducible across versions you might need to store its value
+somewhere along with the hashes or the encrypted data.
+
+If you use yescrypt's standard hash string encoding, then yescrypt
+already encodes and decodes this value for you, so you don't need to
+worry about this.
diff --git a/libbb/yescrypt/alg-sha256.c b/libbb/yescrypt/alg-sha256.c
index 1ccffa1e5..25446406b 100644
--- a/libbb/yescrypt/alg-sha256.c
+++ b/libbb/yescrypt/alg-sha256.c
@@ -36,7 +36,7 @@ PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen,
uint64_t c, uint8_t *buf, size_t dkLen)
{
hmac_ctx_t Phctx, PShctx;
- size_t i;
+ uint32_t i;
/* Compute HMAC state after processing P. */
hmac_begin(&Phctx, passwd, passwdlen, sha256_begin);
@@ -46,7 +46,7 @@ PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen,
hmac_hash(&PShctx, salt, saltlen);
/* Iterate through the blocks. */
- for (i = 0; dkLen != 0; i++) {
+ for (i = 0; dkLen != 0; ) {
uint64_t U[32 / 8];
uint64_t T[32 / 8];
uint64_t j;
@@ -54,8 +54,9 @@ PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen,
size_t clen;
int k;
- /* Generate INT(i + 1). */
- ivec = SWAP_BE32((uint32_t)(i + 1));
+ /* Generate INT(i). */
+ i++;
+ ivec = SWAP_BE32(i);
/* Compute U_1 = PRF(P, S || INT(i)). */
hmac_peek_hash(&PShctx, (void*)T, &ivec, 4, NULL);
diff --git a/libbb/yescrypt/alg-yescrypt-common.c b/libbb/yescrypt/alg-yescrypt-common.c
index dfcf32145..5d8be587a 100644
--- a/libbb/yescrypt/alg-yescrypt-common.c
+++ b/libbb/yescrypt/alg-yescrypt-common.c
@@ -92,7 +92,7 @@ static const uint8_t *decode64(
store:
dbg_dec64(" storing bits:%d v:%08x", bits, (int)SWAP_BE32(value)); //BE to see lsb first
while (dstpos < *dstlen) {
- if (!(*src && *src != '$') && value == 0 && bits < 8) {
+ if ((!*src || *src == '$') && value == 0 && bits < 8) {
/* Example: mkpasswd PWD '$y$j9T$123':
* the "123" is bits:18 value:03,51,00
* is considered to be 2 bytes, not 3!
@@ -120,7 +120,6 @@ static const uint8_t *decode64(
break;
}
end:
- /* here, srclen is 0, no need to check */
*dstlen = dstpos;
dbg_dec64("dec64: OK, dst[%d]", (int)dstpos);
return src;
More information about the busybox-cvs
mailing list