From 5b0711d2627b048bc433c898d8bf185b416e356a Mon Sep 17 00:00:00 2001 From: jsing Date: Wed, 9 Nov 2022 17:39:29 +0000 Subject: [PATCH] Rework ED25519 API. BoringSSL implemented a compound private key, which includes a copy of the public key as a performance optimisation for signing. However, this does not readily match with how EVP works, makes the ED25519 API inconsistent with the X25519 API, diverges from th RFC and does not align with the OpenSSL API. Instead, the caller can readily compute the public key and pass this in to the signing process. ok tb@ --- lib/libcrypto/curve25519/curve25519.c | 51 +++++++++---------- lib/libcrypto/curve25519/curve25519.h | 28 +++++----- .../curve25519/curve25519_internal.h | 6 +-- 3 files changed, 40 insertions(+), 45 deletions(-) diff --git a/lib/libcrypto/curve25519/curve25519.c b/lib/libcrypto/curve25519/curve25519.c index 8d29379eb23..56373db923f 100644 --- a/lib/libcrypto/curve25519/curve25519.c +++ b/lib/libcrypto/curve25519/curve25519.c @@ -1,4 +1,4 @@ -/* $OpenBSD: curve25519.c,v 1.10 2022/11/08 17:07:17 jsing Exp $ */ +/* $OpenBSD: curve25519.c,v 1.11 2022/11/09 17:39:29 jsing Exp $ */ /* * Copyright (c) 2015, Google Inc. * @@ -4615,14 +4615,30 @@ sc_muladd(uint8_t *s, const uint8_t *a, const uint8_t *b, s[31] = s11 >> 17; } -void ED25519_keypair(uint8_t out_public_key[32], uint8_t out_private_key[64]) { - uint8_t seed[32]; - arc4random_buf(seed, 32); - ED25519_keypair_from_seed(out_public_key, out_private_key, seed); +void ED25519_public_from_private(uint8_t out_public_key[ED25519_PUBLIC_KEY_LENGTH], + const uint8_t private_key[ED25519_PRIVATE_KEY_LENGTH]) { + uint8_t az[SHA512_DIGEST_LENGTH]; + SHA512(private_key, 32, az); + + az[0] &= 248; + az[31] &= 63; + az[31] |= 64; + + ge_p3 A; + x25519_ge_scalarmult_base(&A, az); + ge_p3_tobytes(out_public_key, &A); +} + +void ED25519_keypair(uint8_t out_public_key[ED25519_PUBLIC_KEY_LENGTH], + uint8_t out_private_key[ED25519_PRIVATE_KEY_LENGTH]) { + arc4random_buf(out_private_key, 32); + + ED25519_public_from_private(out_public_key, out_private_key); } int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, - const uint8_t private_key[64]) { + const uint8_t public_key[ED25519_PUBLIC_KEY_LENGTH], + const uint8_t private_key[ED25519_PRIVATE_KEY_LENGTH]) { uint8_t az[SHA512_DIGEST_LENGTH]; SHA512(private_key, 32, az); @@ -4644,7 +4660,7 @@ int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, SHA512_Init(&hash_ctx); SHA512_Update(&hash_ctx, out_sig, 32); - SHA512_Update(&hash_ctx, private_key + 32, 32); + SHA512_Update(&hash_ctx, public_key, 32); SHA512_Update(&hash_ctx, message, message_len); uint8_t hram[SHA512_DIGEST_LENGTH]; SHA512_Final(hram, &hash_ctx); @@ -4656,7 +4672,8 @@ int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, } int ED25519_verify(const uint8_t *message, size_t message_len, - const uint8_t signature[64], const uint8_t public_key[32]) { + const uint8_t signature[ED25519_SIGNATURE_LENGTH], + const uint8_t public_key[ED25519_PUBLIC_KEY_LENGTH]) { ge_p3 A; if ((signature[63] & 224) != 0 || x25519_ge_frombytes_vartime(&A, public_key) != 0) { @@ -4692,24 +4709,6 @@ int ED25519_verify(const uint8_t *message, size_t message_len, return timingsafe_memcmp(rcheck, rcopy, sizeof(rcheck)) == 0; } -void ED25519_keypair_from_seed(uint8_t out_public_key[32], - uint8_t out_private_key[64], - const uint8_t seed[32]) { - uint8_t az[SHA512_DIGEST_LENGTH]; - SHA512(seed, 32, az); - - az[0] &= 248; - az[31] &= 63; - az[31] |= 64; - - ge_p3 A; - x25519_ge_scalarmult_base(&A, az); - ge_p3_tobytes(out_public_key, &A); - - memcpy(out_private_key, seed, 32); - memcpy(out_private_key + 32, out_public_key, 32); -} - /* Replace (f,g) with (g,f) if b == 1; * replace (f,g) with (f,g) if b == 0. * diff --git a/lib/libcrypto/curve25519/curve25519.h b/lib/libcrypto/curve25519/curve25519.h index 164f2e9e7f7..8b84c889cd2 100644 --- a/lib/libcrypto/curve25519/curve25519.h +++ b/lib/libcrypto/curve25519/curve25519.h @@ -1,4 +1,4 @@ -/* $OpenBSD: curve25519.h,v 1.4 2022/11/06 16:31:19 jsing Exp $ */ +/* $OpenBSD: curve25519.h,v 1.5 2022/11/09 17:39:29 jsing Exp $ */ /* * Copyright (c) 2015, Google Inc. * @@ -67,31 +67,27 @@ int X25519(uint8_t out_shared_key[X25519_KEY_LENGTH], * * Ed25519 is a signature scheme using a twisted Edwards curve that is * birationally equivalent to curve25519. - * - * Note that, unlike RFC 8032's formulation, our private key representation - * includes a public key suffix to make multiple key signing operations with the - * same key more efficient. The RFC 8032 private key is referred to in this - * implementation as the "seed" and is the first 32 bytes of our private key. */ -#define ED25519_PRIVATE_KEY_LEN 64 -#define ED25519_PUBLIC_KEY_LEN 32 -#define ED25519_SIGNATURE_LEN 64 +#define ED25519_PRIVATE_KEY_LENGTH 32 +#define ED25519_PUBLIC_KEY_LENGTH 32 +#define ED25519_SIGNATURE_LENGTH 64 /* * ED25519_keypair sets |out_public_key| and |out_private_key| to a freshly * generated, public/private key pair. */ -void ED25519_keypair(uint8_t out_public_key[ED25519_PUBLIC_KEY_LEN], - uint8_t out_private_key[ED25519_PRIVATE_KEY_LEN]); +void ED25519_keypair(uint8_t out_public_key[ED25519_PUBLIC_KEY_LENGTH], + uint8_t out_private_key[ED25519_PRIVATE_KEY_LENGTH]); /* * ED25519_sign sets |out_sig| to be a signature of |message_len| bytes from - * |message| using |private_key|. It returns one on success or zero on - * allocation failure. + * |message| using |public_key| and |private_key|. It returns one on success + * or zero on allocation failure. */ int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, - const uint8_t private_key[ED25519_PRIVATE_KEY_LEN]); + const uint8_t public_key[ED25519_PUBLIC_KEY_LENGTH], + const uint8_t private_key_seed[ED25519_PRIVATE_KEY_LENGTH]); /* * ED25519_verify returns one iff |signature| is a valid signature by @@ -99,8 +95,8 @@ int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len, * otherwise. */ int ED25519_verify(const uint8_t *message, size_t message_len, - const uint8_t signature[ED25519_SIGNATURE_LEN], - const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]); + const uint8_t signature[ED25519_SIGNATURE_LENGTH], + const uint8_t public_key[ED25519_PUBLIC_KEY_LENGTH]); #endif #if defined(__cplusplus) diff --git a/lib/libcrypto/curve25519/curve25519_internal.h b/lib/libcrypto/curve25519/curve25519_internal.h index 9d2ee9b4d7f..0a987816512 100644 --- a/lib/libcrypto/curve25519/curve25519_internal.h +++ b/lib/libcrypto/curve25519/curve25519_internal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: curve25519_internal.h,v 1.4 2022/11/08 17:07:17 jsing Exp $ */ +/* $OpenBSD: curve25519_internal.h,v 1.5 2022/11/09 17:39:29 jsing Exp $ */ /* * Copyright (c) 2015, Google Inc. * @@ -94,8 +94,8 @@ void x25519_scalar_mult(uint8_t out[32], const uint8_t scalar[32], void x25519_scalar_mult_generic(uint8_t out[32], const uint8_t scalar[32], const uint8_t point[32]); -void ED25519_keypair_from_seed(uint8_t out_public_key[32], - uint8_t out_private_key[64], const uint8_t seed[32]); +void ED25519_public_from_private(uint8_t out_public_key[32], + const uint8_t private_key[32]); __END_HIDDEN_DECLS -- 2.20.1