summaryrefslogtreecommitdiff
path: root/crypto/ecc.c
diff options
context:
space:
mode:
authorTudor-Dan Ambarus <tudor.ambarus@microchip.com>2017-05-30 17:52:48 +0300
committerHerbert Xu <herbert@gondor.apana.org.au>2017-06-10 07:04:35 +0300
commit6755fd269d5c100b0eca420db501ae58435efd6e (patch)
tree647d5f929f4ebb6a50eae63afc645cae32fa9f4a /crypto/ecc.c
parentf2663872f073c874495b793721a47cc7f30eaec7 (diff)
downloadlinux-6755fd269d5c100b0eca420db501ae58435efd6e.tar.xz
crypto: ecdh - add privkey generation support
Add support for generating ecc private keys. Generation of ecc private keys is helpful in a user-space to kernel ecdh offload because the keys are not revealed to user-space. Private key generation is also helpful to implement forward secrecy. If the user provides a NULL ecc private key, the kernel will generate it and further use it for ecdh. Move ecdh's object files below drbg's. drbg must be present in the kernel at the time of calling. Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com> Reviewed-by: Stephan Müller <smueller@chronox.de> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/ecc.c')
-rw-r--r--crypto/ecc.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/crypto/ecc.c b/crypto/ecc.c
index 6c33c4323d6a..633a9bcdc574 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -29,6 +29,7 @@
#include <linux/swab.h>
#include <linux/fips.h>
#include <crypto/ecdh.h>
+#include <crypto/rng.h>
#include "ecc.h"
#include "ecc_curve_defs.h"
@@ -927,6 +928,61 @@ int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
return 0;
}
+/*
+ * ECC private keys are generated using the method of extra random bits,
+ * equivalent to that described in FIPS 186-4, Appendix B.4.1.
+ *
+ * d = (c mod(n–1)) + 1 where c is a string of random bits, 64 bits longer
+ * than requested
+ * 0 <= c mod(n-1) <= n-2 and implies that
+ * 1 <= d <= n-1
+ *
+ * This method generates a private key uniformly distributed in the range
+ * [1, n-1].
+ */
+int ecc_gen_privkey(unsigned int curve_id, unsigned int ndigits, u64 *privkey)
+{
+ const struct ecc_curve *curve = ecc_get_curve(curve_id);
+ u64 priv[ndigits];
+ unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+ unsigned int nbits = vli_num_bits(curve->n, ndigits);
+ int err;
+
+ /* Check that N is included in Table 1 of FIPS 186-4, section 6.1.1 */
+ if (nbits < 160)
+ return -EINVAL;
+
+ /*
+ * FIPS 186-4 recommends that the private key should be obtained from a
+ * RBG with a security strength equal to or greater than the security
+ * strength associated with N.
+ *
+ * The maximum security strength identified by NIST SP800-57pt1r4 for
+ * ECC is 256 (N >= 512).
+ *
+ * This condition is met by the default RNG because it selects a favored
+ * DRBG with a security strength of 256.
+ */
+ if (crypto_get_default_rng())
+ err = -EFAULT;
+
+ err = crypto_rng_get_bytes(crypto_default_rng, (u8 *)priv, nbytes);
+ crypto_put_default_rng();
+ if (err)
+ return err;
+
+ if (vli_is_zero(priv, ndigits))
+ return -EINVAL;
+
+ /* Make sure the private key is in the range [1, n-1]. */
+ if (vli_cmp(curve->n, priv, ndigits) != 1)
+ return -EINVAL;
+
+ ecc_swap_digits(priv, privkey, ndigits);
+
+ return 0;
+}
+
int ecc_make_pub_key(unsigned int curve_id, unsigned int ndigits,
const u64 *private_key, u64 *public_key)
{