@@ -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_array(pk->x, ndigits, public_key, nbytes);
+ ecc_digits_to_array(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_array(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_array(public_key, nbytes, pk->x, ndigits);
+ ecc_digits_from_array(&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_array(product->x, ndigits, secret, nbytes);
err_validity:
memzero_explicit(priv, sizeof(priv));
@@ -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,9 +40,7 @@ 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;
-
- ecc_digits_from_array(params.key, nbytes, priv, ctx->ndigits);
+ ecc_digits_from_array(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,
@@ -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;
}
@@ -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
All curves supported so far provide digit arrays with ndigits to convert coordinates from and to. For NIST P521 only 8 digits and 2 bytes will be given per coordinate so that conversion from ndigits (= 9) does not work since some bytes are missing. Therefore, regard the input (and output) arrays as byte arrays that need to be converted to digits (from digits). Use ecc_digits_from array to convert a byte array to digits and ecc_digits_to_array to convert digits to a byte array. crypt_ecdh_shared_secret creates nbytes into a byte array from which to create rand_z from. The most significant digit of rand_z needs to be adjusted to mask out unnecessary bits beyond the 521 bits of the NIST P521 curve. Therefore, apply a mask to the most significant digit. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> --- crypto/ecc.c | 27 +++++++++++++++------------ crypto/ecdh.c | 24 ++++++++++++++---------- include/crypto/internal/ecc.h | 10 +++++++--- 3 files changed, 36 insertions(+), 25 deletions(-)