chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1,613 @@
// Copyright (c) 2020, Google Inc.
// SPDX-License-Identifier: ISC
// Some of this code is taken from the ref10 version of Ed25519 in SUPERCOP
// 20141124 (http://bench.cr.yp.to/supercop.html). That code is released as
// public domain. Other parts have been replaced to call into code generated by
// Fiat (https://github.com/mit-plv/fiat-crypto) in //third_party/fiat.
//
// The field functions are shared by Ed25519 and X25519 where possible.
#include <openssl/curve25519.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include "../../internal.h"
#include "../cpucap/internal.h"
#include "internal.h"
const uint8_t RFC8032_DOM2_PREFIX[DOM2_PREFIX_SIZE] = {
'S', 'i', 'g', 'E', 'd', '2', '5', '5', '1', '9', ' ',
'n', 'o', ' ', 'E', 'd', '2', '5', '5', '1', '9', ' ',
'c', 'o', 'l', 'l', 'i', 's', 'i', 'o', 'n', 's'};
// X25519 [1] and Ed25519 [2] is an ECDHE protocol and signature scheme,
// respectively. This file contains an implementation of both using two
// different backends:
// 1) One backend is a pure C backend that should work on any platform.
// 2) The other backend is machine-optimized using s2n-bignum [3] as backend.
//
// [1]: https://datatracker.ietf.org/doc/html/rfc7748
// [2]: https://datatracker.ietf.org/doc/html/rfc8032
// [3]: https://github.com/awslabs/s2n-bignum
//
// "Clamping":
// Both X25519 and Ed25519 contain "clamping" steps; bit-twiddling, masking or
// setting specific bits. Generally, the bit-twiddling is to avoid common
// implementation errors and weak instances. Details can be found through the
// following two references:
// * https://mailarchive.ietf.org/arch/msg/cfrg/pt2bt3fGQbNF8qdEcorp-rJSJrc/
// * https://neilmadden.blog/2020/05/28/whats-the-curve25519-clamping-all-about
//
// Ed25519 domain and pre-hash functions:
// For Ed25519, dom2(F,C) is the empty string and PH the identify function,
// cf. rfc8032 5.1.
void ed25519_sha512(uint8_t out[SHA512_DIGEST_LENGTH], const void *input1,
size_t len1, const void *input2, size_t len2,
const void *input3, size_t len3, const void *input4,
size_t len4) {
SHA512_CTX hash_ctx;
SHA512_Init(&hash_ctx);
SHA512_Update(&hash_ctx, input1, len1);
SHA512_Update(&hash_ctx, input2, len2);
if (len3 != 0) {
SHA512_Update(&hash_ctx, input3, len3);
}
if (len4 != 0) {
SHA512_Update(&hash_ctx, input4, len4);
}
SHA512_Final(out, &hash_ctx);
}
// Public interface functions
void ED25519_keypair_from_seed(uint8_t out_public_key[ED25519_PUBLIC_KEY_LEN],
uint8_t out_private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t seed[ED25519_SEED_LEN]) {
// ED25519_keypair already ensures this with the same check, and is also the
// function that is approved for FIPS (sets the indicator). Ensuring it here
// for brevity.
boringssl_ensure_eddsa_self_test();
// Step: rfc8032 5.1.5.1
// Compute SHA512(seed).
uint8_t az[SHA512_DIGEST_LENGTH];
SHA512(seed, ED25519_SEED_LEN, az);
// Step: rfc8032 5.1.5.2
az[0] &= 248; // 11111000_2
az[31] &= 127; // 01111111_2
az[31] |= 64; // 01000000_2
// Step: rfc8032 5.1.5.[3,4]
// Compute [az]B and encode public key to a 32 byte octet.
#if defined(CURVE25519_S2N_BIGNUM_CAPABLE)
ed25519_public_key_from_hashed_seed_s2n_bignum(out_public_key, az);
#else
ed25519_public_key_from_hashed_seed_nohw(out_public_key, az);
#endif
// Encoded public key is a suffix in the private key. Avoids having to
// generate the public key from the private key when signing.
OPENSSL_STATIC_ASSERT(ED25519_PRIVATE_KEY_LEN == (ED25519_SEED_LEN + ED25519_PUBLIC_KEY_LEN), ed25519_parameter_length_mismatch)
OPENSSL_memcpy(out_private_key, seed, ED25519_SEED_LEN);
OPENSSL_memcpy(out_private_key + ED25519_SEED_LEN, out_public_key,
ED25519_PUBLIC_KEY_LEN);
OPENSSL_cleanse(az, sizeof(az));
}
static int ed25519_keypair_pct(uint8_t public_key[ED25519_PUBLIC_KEY_LEN],
uint8_t private_key[ED25519_PRIVATE_KEY_LEN]) {
#if defined(AWSLC_FIPS)
uint8_t msg[16] = {16};
uint8_t out_sig[ED25519_SIGNATURE_LEN];
if (ED25519_sign_no_self_test(out_sig, msg, 16, private_key) != 1) {
// This should never happen and static analysis will say that ED25519_sign_no_self_test
// always returns 1
AWS_LC_FIPS_failure("Ed25519 keygen PCT failed");
return 0;
}
if (boringssl_fips_break_test("EDDSA_PWCT")) {
msg[0] = ~msg[0];
}
if (ED25519_verify_no_self_test(msg, 16, out_sig, public_key) != 1) {
AWS_LC_FIPS_failure("Ed25519 keygen PCT failed");
return 0;
}
#endif
return 1;
}
int ED25519_keypair_internal(uint8_t out_public_key[ED25519_PUBLIC_KEY_LEN],
uint8_t out_private_key[ED25519_PRIVATE_KEY_LEN]) {
// We have to avoid the self tests and digest function in ed25519_keypair_pct
// from updating the service indicator.
FIPS_service_indicator_lock_state();
boringssl_ensure_eddsa_self_test();
SET_DIT_AUTO_RESET;
// Ed25519 key generation: rfc8032 5.1.5
// Private key is 32 octets of random data.
uint8_t seed[ED25519_SEED_LEN];
AWSLC_ABORT_IF_NOT_ONE(RAND_bytes(seed, ED25519_SEED_LEN));
// Public key generation is handled in a separate function. See function
// description why this is useful.
ED25519_keypair_from_seed(out_public_key, out_private_key, seed);
OPENSSL_cleanse(seed, ED25519_SEED_LEN);
int result = ed25519_keypair_pct(out_public_key, out_private_key);
FIPS_service_indicator_unlock_state();
if (result) {
FIPS_service_indicator_update_state();
}
return result;
}
void ED25519_keypair(uint8_t out_public_key[ED25519_PUBLIC_KEY_LEN],
uint8_t out_private_key[ED25519_PRIVATE_KEY_LEN]) {
// The existing public function is void, ED25519_keypair_internal can only
// fail if the PWCT fails and we're in a callback build where AWS_LC_FIPS_failure
// doesn't abort on FIPS failure.
AWSLC_ASSERT(ED25519_keypair_internal(out_public_key, out_private_key));
}
int ED25519_sign(uint8_t out_sig[ED25519_SIGNATURE_LEN],
const uint8_t *message, size_t message_len,
const uint8_t private_key[ED25519_PRIVATE_KEY_LEN]) {
FIPS_service_indicator_lock_state();
boringssl_ensure_eddsa_self_test();
int res =
ED25519_sign_no_self_test(out_sig, message, message_len, private_key);
FIPS_service_indicator_unlock_state();
if (res) {
FIPS_service_indicator_update_state();
}
return res;
}
int ED25519_sign_no_self_test(
uint8_t out_sig[ED25519_SIGNATURE_LEN], const uint8_t *message,
size_t message_len, const uint8_t private_key[ED25519_PRIVATE_KEY_LEN]) {
return ed25519_sign_internal(ED25519_ALG, out_sig, message, message_len,
private_key, NULL, 0);
}
static int dom2(ed25519_algorithm_t alg, uint8_t buffer[MAX_DOM2_SIZE],
size_t *buffer_len, const uint8_t *context,
size_t context_len) {
GUARD_PTR(buffer_len);
*buffer_len = 0;
uint8_t phflag = 0;
switch (alg) {
case ED25519_ALG:
// Per rfc8032:
// For Ed25519, dom2(f,c) is the empty string. The phflag value is
// irrelevant. The context (if present at all) MUST be empty.
return context_len == 0;
case ED25519CTX_ALG:
// Per rfc8032:
// For Ed25519ctx, phflag=0. The context input SHOULD NOT be empty.
if (context_len == 0) {
return 0;
}
phflag = 0;
break;
case ED25519PH_ALG:
// For Ed25519ph, phflag=1
phflag = 1;
break;
default:
// Should never happen unless we missed a ed25519_algorithm_t enum variant
// case in this switch statement
abort();
}
OPENSSL_memcpy(buffer, RFC8032_DOM2_PREFIX, DOM2_PREFIX_SIZE);
buffer[DOM2_F_OFFSET] = phflag;
buffer[DOM2_C_OFFSET] = context_len;
if (context_len > 0) {
GUARD_PTR(context);
if (context_len > MAX_DOM2_CONTEXT_SIZE) {
return 0;
}
OPENSSL_memcpy(&buffer[DOM2_CONTEXT_OFFSET], context, context_len);
}
*buffer_len = DOM2_PREFIX_SIZE + DOM2_F_SIZE + DOM2_C_SIZE + context_len;
return 1;
}
int ed25519_sign_internal(
ed25519_algorithm_t alg,
uint8_t out_sig[ED25519_SIGNATURE_LEN],
const uint8_t *message, size_t message_len,
const uint8_t private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t *ctx, size_t ctx_len) {
// NOTE: The documentation on this function says that it returns zero on
// allocation failure. While that can't happen with the current
// implementation, we want to reserve the ability to allocate in this
// implementation in the future.
if (alg == ED25519PH_ALG &&
message_len != SHA512_DIGEST_LENGTH) {
OPENSSL_PUT_ERROR(CRYPTO, ERR_R_CRYPTO_LIB);
return 0;
}
// Ed25519 sign: rfc8032 5.1.6
//
// Step: rfc8032 5.1.6.1
// This step is a repeat of rfc8032 5.1.5.[1,2].
// seed = private_key[0:31]
// A = private_key[32:61] (per 5.1.5.4)
// Compute az = SHA512(seed).
SET_DIT_AUTO_RESET;
uint8_t az[SHA512_DIGEST_LENGTH];
SHA512(private_key, ED25519_PRIVATE_KEY_SEED_LEN, az);
// s = az[0:31]
// prefix = az[32:61]
az[0] &= 248; // 11111000_2
az[31] &= 63; // 00111111_2
az[31] |= 64; // 01000000_2
uint8_t r[SHA512_DIGEST_LENGTH];
uint8_t dom2_buffer[MAX_DOM2_SIZE] = {0};
size_t dom2_buffer_len = 0;
if (!dom2(alg, dom2_buffer, &dom2_buffer_len, ctx, ctx_len)) {
OPENSSL_PUT_ERROR(CRYPTO, ERR_R_CRYPTO_LIB);
OPENSSL_cleanse(az, sizeof(az));
return 0;
}
// Step: rfc8032 5.1.6.2
if (dom2_buffer_len > 0) {
// Compute r = SHA512(dom2(phflag, context) || prefix || message).
ed25519_sha512(r, dom2_buffer, dom2_buffer_len,
az + ED25519_PRIVATE_KEY_SEED_LEN,
ED25519_PRIVATE_KEY_SEED_LEN, message, message_len, NULL, 0);
} else {
// Compute r = SHA512(prefix || message).
ed25519_sha512(r, az + ED25519_PRIVATE_KEY_SEED_LEN,
ED25519_PRIVATE_KEY_SEED_LEN, message, message_len, NULL, 0,
NULL, 0);
}
// Step: rfc8032 5.1.6.[3,5,6,7]
#if defined(CURVE25519_S2N_BIGNUM_CAPABLE)
ed25519_sign_s2n_bignum(out_sig, r, az,
private_key + ED25519_PRIVATE_KEY_SEED_LEN, message,
message_len, dom2_buffer, dom2_buffer_len);
#else
ed25519_sign_nohw(out_sig, r, az, private_key + ED25519_PRIVATE_KEY_SEED_LEN,
message, message_len, dom2_buffer, dom2_buffer_len);
#endif
// The signature is computed from the private key, but is public.
CONSTTIME_DECLASSIFY(out_sig, 64);
OPENSSL_cleanse(az, sizeof(az));
OPENSSL_cleanse(r, sizeof(r));
return 1;
}
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]) {
FIPS_service_indicator_lock_state();
boringssl_ensure_eddsa_self_test();
int res =
ED25519_verify_no_self_test(message, message_len, signature, public_key);
FIPS_service_indicator_unlock_state();
if(res) {
FIPS_service_indicator_update_state();
}
return res;
}
int ED25519_verify_no_self_test(
const uint8_t *message, size_t message_len,
const uint8_t signature[ED25519_SIGNATURE_LEN],
const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]) {
return ed25519_verify_internal(ED25519_ALG, message, message_len, signature,
public_key, NULL, 0);
}
int ED25519ctx_sign(uint8_t out_sig[ED25519_SIGNATURE_LEN],
const uint8_t *message, size_t message_len,
const uint8_t private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t *context, size_t context_len) {
FIPS_service_indicator_lock_state();
boringssl_ensure_eddsa_self_test();
int res = ED25519ctx_sign_no_self_test(out_sig, message, message_len,
private_key, context, context_len);
FIPS_service_indicator_unlock_state();
return res;
}
int ED25519ctx_sign_no_self_test(
uint8_t out_sig[ED25519_SIGNATURE_LEN], const uint8_t *message,
size_t message_len, const uint8_t private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t *context, size_t context_len) {
return ed25519_sign_internal(ED25519CTX_ALG, out_sig, message, message_len,
private_key, context, context_len);
}
int ED25519ctx_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 *context, size_t context_len) {
FIPS_service_indicator_lock_state();
boringssl_ensure_eddsa_self_test();
int res = ED25519ctx_verify_no_self_test(message, message_len, signature,
public_key, context, context_len);
FIPS_service_indicator_unlock_state();
return res;
}
int ED25519ctx_verify_no_self_test(
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 *context,
size_t context_len) {
return ed25519_verify_internal(ED25519CTX_ALG, message, message_len,
signature, public_key, context, context_len);
}
int ED25519ph_sign(uint8_t out_sig[ED25519_SIGNATURE_LEN],
const uint8_t *message, size_t message_len,
const uint8_t private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t *context, size_t context_len) {
FIPS_service_indicator_lock_state();
boringssl_ensure_hasheddsa_self_test();
int res = ED25519ph_sign_no_self_test(out_sig, message, message_len,
private_key, context, context_len);
FIPS_service_indicator_unlock_state();
if (res) {
FIPS_service_indicator_update_state();
}
return res;
}
int ED25519ph_sign_no_self_test(
uint8_t out_sig[ED25519_SIGNATURE_LEN], const uint8_t *message,
size_t message_len, const uint8_t private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t *context, size_t context_len) {
uint8_t digest[SHA512_DIGEST_LENGTH] = {0};
SHA512_CTX ctx;
SHA512_Init(&ctx);
SHA512_Update(&ctx, message, message_len);
SHA512_Final(digest, &ctx);
return ED25519ph_sign_digest_no_self_test(out_sig, digest, private_key,
context, context_len);
}
int ED25519ph_sign_digest(uint8_t out_sig[ED25519_SIGNATURE_LEN],
const uint8_t digest[SHA512_DIGEST_LENGTH],
const uint8_t private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t *context, size_t context_len) {
FIPS_service_indicator_lock_state();
boringssl_ensure_hasheddsa_self_test();
int res = ED25519ph_sign_digest_no_self_test(out_sig, digest, private_key,
context, context_len);
FIPS_service_indicator_unlock_state();
if (res) {
FIPS_service_indicator_update_state();
}
return res;
}
int ED25519ph_sign_digest_no_self_test(
uint8_t out_sig[ED25519_SIGNATURE_LEN],
const uint8_t digest[SHA512_DIGEST_LENGTH],
const uint8_t private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t *context, size_t context_len) {
return ed25519_sign_internal(ED25519PH_ALG, out_sig, digest,
SHA512_DIGEST_LENGTH, private_key, context,
context_len);
}
int ED25519ph_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 *context, size_t context_len) {
FIPS_service_indicator_lock_state();
boringssl_ensure_hasheddsa_self_test();
int res = ED25519ph_verify_no_self_test(message, message_len, signature,
public_key, context, context_len);
FIPS_service_indicator_unlock_state();
if (res) {
FIPS_service_indicator_update_state();
}
return res;
}
int ED25519ph_verify_no_self_test(
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 *context,
size_t context_len) {
uint8_t digest[SHA512_DIGEST_LENGTH] = {0};
SHA512_CTX ctx;
SHA512_Init(&ctx);
SHA512_Update(&ctx, message, message_len);
SHA512_Final(digest, &ctx);
return ED25519ph_verify_digest_no_self_test(digest, signature, public_key,
context, context_len);
}
int ED25519ph_verify_digest(const uint8_t digest[SHA512_DIGEST_LENGTH],
const uint8_t signature[ED25519_SIGNATURE_LEN],
const uint8_t public_key[ED25519_PUBLIC_KEY_LEN],
const uint8_t *context, size_t context_len) {
FIPS_service_indicator_lock_state();
boringssl_ensure_hasheddsa_self_test();
int res = ED25519ph_verify_digest_no_self_test(
digest, signature, public_key, context, context_len);
FIPS_service_indicator_unlock_state();
if(res) {
FIPS_service_indicator_update_state();
}
return res;
}
int ED25519ph_verify_digest_no_self_test(
const uint8_t digest[SHA512_DIGEST_LENGTH],
const uint8_t signature[ED25519_SIGNATURE_LEN],
const uint8_t public_key[ED25519_PUBLIC_KEY_LEN], const uint8_t *context,
size_t context_len) {
return ed25519_verify_internal(ED25519PH_ALG, digest,
SHA512_DIGEST_LENGTH, signature, public_key,
context, context_len);
}
int ed25519_verify_internal(
ed25519_algorithm_t alg,
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 *ctx, size_t ctx_len) {
// Ed25519 verify: rfc8032 5.1.7
if (alg == ED25519PH_ALG &&
message_len != SHA512_DIGEST_LENGTH) {
OPENSSL_PUT_ERROR(CRYPTO, ERR_R_CRYPTO_LIB);
return 0;
}
// Step: rfc8032 5.1.7.1 (up to decoding the public key)
// Decode signature as:
// - signature[0:31]: encoded point R, aliased to R_expected.
// - signature[32:61]: integer S.
uint8_t R_expected[32];
OPENSSL_memcpy(R_expected, signature, 32);
uint8_t S[32];
OPENSSL_memcpy(S, signature + 32, 32);
// Per rfc8032 5.1.6.6
// "the three most significant bits of the final octet are always zero"
// 224 = 11100000_2
if ((signature[63] & 224) != 0) {
return 0;
}
// S must be in the range [0, order) in order to prevent signature
// malleability. kOrder is the order of curve25519 in little-endian form.
static const uint64_t kOrder[4] = {
UINT64_C(0x5812631a5cf5d3ed),
UINT64_C(0x14def9dea2f79cd6),
0,
UINT64_C(0x1000000000000000),
};
for (size_t i = 3;; i--) {
uint64_t word = CRYPTO_load_u64_le(S + i * 8);
if (word > kOrder[i]) {
return 0;
} else if (word < kOrder[i]) {
break;
} else if (i == 0) {
return 0;
}
}
uint8_t dom2_buffer[MAX_DOM2_SIZE] = {0};
size_t dom2_buffer_len = 0;
if (!dom2(alg, dom2_buffer, &dom2_buffer_len, ctx, ctx_len)) {
OPENSSL_PUT_ERROR(CRYPTO, ERR_R_CRYPTO_LIB);
return 0;
}
// Step: rfc8032 5.1.7.[1,2,3]
// Verification works by computing [S]B - [k]A' and comparing against R_expected.
int res = 0;
uint8_t R_computed_encoded[32];
#if defined(CURVE25519_S2N_BIGNUM_CAPABLE)
res = ed25519_verify_s2n_bignum(R_computed_encoded, public_key, R_expected, S,
message, message_len, dom2_buffer,
dom2_buffer_len);
#else
res = ed25519_verify_nohw(R_computed_encoded, public_key, R_expected, S,
message, message_len, dom2_buffer, dom2_buffer_len);
#endif
// Comparison [S]B - [k]A' =? R_expected. Short-circuits if decoding failed.
return (res == 1) && CRYPTO_memcmp(R_computed_encoded, R_expected,
sizeof(R_computed_encoded)) == 0;
}
int ED25519_check_public_key(const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]) {
#if defined(CURVE25519_S2N_BIGNUM_CAPABLE)
return ed25519_check_public_key_s2n_bignum(public_key);
#else
return ed25519_check_public_key_nohw(public_key);
#endif
}
void X25519_public_from_private(
uint8_t out_public_value[X25519_PUBLIC_VALUE_LEN],
const uint8_t private_key[X25519_PRIVATE_KEY_LEN]) {
SET_DIT_AUTO_RESET;
#if defined(CURVE25519_S2N_BIGNUM_CAPABLE)
x25519_public_from_private_s2n_bignum(out_public_value, private_key);
#else
x25519_public_from_private_nohw(out_public_value, private_key);
#endif
// The public key is derived from the private key, but it is public.
CONSTTIME_DECLASSIFY(out_public_value, X25519_PUBLIC_VALUE_LEN);
}
void X25519_keypair(uint8_t out_public_value[X25519_PUBLIC_VALUE_LEN],
uint8_t out_private_key[X25519_PRIVATE_KEY_LEN]) {
SET_DIT_AUTO_RESET;
AWSLC_ABORT_IF_NOT_ONE(RAND_bytes(out_private_key, X25519_PRIVATE_KEY_LEN));
// All X25519 implementations should decode scalars correctly (see
// https://tools.ietf.org/html/rfc7748#section-5). However, if an
// implementation doesn't then it might interoperate with random keys a
// fraction of the time because they'll, randomly, happen to be correctly
// formed.
//
// Thus we do the opposite of the masking here to make sure that our private
// keys are never correctly masked and so, hopefully, any incorrect
// implementations are deterministically broken.
//
// This does not affect security because, although we're throwing away
// entropy, a valid implementation of scalarmult should throw away the exact
// same bits anyway.
out_private_key[0] |= ~248;
out_private_key[31] &= ~64;
out_private_key[31] |= ~127;
X25519_public_from_private(out_public_value, out_private_key);
}
int X25519(uint8_t out_shared_key[X25519_SHARED_KEY_LEN],
const uint8_t private_key[X25519_PRIVATE_KEY_LEN],
const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN]) {
SET_DIT_AUTO_RESET;
static const uint8_t kZeros[X25519_SHARED_KEY_LEN] = {0};
#if defined(CURVE25519_S2N_BIGNUM_CAPABLE)
x25519_scalar_mult_generic_s2n_bignum(out_shared_key, private_key, peer_public_value);
#else
x25519_scalar_mult_generic_nohw(out_shared_key, private_key, peer_public_value);
#endif
// The all-zero output results when the input is a point of small order.
return constant_time_declassify_int(
CRYPTO_memcmp(kZeros, out_shared_key, X25519_SHARED_KEY_LEN)) != 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,143 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include "internal.h"
#include "../cpucap/internal.h"
#if defined(CURVE25519_S2N_BIGNUM_CAPABLE)
#include "../../../third_party/s2n-bignum/s2n-bignum_aws-lc.h"
void x25519_scalar_mult_generic_s2n_bignum(
uint8_t out_shared_key[X25519_SHARED_KEY_LEN],
const uint8_t private_key[X25519_PRIVATE_KEY_LEN],
const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN]) {
uint8_t private_key_internal_demask[X25519_PRIVATE_KEY_LEN];
OPENSSL_memcpy(private_key_internal_demask, private_key, X25519_PRIVATE_KEY_LEN);
private_key_internal_demask[0] &= 248;
private_key_internal_demask[31] &= 127;
private_key_internal_demask[31] |= 64;
curve25519_x25519_byte_selector(out_shared_key,
private_key_internal_demask,
peer_public_value);
}
void x25519_public_from_private_s2n_bignum(
uint8_t out_public_value[X25519_PUBLIC_VALUE_LEN],
const uint8_t private_key[X25519_PRIVATE_KEY_LEN]) {
uint8_t private_key_internal_demask[X25519_PRIVATE_KEY_LEN];
OPENSSL_memcpy(private_key_internal_demask, private_key, X25519_PRIVATE_KEY_LEN);
private_key_internal_demask[0] &= 248;
private_key_internal_demask[31] &= 127;
private_key_internal_demask[31] |= 64;
curve25519_x25519base_byte_selector(out_public_value, private_key_internal_demask);
}
void ed25519_public_key_from_hashed_seed_s2n_bignum(
uint8_t out_public_key[ED25519_PUBLIC_KEY_LEN],
uint8_t az[SHA512_DIGEST_LENGTH]) {
uint64_t uint64_point[8] = {0};
uint64_t uint64_hashed_seed[4] = {0};
OPENSSL_memcpy(uint64_hashed_seed, az, 32);
edwards25519_scalarmulbase_selector(uint64_point, uint64_hashed_seed);
edwards25519_encode(out_public_key, uint64_point);
}
void ed25519_sign_s2n_bignum(uint8_t out_sig[ED25519_SIGNATURE_LEN],
uint8_t r[SHA512_DIGEST_LENGTH], const uint8_t *s, const uint8_t *A,
const void *message, size_t message_len, const uint8_t *dom2, size_t dom2_len) {
uint8_t k[SHA512_DIGEST_LENGTH] = {0};
uint64_t R[8] = {0};
uint64_t S[4] = {0};
uint64_t uint64_r[8] = {0};
uint64_t uint64_k[8] = {0};
uint64_t uint64_s[4] = {0};
OPENSSL_memcpy(uint64_r, r, 64);
OPENSSL_memcpy(uint64_s, s, 32);
// Reduce r modulo the order of the base-point B.
bignum_mod_n25519(uint64_r, 8, uint64_r);
// Compute [r]B.
edwards25519_scalarmulbase_selector(R, uint64_r);
edwards25519_encode(out_sig, R);
// R is of length 32 octets
if (dom2_len > 0) {
// Compute k = SHA512(dom2(phflag, context) || R || A || message)
ed25519_sha512(k, dom2, dom2_len, out_sig, 32, A, ED25519_PUBLIC_KEY_LEN, message,
message_len);
} else {
// Compute k = SHA512(R || A || message)
ed25519_sha512(k, out_sig, 32, A, ED25519_PUBLIC_KEY_LEN, message,
message_len, NULL, 0);
}
OPENSSL_memcpy(uint64_k, k, SHA512_DIGEST_LENGTH);
bignum_mod_n25519(uint64_k, 8, uint64_k);
// Compute S = r + k * s modulo the order of the base-point B.
// out_sig = R || S
bignum_madd_n25519_selector(S, uint64_k, uint64_s, uint64_r);
OPENSSL_memcpy(out_sig + 32, S, 32);
}
int ed25519_verify_s2n_bignum(uint8_t R_computed_encoded[32],
const uint8_t public_key[ED25519_PUBLIC_KEY_LEN], uint8_t R_expected[32],
uint8_t S[32], const uint8_t *message, size_t message_len, const uint8_t *dom2, size_t dom2_len) {
uint8_t k[SHA512_DIGEST_LENGTH] = {0};
uint64_t uint64_k[8] = {0};
uint64_t uint64_R[8] = {0};
uint64_t uint64_S[4] = {0};
uint64_t A[8] = {0};
// Decode public key as A'.
if (edwards25519_decode_selector(A, public_key) != 0) {
return 0;
}
// Step: rfc8032 5.1.7.2
if(dom2_len > 0) {
// Compute k = SHA512(dom2(phflag, context) || R_expected || public_key || message).
ed25519_sha512(k, dom2, dom2_len, R_expected, 32, public_key,
ED25519_PUBLIC_KEY_LEN, message, message_len);
} else {
// Compute k = SHA512(R_expected || public_key || message).
ed25519_sha512(k, R_expected, 32, public_key, ED25519_PUBLIC_KEY_LEN,
message, message_len, NULL, 0);
}
OPENSSL_memcpy(uint64_k, k, SHA512_DIGEST_LENGTH);
bignum_mod_n25519(uint64_k, 8, uint64_k);
// Step: rfc8032 5.1.7.3
// Recall, we must compute [S]B - [k]A'.
// First negate A'. Point negation for the twisted edwards curve when points
// are represented in the extended coordinate system is simply:
// -(X,Y,Z,T) = (-X,Y,Z,-T).
// See "Twisted Edwards curves revisited" https://ia.cr/2008/522.
bignum_neg_p25519(A, A);
// Compute R_have <- [S]B - [k]A'.
OPENSSL_memcpy(uint64_S, S, 32);
edwards25519_scalarmuldouble_selector(uint64_R, uint64_k, A, uint64_S);
edwards25519_encode(R_computed_encoded, uint64_R);
return 1;
}
int ed25519_check_public_key_s2n_bignum(const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]) {
uint64_t A[8] = {0};
if (edwards25519_decode_selector(A, public_key) != 0) {
return 0;
}
return 1;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,214 @@
// Copyright (c) 2015, Google Inc.
// SPDX-License-Identifier: ISC
#include <stdint.h>
#include <string.h>
#include <gtest/gtest.h>
#include <openssl/curve25519.h>
#include "../../internal.h"
#include "../../test/file_test.h"
#include "../../test/test_util.h"
TEST(Ed25519Test, TestVectors) {
FileTestGTest("crypto/fipsmodule/curve25519/ed25519_tests.txt", [](FileTest *t) {
std::vector<uint8_t> private_key, public_key, message, expected_signature;
ASSERT_TRUE(t->GetBytes(&private_key, "PRIV"));
ASSERT_EQ(64u, private_key.size());
ASSERT_TRUE(t->GetBytes(&public_key, "PUB"));
ASSERT_EQ(32u, public_key.size());
ASSERT_TRUE(t->GetBytes(&message, "MESSAGE"));
ASSERT_TRUE(t->GetBytes(&expected_signature, "SIG"));
ASSERT_EQ(64u, expected_signature.size());
// Signing should not leak the private key or the message.
CONSTTIME_SECRET(private_key.data(), private_key.size());
CONSTTIME_SECRET(message.data(), message.size());
uint8_t signature[64];
ASSERT_TRUE(ED25519_sign(signature, message.data(), message.size(),
private_key.data()));
CONSTTIME_DECLASSIFY(signature, sizeof(signature));
CONSTTIME_DECLASSIFY(message.data(), message.size());
EXPECT_EQ(Bytes(expected_signature), Bytes(signature));
EXPECT_TRUE(ED25519_verify(message.data(), message.size(), signature,
public_key.data()));
});
}
TEST(Ed25519Test, Malleability) {
// https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test
// that s be in [0, order). This prevents someone from adding a multiple of
// order to s and obtaining a second valid signature for the same message.
static const uint8_t kMsg[] = {0x54, 0x65, 0x73, 0x74};
static const uint8_t kSig[] = {
0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
};
static const uint8_t kPub[] = {
0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
};
EXPECT_FALSE(ED25519_verify(kMsg, sizeof(kMsg), kSig, kPub));
// The following inputs try to exercise the boundaries of the order check,
// where s is near the order above and below. EdDSA hashes the public key with
// the message, which frustrates constructing actual boundary cases. Instead,
// these inputs were found by randomly generating signatures. kSigValid had
// the highest s value. kSigInvalid had the lowest s value, and then the order
// was added.
//
// This isn't ideal, but it is sensitive to the most significant 32 bits.
//
// The private key seed for kPub2 is
// a59a4130fcfd293c9737db8f14177ce034305cf34bdc4346f24b4d262e07b5c2.
static const uint8_t kPub2[] = {
0x10, 0x0f, 0xdf, 0x47, 0xfb, 0x94, 0xf1, 0x53, 0x6a, 0x4f, 0x7c,
0x3f, 0xda, 0x27, 0x38, 0x3f, 0xa0, 0x33, 0x75, 0xa8, 0xf5, 0x27,
0xc5, 0x37, 0xe6, 0xf1, 0x70, 0x3c, 0x47, 0xf9, 0x4f, 0x86};
static const uint8_t kMsgValid[] = {
0x12, 0x4e, 0x58, 0x3f, 0x8b, 0x8e, 0xca, 0x58, 0xbb, 0x29, 0xc2,
0x71, 0xb4, 0x1d, 0x36, 0x98, 0x6b, 0xbc, 0x45, 0x54, 0x1f, 0x8e,
0x51, 0xf9, 0xcb, 0x01, 0x33, 0xec, 0xa4, 0x47, 0x60, 0x1e};
static const uint8_t kSigValid[] = {
0xda, 0xc1, 0x19, 0xd6, 0xca, 0x87, 0xfc, 0x59, 0xae, 0x61, 0x1c,
0x15, 0x70, 0x48, 0xf4, 0xd4, 0xfc, 0x93, 0x2a, 0x14, 0x9d, 0xbe,
0x20, 0xec, 0x6e, 0xff, 0xd1, 0x43, 0x6a, 0xbf, 0x83, 0xea, 0x05,
0xc7, 0xdf, 0x0f, 0xef, 0x06, 0x14, 0x72, 0x41, 0x25, 0x91, 0x13,
0x90, 0x9b, 0xc7, 0x1b, 0xd3, 0xc5, 0x3b, 0xa4, 0x46, 0x4f, 0xfc,
0xad, 0x3c, 0x09, 0x68, 0xf2, 0xff, 0xff, 0xff, 0x0f};
static const uint8_t kMsgInvalid[] = {
0x6a, 0x0b, 0xc2, 0xb0, 0x05, 0x7c, 0xed, 0xfc, 0x0f, 0xa2, 0xe3,
0xf7, 0xf7, 0xd3, 0x92, 0x79, 0xb3, 0x0f, 0x45, 0x4a, 0x69, 0xdf,
0xd1, 0x11, 0x7c, 0x75, 0x8d, 0x86, 0xb1, 0x9d, 0x85, 0xe0};
static const uint8_t kSigInvalid[] = {
0x09, 0x71, 0xf8, 0x6d, 0x2c, 0x9c, 0x78, 0x58, 0x25, 0x24, 0xa1,
0x03, 0xcb, 0x9c, 0xf9, 0x49, 0x52, 0x2a, 0xe5, 0x28, 0xf8, 0x05,
0x4d, 0xc2, 0x01, 0x07, 0xd9, 0x99, 0xbe, 0x67, 0x3f, 0xf4, 0xe2,
0x5e, 0xbf, 0x2f, 0x29, 0x28, 0x76, 0x6b, 0x12, 0x48, 0xbe, 0xc6,
0xe9, 0x16, 0x97, 0x77, 0x5f, 0x84, 0x46, 0x63, 0x9e, 0xde, 0x46,
0xad, 0x4d, 0xf4, 0x05, 0x30, 0x00, 0x00, 0x00, 0x10};
EXPECT_TRUE(ED25519_verify(kMsgValid, sizeof(kMsgValid), kSigValid, kPub2));
EXPECT_FALSE(
ED25519_verify(kMsgInvalid, sizeof(kMsgInvalid), kSigInvalid, kPub2));
}
TEST(Ed25519Test, KeypairFromSeed) {
uint8_t public_key1[32], private_key1[64];
ED25519_keypair(public_key1, private_key1);
uint8_t seed[32];
OPENSSL_memcpy(seed, private_key1, sizeof(seed));
CONSTTIME_SECRET(seed, sizeof(seed));
uint8_t public_key2[32], private_key2[64];
ED25519_keypair_from_seed(public_key2, private_key2, seed);
CONSTTIME_DECLASSIFY(public_key2, sizeof(public_key2));
CONSTTIME_DECLASSIFY(private_key2, sizeof(private_key2));
EXPECT_EQ(Bytes(public_key1), Bytes(public_key2));
EXPECT_EQ(Bytes(private_key1), Bytes(private_key2));
}
TEST(Ed25519phTest, TestVectors) {
FileTestGTest("crypto/fipsmodule/curve25519/ed25519ph_tests.txt", [](FileTest *t) {
std::vector<uint8_t> seed, q, message, context, expected_signature;
ASSERT_TRUE(t->GetBytes(&seed, "SEED"));
ASSERT_EQ(32u, seed.size());
ASSERT_TRUE(t->GetBytes(&q, "Q"));
ASSERT_EQ(32u, q.size());
ASSERT_TRUE(t->GetBytes(&message, "MESSAGE"));
ASSERT_TRUE(t->GetBytes(&expected_signature, "SIGNATURE"));
ASSERT_EQ(64u, expected_signature.size());
if (t->HasAttribute("CONTEXT")) {
t->GetBytes(&context, "CONTEXT");
} else {
context = std::vector<uint8_t>();
}
uint8_t private_key[ED25519_PRIVATE_KEY_LEN] = {0};
uint8_t public_key[ED25519_PUBLIC_KEY_LEN] = {0};
ED25519_keypair_from_seed(public_key, private_key, seed.data());
ASSERT_EQ(Bytes(q), Bytes(public_key));
// Signing should not leak the private key or the message.
CONSTTIME_SECRET(&private_key[0], sizeof(private_key));
CONSTTIME_SECRET(message.data(), message.size());
CONSTTIME_SECRET(context.data(), context.size());
uint8_t signature[64];
ASSERT_TRUE(ED25519ph_sign(signature, message.data(), message.size(),
private_key, context.data(), context.size()));
CONSTTIME_DECLASSIFY(signature, sizeof(signature));
CONSTTIME_DECLASSIFY(message.data(), message.size());
CONSTTIME_DECLASSIFY(context.data(), context.size());
EXPECT_EQ(Bytes(expected_signature), Bytes(signature));
EXPECT_TRUE(ED25519ph_verify(message.data(), message.size(), signature,
public_key, context.data(), context.size()));
});
}
TEST(Ed25519ctxTest, TestVectors) {
FileTestGTest("crypto/fipsmodule/curve25519/ed25519ctx_tests.txt", [](FileTest *t) {
std::vector<uint8_t> seed, q, message, context, expected_signature;
ASSERT_TRUE(t->GetBytes(&seed, "SEED"));
ASSERT_EQ(32u, seed.size());
ASSERT_TRUE(t->GetBytes(&q, "Q"));
ASSERT_EQ(32u, q.size());
ASSERT_TRUE(t->GetBytes(&message, "MESSAGE"));
ASSERT_TRUE(t->GetBytes(&expected_signature, "SIGNATURE"));
ASSERT_EQ(64u, expected_signature.size());
if (t->HasAttribute("CONTEXT")) {
t->GetBytes(&context, "CONTEXT");
} else {
context = std::vector<uint8_t>();
}
uint8_t private_key[ED25519_PRIVATE_KEY_LEN] = {0};
uint8_t public_key[ED25519_PUBLIC_KEY_LEN] = {0};
ED25519_keypair_from_seed(public_key, private_key, seed.data());
ASSERT_EQ(Bytes(q), Bytes(public_key));
// Signing should not leak the private key or the message.
CONSTTIME_SECRET(&private_key[0], sizeof(private_key));
CONSTTIME_SECRET(message.data(), message.size());
CONSTTIME_SECRET(context.data(), context.size());
uint8_t signature[64];
ASSERT_TRUE(ED25519ctx_sign(signature, message.data(), message.size(),
private_key, context.data(), context.size()));
CONSTTIME_DECLASSIFY(signature, sizeof(signature));
CONSTTIME_DECLASSIFY(message.data(), message.size());
CONSTTIME_DECLASSIFY(context.data(), context.size());
EXPECT_EQ(Bytes(expected_signature), Bytes(signature));
EXPECT_TRUE(ED25519ctx_verify(message.data(), message.size(), signature,
public_key, context.data(), context.size()));
});
}
TEST(Ed25519ctxTest, EmptyContext) {
uint8_t private_key[ED25519_PRIVATE_KEY_LEN] = {0};
uint8_t public_key[ED25519_PUBLIC_KEY_LEN] = {0};
uint8_t signature[ED25519_SIGNATURE_LEN] = {0};
const uint8_t message[3] = {'f', 'o', 'o'};
ED25519_keypair(public_key, private_key);
EXPECT_FALSE(ED25519ctx_sign(signature, message, sizeof(message), private_key, NULL, 0));
EXPECT_FALSE(ED25519ctx_verify(message, sizeof(message), signature, public_key, NULL, 0));
}

View File

@@ -0,0 +1,276 @@
// Copyright (c) 2020, Google Inc.
// SPDX-License-Identifier: ISC
#ifndef OPENSSL_HEADER_CURVE25519_INTERNAL_H
#define OPENSSL_HEADER_CURVE25519_INTERNAL_H
#if defined(__cplusplus)
extern "C" {
#endif
#include <openssl/base.h>
#include <openssl/curve25519.h>
#include "../../internal.h"
typedef enum {
ED25519_ALG,
ED25519CTX_ALG,
ED25519PH_ALG,
} ed25519_algorithm_t;
#define DOM2_PREFIX_SIZE 32
#define DOM2_F_SIZE 1
#define DOM2_C_SIZE 1
#define DOM2_F_OFFSET DOM2_PREFIX_SIZE
#define DOM2_C_OFFSET (DOM2_F_OFFSET + DOM2_F_SIZE)
#define DOM2_CONTEXT_OFFSET (DOM2_C_OFFSET + DOM2_C_SIZE)
#define MAX_DOM2_CONTEXT_SIZE 255
#define MAX_DOM2_SIZE \
(DOM2_PREFIX_SIZE + DOM2_F_SIZE + DOM2_C_SIZE + MAX_DOM2_CONTEXT_SIZE)
int ED25519_keypair_internal(
uint8_t out_public_key[ED25519_PUBLIC_KEY_LEN],
uint8_t out_private_key[ED25519_PRIVATE_KEY_LEN]);
int ed25519_sign_internal(
ed25519_algorithm_t alg,
uint8_t out_sig[ED25519_SIGNATURE_LEN],
const uint8_t *message, size_t message_len,
const uint8_t private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t *ctx, size_t ctx_len);
int ed25519_verify_internal(
ed25519_algorithm_t alg,
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 *ctx, size_t ctx_len);
int ED25519_sign_no_self_test(
uint8_t out_sig[ED25519_SIGNATURE_LEN],
const uint8_t *message, size_t message_len,
const uint8_t private_key[ED25519_PRIVATE_KEY_LEN]);
int ED25519_verify_no_self_test(
const uint8_t *message, size_t message_len,
const uint8_t signature[ED25519_SIGNATURE_LEN],
const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]);
int ED25519ctx_sign_no_self_test(
uint8_t out_sig[ED25519_SIGNATURE_LEN],
const uint8_t *message, size_t message_len,
const uint8_t private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t *context, size_t context_len);
int ED25519ctx_verify_no_self_test(
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 *context, size_t context_len);
int ED25519ph_sign_no_self_test(
uint8_t out_sig[ED25519_SIGNATURE_LEN],
const uint8_t *message, size_t message_len,
const uint8_t private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t *context, size_t context_len);
int ED25519ph_sign_digest_no_self_test(
uint8_t out_sig[ED25519_SIGNATURE_LEN],
const uint8_t digest[SHA512_DIGEST_LENGTH],
const uint8_t private_key[ED25519_PRIVATE_KEY_LEN],
const uint8_t *context, size_t context_len);
int ED25519ph_verify_no_self_test(
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 *context, size_t context_len);
int ED25519ph_verify_digest_no_self_test(
const uint8_t digest[SHA512_DIGEST_LENGTH],
const uint8_t signature[ED25519_SIGNATURE_LEN],
const uint8_t public_key[ED25519_PUBLIC_KEY_LEN],
const uint8_t *context, size_t context_len);
// If (1) x86_64 or aarch64, (2) linux or apple, and (3) OPENSSL_NO_ASM is not
// set, s2n-bignum path is capable.
#if ((defined(OPENSSL_X86_64) && !defined(MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX)) || \
defined(OPENSSL_AARCH64)) && \
(defined(OPENSSL_LINUX) || defined(OPENSSL_APPLE) || \
defined(OPENSSL_OPENBSD) || defined(OPENSSL_FREEBSD) || \
defined(OPENSSL_NETBSD)) && \
!defined(OPENSSL_NO_ASM)
#define CURVE25519_S2N_BIGNUM_CAPABLE
#endif
#if defined(BORINGSSL_HAS_UINT128)
#define BORINGSSL_CURVE25519_64BIT
#endif
#if defined(BORINGSSL_CURVE25519_64BIT)
// fe means field element. Here the field is \Z/(2^255-19). An element t,
// entries t[0]...t[4], represents the integer t[0]+2^51 t[1]+2^102 t[2]+2^153
// t[3]+2^204 t[4].
// fe limbs are bounded by 1.125*2^51.
// Multiplication and carrying produce fe from fe_loose.
typedef struct fe { uint64_t v[5]; } fe;
// fe_loose limbs are bounded by 3.375*2^51.
// Addition and subtraction produce fe_loose from (fe, fe).
typedef struct fe_loose { uint64_t v[5]; } fe_loose;
#else
// fe means field element. Here the field is \Z/(2^255-19). An element t,
// entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
// t[3]+2^102 t[4]+...+2^230 t[9].
// fe limbs are bounded by 1.125*2^26,1.125*2^25,1.125*2^26,1.125*2^25,etc.
// Multiplication and carrying produce fe from fe_loose.
typedef struct fe { uint32_t v[10]; } fe;
// fe_loose limbs are bounded by 3.375*2^26,3.375*2^25,3.375*2^26,3.375*2^25,etc.
// Addition and subtraction produce fe_loose from (fe, fe).
typedef struct fe_loose { uint32_t v[10]; } fe_loose;
#endif
// ge means group element.
//
// Here the group is the set of pairs (x,y) of field elements (see fe.h)
// satisfying -x^2 + y^2 = 1 + d x^2y^2
// where d = -121665/121666.
//
// Representations:
// ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
// ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
// ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
// ge_precomp (Duif): (y+x,y-x,2dxy)
typedef struct {
fe X;
fe Y;
fe Z;
} ge_p2;
typedef struct {
fe X;
fe Y;
fe Z;
fe T;
} ge_p3;
typedef struct {
fe_loose X;
fe_loose Y;
fe_loose Z;
fe_loose T;
} ge_p1p1;
typedef struct {
fe_loose yplusx;
fe_loose yminusx;
fe_loose xy2d;
} ge_precomp;
typedef struct {
fe_loose YplusX;
fe_loose YminusX;
fe_loose Z;
fe_loose T2d;
} ge_cached;
void x25519_ge_tobytes(uint8_t s[32], const ge_p2 *h);
int x25519_ge_frombytes_vartime(ge_p3 *h, const uint8_t s[32]);
void x25519_ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
void x25519_ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
void x25519_ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
void x25519_ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
void x25519_ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
void x25519_ge_scalarmult_small_precomp(
ge_p3 *h, const uint8_t a[32], const uint8_t precomp_table[15 * 2 * 32]);
void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]);
void x25519_ge_scalarmult(ge_p2 *r, const uint8_t *scalar, const ge_p3 *A);
void x25519_sc_reduce(uint8_t s[64]);
// x25519_scalar_mult_generic_[s2n_bignum,nohw] computes the x25519 function
// from rfc7748 6.1 using the peer coordinate (either K_A or K_B) encoded in
// |peer_public_value| and the scalar is |private_key|. The resulting shared key
// is returned in |out_shared_key|.
void x25519_scalar_mult_generic_s2n_bignum(
uint8_t out_shared_key[X25519_SHARED_KEY_LEN],
const uint8_t private_key[X25519_PRIVATE_KEY_LEN],
const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN]);
void x25519_scalar_mult_generic_nohw(
uint8_t out_shared_key[X25519_SHARED_KEY_LEN],
const uint8_t private_key[X25519_PRIVATE_KEY_LEN],
const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN]);
// x25519_public_from_private_[s2n_bignum,nohw] computes the x25519 function
// from rfc7748 6.1 using the base-coordinate 9 and scalar |private_key|. The
// resulting (encoded) public key coordinate (either K_A or K_B) is returned in
// |out_public_value|.
void x25519_public_from_private_s2n_bignum(
uint8_t out_public_value[X25519_PUBLIC_VALUE_LEN],
const uint8_t private_key[X25519_PRIVATE_KEY_LEN]);
void x25519_public_from_private_nohw(
uint8_t out_public_value[X25519_PUBLIC_VALUE_LEN],
const uint8_t private_key[X25519_PRIVATE_KEY_LEN]);
// ed25519_public_key_from_hashed_seed_[s2n_bignum,nohw] handles steps
// rfc8032 5.1.5.[3,4]. Computes [az]B and encodes the public key to a 32-byte
// octet string returning it in |out_public_key|.
void ed25519_public_key_from_hashed_seed_s2n_bignum(
uint8_t out_public_key[ED25519_PUBLIC_KEY_LEN],
uint8_t az[SHA512_DIGEST_LENGTH]);
void ed25519_public_key_from_hashed_seed_nohw(
uint8_t out_public_key[ED25519_PUBLIC_KEY_LEN],
uint8_t az[SHA512_DIGEST_LENGTH]);
// ed25519_sign_[s2n_bignum,nohw] handles steps rfc8032 5.1.6.[3,5,6,7].
// Computes the signature S = r + k * s modulo the order of the base-point B.
// Returns R || S in |out_sig|. |s| must have length
// |ED25519_PRIVATE_KEY_SEED_LEN| and |A| must have length
// |ED25519_PUBLIC_KEY_LEN|.
void ed25519_sign_s2n_bignum(uint8_t out_sig[ED25519_SIGNATURE_LEN],
uint8_t r[SHA512_DIGEST_LENGTH], const uint8_t *s,
const uint8_t *A,
const void *message, size_t message_len,
const uint8_t *dom2, size_t dom2_len);
void ed25519_sign_nohw(uint8_t out_sig[ED25519_SIGNATURE_LEN],
uint8_t r[SHA512_DIGEST_LENGTH], const uint8_t *s,
const uint8_t *A,
const void *message, size_t message_len,
const uint8_t *dom2, size_t dom2_len);
// ed25519_verify_[s2n_bignum,nohw] handles steps rfc8032 5.1.7.[1,2,3].
// Computes [S]B - [k]A' and returns the result in |R_computed_encoded|. Returns
// 1 on success and 0 otherwise. The failure case occurs if decoding of the
// public key |public_key| fails.
int ed25519_verify_s2n_bignum(uint8_t R_computed_encoded[32],
const uint8_t public_key[ED25519_PUBLIC_KEY_LEN],
uint8_t R_expected[32], uint8_t S[32],
const uint8_t *message, size_t message_len,
const uint8_t *dom2, size_t dom2_len);
int ed25519_verify_nohw(uint8_t R_computed_encoded[32],
const uint8_t public_key[ED25519_PUBLIC_KEY_LEN],
uint8_t R_expected[32], uint8_t S[32],
const uint8_t *message, size_t message_len,
const uint8_t *dom2, size_t dom2_len);
// Computes the SHA512 function of up to four input pairs: (|input1|, |len1|),
// (|input2|, |len2|), (|input3|, |len3|), (|input4|, |len4|). Specifically, the
// hash is computed over the concatenation: |input1| || |input2| || |input3| ||
// |input4|. The final two pairs may have |len3| == 0 or |len4| == 0, meaning
// those input values will be ignored. The result is written to |out|.
void ed25519_sha512(uint8_t out[SHA512_DIGEST_LENGTH],
const void *input1, size_t len1, const void *input2, size_t len2,
const void *input3, size_t len3, const void *input4, size_t len4);
int ed25519_check_public_key_s2n_bignum(const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]);
int ed25519_check_public_key_nohw(const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]);
OPENSSL_EXPORT int ED25519_check_public_key(const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]);
#if defined(__cplusplus)
} // extern C
#endif
#endif // OPENSSL_HEADER_CURVE25519_INTERNAL_H

