On Fri Mar 1, 2024 at 4:19 AM EET, Stefan Berger wrote: > 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. > > Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxx> > --- > crypto/ecdsa.c | 14 +++++++++----- > include/crypto/internal/ecc.h | 25 +++++++++++++++++++++++++ > 2 files changed, 34 insertions(+), 5 deletions(-) > > 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..48a04605da7f 100644 > --- a/include/crypto/internal/ecc.h > +++ b/include/crypto/internal/ecc.h > @@ -56,6 +56,31 @@ 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; > + size_t i; > + > + if (o == 0) { > + ecc_swap_digits(in, out, ndigits); > + } else { > + /* if key length is not a multiple of 64 bits (NIST P521) */ > + for (i = 0; i < o; i++) > + msd = (msd << 8) | in[i]; > + out[ndigits - 1] = msd; > + ecc_swap_digits(&in[o], out, (nbytes - o) >> 3); > + } https://lore.kernel.org/keyrings/CZIOY02QS2QC.LV0A0HNT7VKM@suppilovahvero/ BR, Jarkko