Skip to content

Commit 1e20796

Browse files
nicstangeherbertx
authored andcommitted
crypto: dh - implement private key generation primitive for ffdheXYZ(dh)
The support for NVME in-band authentication currently in the works ([1]) needs to generate ephemeral DH keys for use with the RFC 7919 safe-prime FFDHE groups. In analogy to ECDH and its ecc_gen_privkey(), implement a dh_safe_prime_gen_privkey() and invoke it from the ffdheXYZ(dh) templates' common ->set_secret(), i.e. dh_safe_prime_set_secret(), in case the input ->key_size is zero. As the RFC 7919 FFDHE groups are classified as approved safe-prime groups by SP800-56Arev3, it's worthwhile to make the new dh_safe_prime_gen_privkey() to follow the approach specified in SP800-56Arev3, sec. 5.6.1.1.3 ("Key-Pair Generation Using Extra Random Bits") in order to achieve conformance. SP800-56Arev3 specifies a lower as well as an upper bound on the generated key's length: - it must be >= two times the maximum supported security strength of the group in question and - it must be <= the length of the domain parameter Q. For any safe-prime group Q = (P - 1)/2 by definition and the individual maximum supported security strengths as specified by SP800-56Arev3 have been made available as part of the FFDHE dh_safe_prime definitions introduced with a previous patch. Make dh_safe_prime_gen_privkey() pick twice the maximum supported strength rounded up to the next power of two for the output key size. This choice respects both, the lower and upper bounds given by SP800-90Arev3 for any of the approved safe-prime groups and is also in line with the NVME base spec 2.0, which requires the key size to be >= 256bits. [1] https://lore.kernel.org/r/[email protected] Signed-off-by: Nicolai Stange <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent 60a273e commit 1e20796

File tree

2 files changed

+138
-3
lines changed

2 files changed

+138
-3
lines changed

crypto/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ config CRYPTO_DH
234234
config CRYPTO_DH_RFC7919_GROUPS
235235
bool "Support for RFC 7919 FFDHE group parameters"
236236
depends on CRYPTO_DH
237+
select CRYPTO_RNG_DEFAULT
237238
help
238239
Provide support for RFC 7919 FFDHE group parameters. If unsure, say N.
239240

crypto/dh.c

Lines changed: 137 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <crypto/internal/kpp.h>
1111
#include <crypto/kpp.h>
1212
#include <crypto/dh.h>
13+
#include <crypto/rng.h>
1314
#include <linux/mpi.h>
1415

1516
struct dh_ctx {
@@ -315,14 +316,136 @@ static void dh_safe_prime_exit_tfm(struct crypto_kpp *tfm)
315316
crypto_free_kpp(tfm_ctx->dh_tfm);
316317
}
317318

