2024-02-08 22:21:02

by Stefan Berger

[permalink] [raw]
Subject: [PATCH 00/14] Add support for NIST P521 to ecdsa and ecdh

This series of patches adds support for NIST P521 curve to ecdsa and
ecdh. Test cases are added to both modules.

An issue with the current code in ecdsa and ecdh is that it assumes that
input arrays providing key coordinates for example are arrays of digits
(a 'digit' is a 'u64'). This works well for existing curves, such as
NIST P192/256/384, but does not work for NIST P521 where coordinates
are 8 digits + 2 bytes long. So some of the changes deal with converting
byte arrays to digits and digits to byte array.

Regards,
Stefan

Stefan Berger (14):
crypto: ecdsa - Convert byte arrays with key coordinates to digits
crypto: ecdsa - Adjust tests on length of key material
crypto: ecdsa - Adjust res.x mod n for NIST P521
crypto: ecc - Implement vli_mmod_fast_521 for NIST p521
crypto: ecc - For NIST P521 use vli_num_bits to get number of bits
crypto: ecc - Add NIST P521 curve parameters
crypto: ecdsa - Register NIST P521 and extend test suite
x509: Add OID for NIST P521 and extend parser for it
crypto: ecdh - Use properly formatted digits to check for valid key
crypto: ecc - Implement ecc_digits_to_array to convert digits to byte
array
crypto: Add nbits field to ecc_curve structure
crypto: ecc - Implement and use ecc_curve_get_nbytes to get curve's
nbytes
crypto: ecdh - Use functions to copy digits from and to array
crypto: ecdh - Add support for NIST P521 and add test case

crypto/asymmetric_keys/x509_cert_parser.c | 3 +
crypto/ecc.c | 71 +++++--
crypto/ecc_curve_defs.h | 45 +++++
crypto/ecdh.c | 59 +++++-
crypto/ecdsa.c | 51 ++++-
crypto/testmgr.c | 14 ++
crypto/testmgr.h | 225 ++++++++++++++++++++++
include/crypto/ecc_curve.h | 3 +
include/crypto/ecdh.h | 1 +
include/crypto/internal/ecc.h | 61 +++++-
include/linux/oid_registry.h | 1 +
11 files changed, 497 insertions(+), 37 deletions(-)

--
2.43.0



2024-02-08 22:21:18

by Stefan Berger

[permalink] [raw]
Subject: [PATCH 13/14] crypto: ecdh - Use functions to copy digits from and to array

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 <[email protected]>
---
crypto/ecc.c | 27 +++++++++++++++------------
crypto/ecdh.c | 24 ++++++++++++++----------
include/crypto/internal/ecc.h | 10 +++++++---
3 files changed, 36 insertions(+), 25 deletions(-)

diff --git a/crypto/ecc.c b/crypto/ecc.c
index f643719450b8..e80ab4f3b5e1 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_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));
diff --git a/crypto/ecdh.c b/crypto/ecdh.c
index 83029233c03e..9f16dbef94d5 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, &params) < 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;
}
diff --git a/include/crypto/internal/ecc.h b/include/crypto/internal/ecc.h
index ba9ca0dcb971..29e899fcde8d 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


2024-02-08 22:21:27

by Stefan Berger

[permalink] [raw]
Subject: [PATCH 06/14] crypto: ecc - Add NIST P521 curve parameters

Add the parameters for the NIST P521 curve and define a new curve ID
for it. Make the curve available in ecc_get_curve.

Signed-off-by: Stefan Berger <[email protected]>
---
crypto/ecc.c | 2 ++
crypto/ecc_curve_defs.h | 44 +++++++++++++++++++++++++++++++++++++++++
include/crypto/ecdh.h | 1 +
3 files changed, 47 insertions(+)

