All curves supported so far provide full 64bit digit arrays to convert coordinates from and to. For NIST P521 only 8 digits and 2 bytes will be given per coordinate so that conversion from 9 digits does not work since some bytes are missing. Therefore, regard the input (output) arrays as byte arrays that need to be converted to digits (from digits). Use ecc_digits_from_bytes to convert a byte array to digits and ecc_digits_to_bytes to convert digits to a byte array. crypt_ecdh_shared_secret creates 'rand_z' from 'nbytes' of random bytes. Also convert this array to fill a byte array with 'nbytes' of random bytes and create the rand_z digits from the byte array. The most significant digit of rand_z needs to be adjusted to mask out unnecessary bits beyond the 521 bits of NIST P521. Therefore, apply the appropriate mask to the most significant digit keeping only the 9 most significant bits. Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxx> --- crypto/ecc.c | 27 +++++++++++++++------------ crypto/ecdh.c | 26 +++++++++++++++----------- include/crypto/internal/ecc.h | 10 +++++++--- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/crypto/ecc.c b/crypto/ecc.c index f643719450b8..ced77eb6e533 100644 --- a/crypto/ecc.c +++ b/crypto/ecc.c @@ -1542,7 +1542,8 @@ int ecc_gen_privkey(unsigned int curve_id, unsigned int ndigits, u64 *privkey) EXPORT_SYMBOL(ecc_gen_privkey); int ecc_make_pub_key(unsigned int curve_id, unsigned int ndigits, - const u64 *private_key, u64 *public_key) + const u64 *private_key, u8 *public_key, + unsigned int nbytes) { int ret = 0; struct ecc_point *pk; @@ -1570,8 +1571,8 @@ int ecc_make_pub_key(unsigned int curve_id, unsigned int ndigits, goto err_free_point; } - ecc_swap_digits(pk->x, public_key, ndigits); - ecc_swap_digits(pk->y, &public_key[ndigits], ndigits); + ecc_digits_to_bytes(pk->x, ndigits, public_key, nbytes); + ecc_digits_to_bytes(pk->y, ndigits, &public_key[nbytes], nbytes); err_free_point: ecc_free_point(pk); @@ -1641,14 +1642,14 @@ int ecc_is_pubkey_valid_full(const struct ecc_curve *curve, EXPORT_SYMBOL(ecc_is_pubkey_valid_full); int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits, - const u64 *private_key, const u64 *public_key, - u64 *secret) + const u64 *private_key, const u8 *public_key, + unsigned int nbytes, u8 *secret, u64 msd_mask) { int ret = 0; struct ecc_point *product, *pk; u64 priv[ECC_MAX_DIGITS]; u64 rand_z[ECC_MAX_DIGITS]; - unsigned int nbytes; + u8 tmp[ECC_MAX_DIGITS << ECC_DIGITS_TO_BYTES_SHIFT]; const struct ecc_curve *curve = ecc_get_curve(curve_id); if (!private_key || !public_key || !curve || @@ -1657,9 +1658,10 @@ int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits, goto out; } - nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT; - - get_random_bytes(rand_z, nbytes); + get_random_bytes(tmp, nbytes); + ecc_digits_from_bytes(tmp, nbytes, rand_z, ndigits); + if (msd_mask) + rand_z[ndigits - 1] &= msd_mask; pk = ecc_alloc_point(ndigits); if (!pk) { @@ -1667,8 +1669,9 @@ int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits, goto out; } - ecc_swap_digits(public_key, pk->x, ndigits); - ecc_swap_digits(&public_key[ndigits], pk->y, ndigits); + ecc_digits_from_bytes(public_key, nbytes, pk->x, ndigits); + ecc_digits_from_bytes(&public_key[nbytes], nbytes, pk->y, ndigits); + ret = ecc_is_pubkey_valid_partial(curve, pk); if (ret) goto err_alloc_product; @@ -1688,7 +1691,7 @@ int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits, goto err_validity; } - ecc_swap_digits(product->x, secret, ndigits); + ecc_digits_to_bytes(product->x, ndigits, secret, nbytes); err_validity: memzero_explicit(priv, sizeof(priv)); diff --git a/crypto/ecdh.c b/crypto/ecdh.c index f187365db7b6..e64133428552 100644 --- a/crypto/ecdh.c +++ b/crypto/ecdh.c @@ -15,6 +15,8 @@ struct ecdh_ctx { unsigned int curve_id; unsigned int ndigits; + unsigned int nbytes; + u64 msd_mask; u64 private_key[ECC_MAX_DIGITS]; }; @@ -28,7 +30,6 @@ static int ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, { struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); u64 priv[ECC_MAX_DIGITS]; - unsigned int nbytes; struct ecdh params; if (crypto_ecdh_decode_key(buf, len, ¶ms) < 0 || @@ -39,10 +40,8 @@ static int ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, return ecc_gen_privkey(ctx->curve_id, ctx->ndigits, ctx->private_key); - nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT; - - memcpy(ctx->private_key, params.key, nbytes); - ecc_swap_digits(ctx->private_key, priv, ctx->ndigits); + ecc_digits_from_bytes(params.key, ctx->nbytes, priv, ctx->ndigits); + ecc_swap_digits(priv, ctx->private_key, ctx->ndigits); if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits, priv, params.key_size) < 0) { @@ -56,13 +55,13 @@ static int ecdh_compute_value(struct kpp_request *req) { struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); - u64 *public_key; - u64 *shared_secret = NULL; + unsigned int nbytes = ctx->nbytes; + u8 *public_key; + u8 *shared_secret = NULL; void *buf; - size_t copied, nbytes, public_key_sz; + size_t copied, public_key_sz; int ret = -ENOMEM; - nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT; /* Public part is a point thus it has both coordinates */ public_key_sz = 2 * nbytes; @@ -91,12 +90,14 @@ static int ecdh_compute_value(struct kpp_request *req) ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits, ctx->private_key, public_key, - shared_secret); + nbytes, shared_secret, + ctx->msd_mask); buf = shared_secret; } else { ret = ecc_make_pub_key(ctx->curve_id, ctx->ndigits, - ctx->private_key, public_key); + ctx->private_key, public_key, + nbytes); buf = public_key; nbytes = public_key_sz; } @@ -134,6 +135,7 @@ static int ecdh_nist_p192_init_tfm(struct crypto_kpp *tfm) ctx->curve_id = ECC_CURVE_NIST_P192; ctx->ndigits = ECC_CURVE_NIST_P192_DIGITS; + ctx->nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT; return 0; } @@ -159,6 +161,7 @@ static int ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm) ctx->curve_id = ECC_CURVE_NIST_P256; ctx->ndigits = ECC_CURVE_NIST_P256_DIGITS; + ctx->nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT; return 0; } @@ -184,6 +187,7 @@ static int ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm) ctx->curve_id = ECC_CURVE_NIST_P384; ctx->ndigits = ECC_CURVE_NIST_P384_DIGITS; + ctx->nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT; return 0; } diff --git a/include/crypto/internal/ecc.h b/include/crypto/internal/ecc.h index 5d485d3221d3..328a82bd35c8 100644 --- a/include/crypto/internal/ecc.h +++ b/include/crypto/internal/ecc.h @@ -138,12 +138,14 @@ int ecc_gen_privkey(unsigned int curve_id, unsigned int ndigits, u64 *privkey); * @ndigits: curve's number of digits * @private_key: pregenerated private key for the given curve * @public_key: buffer for storing the generated public key + * @nbytes: number of bytes per coordinate of public key * * Returns 0 if the public key was generated successfully, a negative value * if an error occurred. */ int ecc_make_pub_key(const unsigned int curve_id, unsigned int ndigits, - const u64 *private_key, u64 *public_key); + const u64 *private_key, u8 *public_key, + unsigned int nbytes); /** * crypto_ecdh_shared_secret() - Compute a shared secret @@ -152,7 +154,9 @@ int ecc_make_pub_key(const unsigned int curve_id, unsigned int ndigits, * @ndigits: curve's number of digits * @private_key: private key of part A * @public_key: public key of counterpart B + * @nbytes: number of bytes per coordinate of public key * @secret: buffer for storing the calculated shared secret + * @msd_mask: optional mask to apply to the most significant digit * * Note: It is recommended that you hash the result of crypto_ecdh_shared_secret * before using it for symmetric encryption or HMAC. @@ -161,8 +165,8 @@ int ecc_make_pub_key(const unsigned int curve_id, unsigned int ndigits, * if an error occurred. */ int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits, - const u64 *private_key, const u64 *public_key, - u64 *secret); + const u64 *private_key, const u8 *public_key, + unsigned int nbytes, u8 *secret, u64 msd_mask); /** * ecc_is_pubkey_valid_partial() - Partial public key validation -- 2.43.0