319+
static u64 __add_u64_to_be(__be64 *dst, unsigned int n, u64 val)
320+
{
321+
unsigned int i;
322+
323+
for (i = n; val && i > 0; --i) {
324+
u64 tmp = be64_to_cpu(dst[i - 1]);
325+
326+
tmp += val;
327+
val = tmp >= val ? 0 : 1;
328+
dst[i - 1] = cpu_to_be64(tmp);
329+
}
330+
331+
return val;
332+
}
333+
334+
static void *dh_safe_prime_gen_privkey(const struct dh_safe_prime *safe_prime,
335+
unsigned int *key_size)
336+
{
337+
unsigned int n, oversampling_size;
338+
__be64 *key;
339+
int err;
340+
u64 h, o;
341+
342+
/*
343+
* Generate a private key following NIST SP800-56Ar3,
344+
* sec. 5.6.1.1.1 and 5.6.1.1.3 resp..
345+
*
346+
* 5.6.1.1.1: choose key length N such that
347+
* 2 * ->max_strength <= N <= log2(q) + 1 = ->p_size * 8 - 1
348+
* with q = (p - 1) / 2 for the safe-prime groups.
349+
* Choose the lower bound's next power of two for N in order to
350+
* avoid excessively large private keys while still
351+
* maintaining some extra reserve beyond the bare minimum in
352+
* most cases. Note that for each entry in safe_prime_groups[],
353+
* the following holds for such N:
354+
* - N >= 256, in particular it is a multiple of 2^6 = 64
355+
* bits and
356+
* - N < log2(q) + 1, i.e. N respects the upper bound.
357+
*/
358+
n = roundup_pow_of_two(2 * safe_prime->max_strength);
359+
WARN_ON_ONCE(n & ((1u << 6) - 1));
360+
n >>= 6; /* Convert N into units of u64. */
361+
362+
/*
363+
* Reserve one extra u64 to hold the extra random bits
364+
* required as per 5.6.1.1.3.
365+
*/
366+
oversampling_size = (n + 1) * sizeof(__be64);
367+
key = kmalloc(oversampling_size, GFP_KERNEL);
368+
if (!key)
369+
return ERR_PTR(-ENOMEM);
370+
371+
/*
372+
* 5.6.1.1.3, step 3 (and implicitly step 4): obtain N + 64
373+
* random bits and interpret them as a big endian integer.
374+
*/
375+
err = -EFAULT;
376+
if (crypto_get_default_rng())
377+
goto out_err;
378+
379+
err = crypto_rng_get_bytes(crypto_default_rng, (u8 *)key,
380+
oversampling_size);
381+
crypto_put_default_rng();
382+
if (err)
383+
goto out_err;
384+
385+
/*
386+
* 5.6.1.1.3, step 5 is implicit: 2^N < q and thus,
387+
* M = min(2^N, q) = 2^N.
388+
*
389+
* For step 6, calculate
390+
* key = (key[] mod (M - 1)) + 1 = (key[] mod (2^N - 1)) + 1.
391+
*
392+
* In order to avoid expensive divisions, note that
393+
* 2^N mod (2^N - 1) = 1 and thus, for any integer h,
394+
* 2^N * h mod (2^N - 1) = h mod (2^N - 1) always holds.
395+
* The big endian integer key[] composed of n + 1 64bit words
396+
* may be written as key[] = h * 2^N + l, with h = key[0]
397+
* representing the 64 most significant bits and l
398+
* corresponding to the remaining 2^N bits. With the remark
399+
* from above,
400+
* h * 2^N + l mod (2^N - 1) = l + h mod (2^N - 1).
401+
* As both, l and h are less than 2^N, their sum after
402+
* this first reduction is guaranteed to be <= 2^(N + 1) - 2.
403+
* Or equivalently, that their sum can again be written as
404+
* h' * 2^N + l' with h' now either zero or one and if one,
405+
* then l' <= 2^N - 2. Thus, all bits at positions >= N will
406+
* be zero after a second reduction:
407+
* h' * 2^N + l' mod (2^N - 1) = l' + h' mod (2^N - 1).
408+
* At this point, it is still possible that
409+
* l' + h' = 2^N - 1, i.e. that l' + h' mod (2^N - 1)
410+
* is zero. This condition will be detected below by means of
411+
* the final increment overflowing in this case.
412+
*/
413+
h = be64_to_cpu(key[0]);
414+
h = __add_u64_to_be(key + 1, n, h);
415+
h = __add_u64_to_be(key + 1, n, h);
416+
WARN_ON_ONCE(h);
417+
418+
/* Increment to obtain the final result. */
419+
o = __add_u64_to_be(key + 1, n, 1);
420+
/*
421+
* The overflow bit o from the increment is either zero or
422+
* one. If zero, key[1:n] holds the final result in big-endian
423+
* order. If one, key[1:n] is zero now, but needs to be set to
424+
* one, c.f. above.
425+
*/
426+
if (o)
427+
key[n] = cpu_to_be64(1);
428+
429+
/* n is in units of u64, convert to bytes. */
430+
*key_size = n << 3;
431+
/* Strip the leading extra __be64, which is (virtually) zero by now. */
432+
memmove(key, &key[1], *key_size);
433+
434+
return key;
435+
436+
out_err:
437+
kfree_sensitive(key);
438+
return ERR_PTR(err);
439+
}
440+
318441
static int dh_safe_prime_set_secret(struct crypto_kpp *tfm, const void *buffer,
319442
unsigned int len)
320443
{
321444
struct dh_safe_prime_instance_ctx *inst_ctx =
322445
dh_safe_prime_instance_ctx(tfm);
323446
struct dh_safe_prime_tfm_ctx *tfm_ctx = kpp_tfm_ctx(tfm);
324447
struct dh params;
325-
void *buf;
448+
void *buf = NULL, *key = NULL;
326449
unsigned int buf_size;
327450
int err;
328451

@@ -338,10 +461,20 @@ static int dh_safe_prime_set_secret(struct crypto_kpp *tfm, const void *buffer,
338461
params.g = safe_prime_g;
339462
params.g_size = sizeof(safe_prime_g);
340463

464+
if (!params.key_size) {
465+
key = dh_safe_prime_gen_privkey(inst_ctx->safe_prime,
466+
&params.key_size);
467+
if (IS_ERR(key))
468+
return PTR_ERR(key);
469+
params.key = key;
470+
}
471+
341472
buf_size = crypto_dh_key_len(&params);
342473
buf = kmalloc(buf_size, GFP_KERNEL);
343-
if (!buf)
344-
return -ENOMEM;
474+
if (!buf) {
475+
err = -ENOMEM;
476+
goto out;
477+
}
345478

346479
err = crypto_dh_encode_key(buf, buf_size, &params);
347480
if (err)
@@ -350,6 +483,7 @@ static int dh_safe_prime_set_secret(struct crypto_kpp *tfm, const void *buffer,
350483
err = crypto_kpp_set_secret(tfm_ctx->dh_tfm, buf, buf_size);
351484
out:
352485
kfree_sensitive(buf);
486+
kfree_sensitive(key);
353487
return err;
354488
}
355489

0 commit comments

Comments
 (0)