diff --git a/crypto/ecc.c b/crypto/ecc.c
index 0734cea284a4..73fbbfc8d69c 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -60,6 +60,8 @@ const struct ecc_curve *ecc_get_curve(unsigned int curve_id)
return &nist_p256;
case ECC_CURVE_NIST_P384:
return &nist_p384;
+ case ECC_CURVE_NIST_P521:
+ return &nist_p521;
default:
return NULL;
}
diff --git a/crypto/ecc_curve_defs.h b/crypto/ecc_curve_defs.h
index 9719934c9428..93a47a5d460a 100644
--- a/crypto/ecc_curve_defs.h
+++ b/crypto/ecc_curve_defs.h
@@ -86,6 +86,50 @@ static struct ecc_curve nist_p384 = {
.b = nist_p384_b
};

+/* NIST P-521 */
+static u64 nist_p521_g_x[] = { 0xf97e7e31c2e5bd66ull, 0x3348b3c1856a429bull,
+ 0xfe1dc127a2ffa8deull, 0xa14b5e77efe75928ull,
+ 0xf828af606b4d3dbaull, 0x9c648139053fb521ull,
+ 0x9e3ecb662395b442ull, 0x858e06b70404e9cdull,
+ 0xc6ull };
+static u64 nist_p521_g_y[] = { 0x88be94769fd16650ull, 0x353c7086a272c240ull,
+ 0xc550b9013fad0761ull, 0x97ee72995ef42640ull,
+ 0x17afbd17273e662cull, 0x98f54449579b4468ull,
+ 0x5c8a5fb42c7d1bd9ull, 0x39296a789a3bc004ull,
+ 0x118ull };
+static u64 nist_p521_p[] = { 0xffffffffffffffffull, 0xffffffffffffffffull,
+ 0xffffffffffffffffull, 0xffffffffffffffffull,
+ 0xffffffffffffffffull, 0xffffffffffffffffull,
+ 0xffffffffffffffffull, 0xffffffffffffffffull,
+ 0x1ffull };
+static u64 nist_p521_n[] = { 0xbb6fb71e91386409ull, 0x3bb5c9b8899c47aeull,
+ 0x7fcc0148f709a5d0ull, 0x51868783bf2f966bull,
+ 0xfffffffffffffffaull, 0xffffffffffffffffull,
+ 0xffffffffffffffffull, 0xffffffffffffffffull,
+ 0x1ffull };
+static u64 nist_p521_a[] = { 0xfffffffffffffffcull, 0xffffffffffffffffull,
+ 0xffffffffffffffffull, 0xffffffffffffffffull,
+ 0xffffffffffffffffull, 0xffffffffffffffffull,
+ 0xffffffffffffffffull, 0xffffffffffffffffull,
+ 0x1ffull };
+static u64 nist_p521_b[] = { 0xef451fd46b503f00ull, 0x3573df883d2c34f1ull,
+ 0x1652c0bd3bb1bf07ull, 0x56193951ec7e937bull,
+ 0xb8b489918ef109e1ull, 0xa2da725b99b315f3ull,
+ 0x929a21a0b68540eeull, 0x953eb9618e1c9a1full,
+ 0x051ull };
+static struct ecc_curve nist_p521 = {
+ .name = "nist_521",
+ .g = {
+ .x = nist_p521_g_x,
+ .y = nist_p521_g_y,
+ .ndigits = 9,
+ },
+ .p = nist_p521_p,
+ .n = nist_p521_n,
+ .a = nist_p521_a,
+ .b = nist_p521_b
+};
+
/* curve25519 */
static u64 curve25519_g_x[] = { 0x0000000000000009, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000 };
diff --git a/include/crypto/ecdh.h b/include/crypto/ecdh.h
index a9f98078d29c..9784ecdd2fb4 100644
--- a/include/crypto/ecdh.h
+++ b/include/crypto/ecdh.h
@@ -26,6 +26,7 @@
#define ECC_CURVE_NIST_P192 0x0001
#define ECC_CURVE_NIST_P256 0x0002
#define ECC_CURVE_NIST_P384 0x0003
+#define ECC_CURVE_NIST_P521 0x0004