View File

@@ -0,0 +1,230 @@
// Copyright (c) 2015, Google Inc.
// SPDX-License-Identifier: ISC
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <gtest/gtest.h>
#include <openssl/curve25519.h>
#include "../../internal.h"
#include "../../test/abi_test.h"
#include "../../test/file_test.h"
#include "../../test/test_util.h"
#include "../../test/wycheproof_util.h"
#include "internal.h"
static inline int ctwrapX25519(uint8_t out_shared_key[32],
const uint8_t private_key[32],
const uint8_t peer_public_value[32]) {
uint8_t scalar[32], point[32];
// Copy all the secrets into a temporary buffer, so we can run constant-time
// validation on them.
OPENSSL_memcpy(scalar, private_key, sizeof(scalar));
OPENSSL_memcpy(point, peer_public_value, sizeof(point));
// X25519 should not leak the private key.
CONSTTIME_SECRET(scalar, sizeof(scalar));
// All other inputs are also marked as secret. This is not to support any
// particular use case for calling X25519 with a secret *point*, but
// rather to ensure that the choice of the point cannot influence whether
// the scalar is leaked or not. Same for the initial contents of the
// output buffer. This conservative choice may be revised in the future.
CONSTTIME_SECRET(point, sizeof(point));
CONSTTIME_SECRET(out_shared_key, 32);
int r = X25519(out_shared_key, scalar, point);
CONSTTIME_DECLASSIFY(out_shared_key, 32);
return r;
}
TEST(X25519Test, TestVector) {
// Taken from https://www.rfc-editor.org/rfc/rfc7748#section-5.2
static const uint8_t kScalar1[32] = {
0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15,
0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc,
0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4,
};
static const uint8_t kPoint1[32] = {
0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1,
0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3,
0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c,
};
uint8_t out[32], secret[32];
EXPECT_TRUE(ctwrapX25519(out, kScalar1, kPoint1));
static const uint8_t kExpected1[32] = {
0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea,
0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c,
0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52,
};
EXPECT_EQ(Bytes(kExpected1), Bytes(out));
static const uint8_t kScalar2[32] = {
0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26,
0x91, 0x95, 0x7d, 0x6a, 0xf5, 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea,
0x01, 0xd4, 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x0d,
};
static const uint8_t kPoint2[32] = {
0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95,
0x9d, 0x05, 0x38, 0xae, 0x2c, 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0,
0x3c, 0x3e, 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x93,
};
EXPECT_TRUE(ctwrapX25519(out, kScalar2, kPoint2));
static const uint8_t kExpected2[32] = {
0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, 0xe4,
0x5c, 0xb4, 0xb8, 0x73, 0xf8, 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f,
0xa1, 0x52, 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57,
};
EXPECT_EQ(Bytes(kExpected2), Bytes(out));
// Taken from https://www.rfc-editor.org/rfc/rfc7748.html#section-6.1
static const uint8_t kPrivateA[32] = {
0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1,
0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0,
0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a,
};
static const uint8_t kPublicA[32] = {
0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d,
0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38,
0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a,
};
static const uint8_t kPrivateB[32] = {
0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, 0x79, 0xe1, 0x7f,
0x8b, 0x83, 0x80, 0x0e, 0xe6, 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18,
0xb6, 0xfd, 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb,
};
static const uint8_t kPublicB[32] = {
0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61,
0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78,
0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f,
};
static const uint8_t kSecret[32] = {
0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b,
0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1,
0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42,
};
OPENSSL_memcpy(secret, kPrivateA, sizeof(secret));
CONSTTIME_SECRET(secret, sizeof(secret));
X25519_public_from_private(out, secret);
CONSTTIME_DECLASSIFY(out, sizeof(out));
EXPECT_EQ(Bytes(out), Bytes(kPublicA));
OPENSSL_memcpy(secret, kPrivateB, sizeof(secret));
CONSTTIME_SECRET(secret, sizeof(secret));
X25519_public_from_private(out, secret);
CONSTTIME_DECLASSIFY(out, sizeof(out));
EXPECT_EQ(Bytes(out), Bytes(kPublicB));
ctwrapX25519(out, kPrivateA, kPublicB);
EXPECT_EQ(Bytes(out), Bytes(kSecret));
ctwrapX25519(out, kPrivateB, kPublicA);
EXPECT_EQ(Bytes(out), Bytes(kSecret));
}
TEST(X25519Test, SmallOrder) {
static const uint8_t kSmallOrderPoint[32] = {
0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3,
0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32,
0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8,
};
uint8_t out[32], private_key[32];
OPENSSL_memset(private_key, 0x11, sizeof(private_key));
OPENSSL_memset(out, 0xff, sizeof(out));
EXPECT_FALSE(ctwrapX25519(out, private_key, kSmallOrderPoint))
<< "X25519 returned success with a small-order input.";
// For callers which don't check, |out| should still be filled with zeros.
static const uint8_t kZeros[32] = {0};
EXPECT_EQ(Bytes(kZeros), Bytes(out));
}
TEST(X25519Test, Iterated) {
// Taken from https://tools.ietf.org/html/rfc7748#section-5.2.
uint8_t scalar[32] = {}, point[32] = {}, out[32];
scalar[0] = 9;
point[0] = 9;
for (unsigned i = 0; i < 1000; i++) {
EXPECT_TRUE(ctwrapX25519(out, scalar, point));
OPENSSL_memcpy(point, scalar, sizeof(point));
OPENSSL_memcpy(scalar, out, sizeof(scalar));
}
static const uint8_t kExpected[32] = {
0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, 0x28, 0x00, 0xef,
0x56, 0x6f, 0x2f, 0x4d, 0x3c, 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60,
0xe3, 0x87, 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51,
};
EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
}
TEST(X25519Test, DISABLED_IteratedLarge) {
// Taken from https://tools.ietf.org/html/rfc7748#section-5.2.
uint8_t scalar[32] = {}, point[32] = {}, out[32];
scalar[0] = 9;
point[0] = 9;
for (unsigned i = 0; i < 1000000; i++) {
EXPECT_TRUE(ctwrapX25519(out, scalar, point));
OPENSSL_memcpy(point, scalar, sizeof(point));
OPENSSL_memcpy(scalar, out, sizeof(scalar));
}
static const uint8_t kExpected[32] = {
0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97,
0x29, 0x7e, 0x57, 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c,
0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24,
};
EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
}
TEST(X25519Test, Wycheproof) {
FileTestGTest("third_party/wycheproof_testvectors/x25519_test.txt",
[](FileTest *t) {
t->IgnoreInstruction("curve");
t->IgnoreAttribute("curve");
WycheproofResult result;
ASSERT_TRUE(GetWycheproofResult(t, &result));
std::vector<uint8_t> priv, pub, shared;
ASSERT_TRUE(t->GetBytes(&priv, "private"));
ASSERT_TRUE(t->GetBytes(&pub, "public"));
ASSERT_TRUE(t->GetBytes(&shared, "shared"));
ASSERT_EQ(32u, priv.size());
ASSERT_EQ(32u, pub.size());
uint8_t secret[32];
int ret = ctwrapX25519(secret, priv.data(), pub.data());
EXPECT_EQ(ret, result.IsValid({"NonCanonicalPublic", "Twist"}) ? 1 : 0);
EXPECT_EQ(Bytes(secret), Bytes(shared));
});
}
#if defined(BORINGSSL_X25519_NEON) && defined(SUPPORTS_ABI_TEST)
TEST(X25519Test, NeonABI) {
if (!CRYPTO_is_NEON_capable()) {
GTEST_SKIP() << "Can't test ABI of NEON code without NEON";
}
static const uint8_t kScalar[32] = {
0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15,
0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc,
0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4,
};
static const uint8_t kPoint[32] = {
0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1,
0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3,
0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c,
};
uint8_t secret[32];
CHECK_ABI(x25519_NEON, secret, kScalar, kPoint);
}
#endif // BORINGSSL_X25519_NEON && SUPPORTS_ABI_TEST