diff mbox series

[v5,01/12] crypto: ecdsa - Convert byte arrays with key coordinates to digits

Message ID 20240306222257.979304-2-stefanb@linux.ibm.com (mailing list archive)
State Superseded
Delegated to: Herbert Xu
Headers show
Series Add support for NIST P521 to ecdsa | expand

Commit Message

Stefan Berger March 6, 2024, 10:22 p.m. UTC
For NIST P192/256/384 the public key's x and y parameters could be copied
directly from a given array since both parameters filled 'ndigits' of
digits (a 'digit' is a u64). For support of NIST P521 the key parameters
need to have leading zeros prepended to the most significant digit since
only 2 bytes of the most significant digit are provided.

Therefore, implement ecc_digits_from_bytes to convert a byte array into an
array of digits and use this function in ecdsa_set_pub_key where an input
byte array needs to be converted into digits.

Suggested-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Tested-by: Lukas Wunner <lukas@wunner.de>
---
 crypto/ecdsa.c                | 14 +++++++++-----
 include/crypto/internal/ecc.h | 21 +++++++++++++++++++++
 2 files changed, 30 insertions(+), 5 deletions(-)

Comments

Lukas Wunner March 8, 2024, 8:41 a.m. UTC | #1
On Wed, Mar 06, 2024 at 05:22:46PM -0500, Stefan Berger wrote:
> +static inline void ecc_digits_from_bytes(const u8 *in, unsigned int nbytes,
> +					 u64 *out, unsigned int ndigits)
> +{
> +	unsigned int o = nbytes & 7;
> +	u64 msd = 0;

My sincere apologies, I made a mistake when I proposed this:
It needs to be __be64 instead of u64...

> +
> +	if (o) {
> +		memcpy((u8 *)&msd + sizeof(msd) - o, in, o);
> +		out[--ndigits] = be64_to_cpu(msd);
> +		in += o;
> +	}

...otherwise sparse complains:

    crypto/ecdsa.c: note: in included file:
    >> include/crypto/internal/ecc.h:74:34: sparse: sparse: cast to restricted __be64
    >> include/crypto/internal/ecc.h:74:34: sparse: sparse: cast to restricted __be64
    [...]
    66	static inline void ecc_digits_from_bytes(const u8 *in, unsigned int nbytes,
    67						 u64 *out, unsigned int ndigits)
    68	{
    69		unsigned int o = nbytes & 7;
    70		u64 msd = 0;
    71	
    72		if (o) {
    73			memcpy((u8 *)&msd + sizeof(msd) - o, in, o);
  > 74			out[--ndigits] = be64_to_cpu(msd);
    75			in += o;
    76		}
    77		ecc_swap_digits(in, out, ndigits);
    78	}
    79	

0-day alerted me about this, it's monitoring my GitHub repo and
I've got your patches on one of my development branches.

Thanks,

Lukas
Stefan Berger March 8, 2024, 12:11 p.m. UTC | #2
On 3/8/24 03:41, Lukas Wunner wrote:
> On Wed, Mar 06, 2024 at 05:22:46PM -0500, Stefan Berger wrote:
>> +static inline void ecc_digits_from_bytes(const u8 *in, unsigned int nbytes,
>> +					 u64 *out, unsigned int ndigits)
>> +{
>> +	unsigned int o = nbytes & 7;
>> +	u64 msd = 0;
> 
> My sincere apologies, I made a mistake when I proposed this:
> It needs to be __be64 instead of u64...
> 
>> +
>> +	if (o) {
>> +		memcpy((u8 *)&msd + sizeof(msd) - o, in, o);
>> +		out[--ndigits] = be64_to_cpu(msd);
>> +		in += o;
>> +	}
> 
> ...otherwise sparse complains:
> 
>      crypto/ecdsa.c: note: in included file:
>      >> include/crypto/internal/ecc.h:74:34: sparse: sparse: cast to restricted __be64
>      >> include/crypto/internal/ecc.h:74:34: sparse: sparse: cast to restricted __be64
>      [...]
>      66	static inline void ecc_digits_from_bytes(const u8 *in, unsigned int nbytes,
>      67						 u64 *out, unsigned int ndigits)
>      68	{
>      69		unsigned int o = nbytes & 7;
>      70		u64 msd = 0;
>      71	
>      72		if (o) {
>      73			memcpy((u8 *)&msd + sizeof(msd) - o, in, o);
>    > 74			out[--ndigits] = be64_to_cpu(msd);
>      75			in += o;
>      76		}
>      77		ecc_swap_digits(in, out, ndigits);
>      78	}
>      79	
> 
> 0-day alerted me about this, it's monitoring my GitHub repo and
> I've got your patches on one of my development branches.

Thanks. Fixed.

> 
> Thanks,
> 
> Lukas
>
diff mbox series

Patch

diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c
index fbd76498aba8..6653dec17327 100644
--- a/crypto/ecdsa.c
+++ b/crypto/ecdsa.c
@@ -222,9 +222,8 @@  static int ecdsa_ecc_ctx_reset(struct ecc_ctx *ctx)
 static int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen)
 {
 	struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm);
+	unsigned int digitlen, ndigits;
 	const unsigned char *d = key;
-	const u64 *digits = (const u64 *)&d[1];
-	unsigned int ndigits;
 	int ret;
 
 	ret = ecdsa_ecc_ctx_reset(ctx);
@@ -238,12 +237,17 @@  static int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsig
 		return -EINVAL;
 
 	keylen--;
-	ndigits = (keylen >> 1) / sizeof(u64);
+	digitlen = keylen >> 1;
+
+	ndigits = DIV_ROUND_UP(digitlen, sizeof(u64));
 	if (ndigits != ctx->curve->g.ndigits)
 		return -EINVAL;
 
-	ecc_swap_digits(digits, ctx->pub_key.x, ndigits);
-	ecc_swap_digits(&digits[ndigits], ctx->pub_key.y, ndigits);
+	d++;
+
+	ecc_digits_from_bytes(d, digitlen, ctx->pub_key.x, ndigits);
+	ecc_digits_from_bytes(&d[digitlen], digitlen, ctx->pub_key.y, ndigits);
+
 	ret = ecc_is_pubkey_valid_full(ctx->curve, &ctx->pub_key);
 
 	ctx->pub_key_set = ret == 0;
diff --git a/include/crypto/internal/ecc.h b/include/crypto/internal/ecc.h
index 4f6c1a68882f..4a556b41873e 100644
--- a/include/crypto/internal/ecc.h
+++ b/include/crypto/internal/ecc.h
@@ -56,6 +56,27 @@  static inline void ecc_swap_digits(const void *in, u64 *out, unsigned int ndigit
 		out[i] = get_unaligned_be64(&src[ndigits - 1 - i]);
 }
 
+/**
+ * ecc_digits_from_bytes() - Create ndigits-sized digits array from byte array
+ * @in:       Input byte array
+ * @nbytes    Size of input byte array
+ * @out       Output digits array
+ * @ndigits:  Number of digits to create from byte array
+ */
+static inline void ecc_digits_from_bytes(const u8 *in, unsigned int nbytes,
+					 u64 *out, unsigned int ndigits)
+{
+	unsigned int o = nbytes & 7;
+	u64 msd = 0;
+
+	if (o) {
+		memcpy((u8 *)&msd + sizeof(msd) - o, in, o);
+		out[--ndigits] = be64_to_cpu(msd);
+		in += o;
+	}
+	ecc_swap_digits(in, out, ndigits);
+}
+
 /**
  * ecc_is_key_valid() - Validate a given ECDH private key
  *