/**
* struct ecdh - define an ECDH private key
--
2.43.0


2024-02-08 22:21:21

by Stefan Berger

[permalink] [raw]
Subject: [PATCH 14/14] crypto: ecdh - Add support for NIST P521 and add test case

Implement ecdh support with NIST P521 and add a test case from RFC5903.

Signed-off-by: Stefan Berger <[email protected]>
---
crypto/ecdh.c | 34 +++++++++++++++
crypto/testmgr.c | 7 ++++
crypto/testmgr.h | 79 +++++++++++++++++++++++++++++++++++
include/crypto/internal/ecc.h | 1 +
4 files changed, 121 insertions(+)

diff --git a/crypto/ecdh.c b/crypto/ecdh.c
index 9f16dbef94d5..ed6c1eff83ce 100644
--- a/crypto/ecdh.c
+++ b/crypto/ecdh.c
@@ -207,6 +207,32 @@ static struct kpp_alg ecdh_nist_p384 = {
},
};

+static int ecdh_nist_p521_init_tfm(struct crypto_kpp *tfm)
+{
+ struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
+
+ ctx->curve_id = ECC_CURVE_NIST_P521;
+ ctx->ndigits = ECC_CURVE_NIST_P521_DIGITS;
+ ctx->nbytes = DIV_ROUND_UP(521, 8);
+ ctx->msd_mask = 0x1ff;
+
+ return 0;
+}
+static struct kpp_alg ecdh_nist_p521 = {
+ .set_secret = ecdh_set_secret,
+ .generate_public_key = ecdh_compute_value,
+ .compute_shared_secret = ecdh_compute_value,
+ .max_size = ecdh_max_size,
+ .init = ecdh_nist_p521_init_tfm,
+ .base = {
+ .cra_name = "ecdh-nist-p521",
+ .cra_driver_name = "ecdh-nist-p521-generic",
+ .cra_priority = 100,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct ecdh_ctx),
+ },
+};
+
static bool ecdh_nist_p192_registered;

static int __init ecdh_init(void)
@@ -225,8 +251,15 @@ static int __init ecdh_init(void)
if (ret)
goto nist_p384_error;

+ ret = crypto_register_kpp(&ecdh_nist_p521);
+ if (ret)
+ goto nist_p521_error;
+
return 0;

+nist_p521_error:
+ crypto_unregister_kpp(&ecdh_nist_p384);
+
nist_p384_error:
crypto_unregister_kpp(&ecdh_nist_p256);

@@ -242,6 +275,7 @@ static void __exit ecdh_exit(void)
crypto_unregister_kpp(&ecdh_nist_p192);
crypto_unregister_kpp(&ecdh_nist_p256);
crypto_unregister_kpp(&ecdh_nist_p384);
+ crypto_unregister_kpp(&ecdh_nist_p521);
}

subsys_initcall(ecdh_init);
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index a017b4ad119b..d1aa0b62f12d 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -5077,6 +5077,13 @@ static const struct alg_test_desc alg_test_descs[] = {
.suite = {
.kpp = __VECS(ecdh_p384_tv_template)
}
+ }, {
+ .alg = "ecdh-nist-p521",
+ .test = alg_test_kpp,
+ .fips_allowed = 1,
+ .suite = {
+ .kpp = __VECS(ecdh_p521_tv_template)
+ }
}, {
.alg = "ecdsa-nist-p192",
.test = alg_test_akcipher,
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 9bde04be8df9..dc9a2b30b5fd 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -4468,6 +4468,85 @@ static const struct kpp_testvec ecdh_p384_tv_template[] = {
}
};

+/*
+ * NIST P521 test vectors from RFC5903
+ */
+static const struct kpp_testvec ecdh_p521_tv_template[] = {
+ {
+ .secret =
+#ifdef __LITTLE_ENDIAN
+ "\x02\x00" /* type */
+ "\x48\x00" /* len */
+ "\x42\x00" /* key_size */
+#else
+ "\x00\x02" /* type */
+ "\x00\x48" /* len */
+ "\x00\x42" /* key_size */
+#endif
+ "\x00\x37\xAD\xE9\x31\x9A\x89\xF4"
+ "\xDA\xBD\xB3\xEF\x41\x1A\xAC\xCC"
+ "\xA5\x12\x3C\x61\xAC\xAB\x57\xB5"
+ "\x39\x3D\xCE\x47\x60\x81\x72\xA0"
+ "\x95\xAA\x85\xA3\x0F\xE1\xC2\x95"
+ "\x2C\x67\x71\xD9\x37\xBA\x97\x77"
+ "\xF5\x95\x7B\x26\x39\xBA\xB0\x72"
+ "\x46\x2F\x68\xC2\x7A\x57\x38\x2D"
+ "\x4A\x52",
+ .b_public =
+ "\x00\xD0\xB3\x97\x5A\xC4\xB7\x99"
+ "\xF5\xBE\xA1\x6D\x5E\x13\xE9\xAF"
+ "\x97\x1D\x5E\x9B\x98\x4C\x9F\x39"
+ "\x72\x8B\x5E\x57\x39\x73\x5A\x21"
+ "\x9B\x97\xC3\x56\x43\x6A\xDC\x6E"
+ "\x95\xBB\x03\x52\xF6\xBE\x64\xA6"
+ "\xC2\x91\x2D\x4E\xF2\xD0\x43\x3C"
+ "\xED\x2B\x61\x71\x64\x00\x12\xD9"
+ "\x46\x0F"
+ "\x01\x5C\x68\x22\x63\x83\x95\x6E"
+ "\x3B\xD0\x66\xE7\x97\xB6\x23\xC2"
+ "\x7C\xE0\xEA\xC2\xF5\x51\xA1\x0C"
+ "\x2C\x72\x4D\x98\x52\x07\x7B\x87"
+ "\x22\x0B\x65\x36\xC5\xC4\x08\xA1"
+ "\xD2\xAE\xBB\x8E\x86\xD6\x78\xAE"
+ "\x49\xCB\x57\x09\x1F\x47\x32\x29"
+ "\x65\x79\xAB\x44\xFC\xD1\x7F\x0F"
+ "\xC5\x6A",
+ .expected_a_public =
+ "\x00\x15\x41\x7E\x84\xDB\xF2\x8C"
+ "\x0A\xD3\xC2\x78\x71\x33\x49\xDC"
+ "\x7D\xF1\x53\xC8\x97\xA1\x89\x1B"
+ "\xD9\x8B\xAB\x43\x57\xC9\xEC\xBE"
+ "\xE1\xE3\xBF\x42\xE0\x0B\x8E\x38"
+ "\x0A\xEA\xE5\x7C\x2D\x10\x75\x64"
+ "\x94\x18\x85\x94\x2A\xF5\xA7\xF4"
+ "\x60\x17\x23\xC4\x19\x5D\x17\x6C"
+ "\xED\x3E"
+ "\x01\x7C\xAE\x20\xB6\x64\x1D\x2E"
+ "\xEB\x69\x57\x86\xD8\xC9\x46\x14"
+ "\x62\x39\xD0\x99\xE1\x8E\x1D\x5A"
+ "\x51\x4C\x73\x9D\x7C\xB4\xA1\x0A"
+ "\xD8\xA7\x88\x01\x5A\xC4\x05\xD7"
+ "\x79\x9D\xC7\x5E\x7B\x7D\x5B\x6C"
+ "\xF2\x26\x1A\x6A\x7F\x15\x07\x43"
+ "\x8B\xF0\x1B\xEB\x6C\xA3\x92\x6F"
+ "\x95\x82",
+ .expected_ss =
+ "\x01\x14\x4C\x7D\x79\xAE\x69\x56"
+ "\xBC\x8E\xDB\x8E\x7C\x78\x7C\x45"
+ "\x21\xCB\x08\x6F\xA6\x44\x07\xF9"
+ "\x78\x94\xE5\xE6\xB2\xD7\x9B\x04"
+ "\xD1\x42\x7E\x73\xCA\x4B\xAA\x24"
+ "\x0A\x34\x78\x68\x59\x81\x0C\x06"
+ "\xB3\xC7\x15\xA3\xA8\xCC\x31\x51"
+ "\xF2\xBE\xE4\x17\x99\x6D\x19\xF3"
+ "\xDD\xEA",
+ .secret_size = 72,
+ .b_public_size = 132,
+ .expected_a_public_size = 132,
+ .expected_ss_size = 66
+ }
+};
+
/*
* MD4 test vectors from RFC1320
*/
diff --git a/include/crypto/internal/ecc.h b/include/crypto/internal/ecc.h
index 29e899fcde8d..6e3e3eec0923 100644
--- a/include/crypto/internal/ecc.h
+++ b/include/crypto/internal/ecc.h
@@ -33,6 +33,7 @@
#define ECC_CURVE_NIST_P192_DIGITS 3
#define ECC_CURVE_NIST_P256_DIGITS 4
#define ECC_CURVE_NIST_P384_DIGITS 6
+#define ECC_CURVE_NIST_P521_DIGITS 9
#define ECC_MAX_DIGITS (576 / 64) /* due to NIST P521 */

#define ECC_DIGITS_TO_BYTES_SHIFT 3
--
2.43.0


2024-02-08 22:22:41

by Stefan Berger

[permalink] [raw]
Subject: [PATCH 12/14] crypto: ecc - Implement and use ecc_curve_get_nbytes to get curve's nbytes

Implement ecc_curve_get_nbytes to get a curve's number of bytes (nbytes).
The number of bytes can be derived from the nbits field of a curve, if
set, otherwise from the ndigits field.

Signed-off-by: Stefan Berger <[email protected]>
---
crypto/ecc.c | 6 ++----
include/crypto/internal/ecc.h | 11 +++++++++++
2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/crypto/ecc.c b/crypto/ecc.c
index 73fbbfc8d69c..f643719450b8 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -1478,10 +1478,8 @@ static int __ecc_is_key_valid(const struct ecc_curve *curve,
int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
const u64 *private_key, unsigned int private_key_len)
{
- int nbytes;
const struct ecc_curve *curve = ecc_get_curve(curve_id);
-
- nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+ int nbytes = ecc_curve_get_nbytes(curve);

if (private_key_len != nbytes)
return -EINVAL;
@@ -1506,7 +1504,7 @@ 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[ECC_MAX_DIGITS];
- unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+ unsigned int nbytes = ecc_curve_get_nbytes(curve);
unsigned int nbits = vli_num_bits(curve->n, ndigits);
int err;

diff --git a/include/crypto/internal/ecc.h b/include/crypto/internal/ecc.h
index 75ee113f58f9..ba9ca0dcb971 100644
--- a/include/crypto/internal/ecc.h
+++ b/include/crypto/internal/ecc.h
@@ -93,6 +93,17 @@ static inline void ecc_digits_to_array(const u64 *in, unsigned int ndigits,
memcpy(out, &tmp[o], nbytes);
}

+/**
+ * ecc_curve_get_nbytes() - Get the number of bytes the curve requires
+ * @curve: The curve
+ */
+static inline unsigned int ecc_curve_get_nbytes(const struct ecc_curve *curve)
+{
+ if (curve->nbits)
+ return DIV_ROUND_UP(curve->nbits, 8);
+ return curve->g.ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+}
+
/**
* ecc_is_key_valid() - Validate a given ECDH private key
*
--
2.43.0