mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 15:03:34 +00:00
ea83cc0ad0
One of the disadvantages of x25519 and ℘256 is it only provides 126 bits of security, so that seems like a weak link in the chain, if we're using ECDHE-ECDSA-AES256-GCM-SHA384. The U.S. government wants classified data to be encrypted using a curve at least as strong as ℘384, which provides 192 bits of security, but if you read the consensus of stack exchange it would give you the impression that ℘384 is three times slower. This change (as well as the previous one) makes ℘384 three times as fast by tuning its modulus and multiplication subroutines with new tests that should convincingly show: the optimized code behaves the same way as the old code. Some of the diff noise from the previous change is now removed too, so that our vendored fork can be more easily compared with upstream sources. So you can now have stronger cryptography without compromises. ℘384 modulus Justine l: 28𝑐 9𝑛𝑠 ℘384 modulus MbedTLS NIST l: 127𝑐 41𝑛𝑠 ℘384 modulus MbedTLS MPI l: 1,850𝑐 597𝑛𝑠 The benchmarks above show the improvements made by secp384r1() which is an important function since it needs to be called 13,000 times whenever someone establishes a connection to your web server. The same's true of Mul6x6Adx() which is able to multiply 384-bit numbers in 73 cycles, but only if your CPU was purchased after 2014 when Broadwell was introduced
279 lines
11 KiB
C
279 lines
11 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Copyright The Mbed TLS Contributors │
|
|
│ │
|
|
│ Licensed under the Apache License, Version 2.0 (the "License"); │
|
|
│ you may not use this file except in compliance with the License. │
|
|
│ You may obtain a copy of the License at │
|
|
│ │
|
|
│ http://www.apache.org/licenses/LICENSE-2.0 │
|
|
│ │
|
|
│ Unless required by applicable law or agreed to in writing, software │
|
|
│ distributed under the License is distributed on an "AS IS" BASIS, │
|
|
│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │
|
|
│ See the License for the specific language governing permissions and │
|
|
│ limitations under the License. │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "third_party/mbedtls/ecdh_everest.h"
|
|
#include "third_party/mbedtls/everest.h"
|
|
#if defined(MBEDTLS_ECDH_C) && defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
|
|
#define KEYSIZE 32
|
|
|
|
asm(".ident\t\"\\n\\n\
|
|
Mbed TLS (Apache 2.0)\\n\
|
|
Copyright ARM Limited\\n\
|
|
Copyright Mbed TLS Contributors\"");
|
|
asm(".include \"libc/disclaimer.inc\"");
|
|
/* clang-format off */
|
|
|
|
/**
|
|
* \brief This function sets up the ECDH context with the information
|
|
* given.
|
|
*
|
|
* This function should be called after mbedtls_ecdh_init() but
|
|
* before mbedtls_ecdh_make_params(). There is no need to call
|
|
* this function before mbedtls_ecdh_read_params().
|
|
*
|
|
* This is the first function used by a TLS server for
|
|
* ECDHE ciphersuites.
|
|
*
|
|
* \param ctx The ECDH context to set up.
|
|
* \param grp_id The group id of the group to set up the context for.
|
|
*
|
|
* \return \c 0 on success.
|
|
*/
|
|
int mbedtls_everest_setup(mbedtls_ecdh_context_everest *ctx, int grp_id)
|
|
{
|
|
if (grp_id != MBEDTLS_ECP_DP_CURVE25519)
|
|
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
|
|
mbedtls_platform_zeroize(ctx, sizeof(*ctx));
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* \brief This function frees a context.
|
|
*
|
|
* \param ctx The context to free.
|
|
*/
|
|
void mbedtls_everest_free(mbedtls_ecdh_context_everest *ctx)
|
|
{
|
|
if (!ctx) return;
|
|
mbedtls_platform_zeroize(ctx, sizeof(*ctx));
|
|
}
|
|
|
|
/**
|
|
* \brief This function generates a public key and a TLS
|
|
* ServerKeyExchange payload.
|
|
*
|
|
* This is the second function used by a TLS server for ECDHE
|
|
* ciphersuites. (It is called after mbedtls_ecdh_setup().)
|
|
*
|
|
* \note This function assumes that the ECP group (grp) of the
|
|
* \p ctx context has already been properly set,
|
|
* for example, using mbedtls_ecp_group_load().
|
|
*
|
|
* \see ecp.h
|
|
*
|
|
* \param ctx The ECDH context.
|
|
* \param olen The number of characters written.
|
|
* \param buf The destination buffer.
|
|
* \param blen The length of the destination buffer.
|
|
* \param f_rng The RNG function.
|
|
* \param p_rng The RNG context.
|
|
*
|
|
* \return \c 0 on success.
|
|
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
|
|
*/
|
|
int mbedtls_everest_make_params(mbedtls_ecdh_context_everest *ctx, size_t *olen,
|
|
unsigned char *buf, size_t blen,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng)
|
|
{
|
|
int ret = 0;
|
|
uint8_t base[KEYSIZE] = {9};
|
|
if ((ret = f_rng(p_rng, ctx->our_secret, KEYSIZE)) != 0) return ret;
|
|
*olen = KEYSIZE + 4;
|
|
if (blen < *olen) return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
|
|
*buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE;
|
|
*buf++ = MBEDTLS_ECP_TLS_CURVE25519 >> 8;
|
|
*buf++ = MBEDTLS_ECP_TLS_CURVE25519 & 0xFF;
|
|
*buf++ = KEYSIZE;
|
|
curve25519(buf, ctx->our_secret, base);
|
|
base[0] = 0;
|
|
if (!timingsafe_memcmp(buf, base, KEYSIZE))
|
|
return MBEDTLS_ERR_ECP_RANDOM_FAILED;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* \brief This function parses and processes a TLS ServerKeyExhange
|
|
* payload.
|
|
*
|
|
* This is the first function used by a TLS client for ECDHE
|
|
* ciphersuites.
|
|
*
|
|
* \see ecp.h
|
|
*
|
|
* \param ctx The ECDH context.
|
|
* \param buf The pointer to the start of the input buffer.
|
|
* \param end The address for one Byte past the end of the buffer.
|
|
*
|
|
* \return \c 0 on success.
|
|
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
|
|
*/
|
|
int mbedtls_everest_read_params(mbedtls_ecdh_context_everest *ctx,
|
|
const unsigned char **buf,
|
|
const unsigned char *end)
|
|
{
|
|
if (end - *buf < KEYSIZE + 1) return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
|
|
if ((*(*buf)++ != KEYSIZE)) return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
|
|
memcpy(ctx->peer_point, *buf, KEYSIZE);
|
|
*buf += KEYSIZE;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* \brief This function sets up an ECDH context from an EC key.
|
|
*
|
|
* It is used by clients and servers in place of the
|
|
* ServerKeyEchange for static ECDH, and imports ECDH
|
|
* parameters from the EC key information of a certificate.
|
|
*
|
|
* \see ecp.h
|
|
*
|
|
* \param ctx The ECDH context to set up.
|
|
* \param key The EC key to use.
|
|
* \param side Defines the source of the key: 1: Our key, or
|
|
* 0: The key of the peer.
|
|
*
|
|
* \return \c 0 on success.
|
|
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
|
|
*/
|
|
int mbedtls_everest_get_params(mbedtls_ecdh_context_everest *ctx,
|
|
const mbedtls_ecp_keypair *key,
|
|
mbedtls_everest_ecdh_side side)
|
|
{
|
|
size_t olen = 0;
|
|
mbedtls_everest_ecdh_side s;
|
|
switch (side)
|
|
{
|
|
case MBEDTLS_EVEREST_ECDH_THEIRS:
|
|
return mbedtls_ecp_point_write_binary(&key->grp, &key->Q,
|
|
MBEDTLS_ECP_PF_COMPRESSED, &olen,
|
|
ctx->peer_point, KEYSIZE);
|
|
case MBEDTLS_EVEREST_ECDH_OURS:
|
|
return mbedtls_mpi_write_binary_le(&key->d, ctx->our_secret, KEYSIZE);
|
|
default:
|
|
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief This function generates a public key and a TLS
|
|
* ClientKeyExchange payload.
|
|
*
|
|
* This is the second function used by a TLS client for ECDH(E)
|
|
* ciphersuites.
|
|
*
|
|
* \see ecp.h
|
|
*
|
|
* \param ctx The ECDH context.
|
|
* \param olen The number of Bytes written.
|
|
* \param buf The destination buffer.
|
|
* \param blen The size of the destination buffer.
|
|
* \param f_rng The RNG function.
|
|
* \param p_rng The RNG context.
|
|
*
|
|
* \return \c 0 on success.
|
|
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
|
|
*/
|
|
int mbedtls_everest_make_public(mbedtls_ecdh_context_everest *ctx, size_t *olen,
|
|
unsigned char *buf, size_t blen,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng)
|
|
{
|
|
int ret = 0;
|
|
unsigned char base[KEYSIZE] = {9};
|
|
if (!ctx) return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
|
|
if ((ret = f_rng(p_rng, ctx->our_secret, KEYSIZE))) return ret;
|
|
*olen = KEYSIZE + 1;
|
|
if (blen < *olen) return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
|
|
*buf++ = KEYSIZE;
|
|
curve25519(buf, ctx->our_secret, base);
|
|
base[0] = 0;
|
|
if (!timingsafe_memcmp(buf, base, KEYSIZE))
|
|
return MBEDTLS_ERR_ECP_RANDOM_FAILED;
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* \brief This function parses and processes a TLS ClientKeyExchange
|
|
* payload.
|
|
*
|
|
* This is the third function used by a TLS server for ECDH(E)
|
|
* ciphersuites. (It is called after mbedtls_ecdh_setup() and
|
|
* mbedtls_ecdh_make_params().)
|
|
*
|
|
* \see ecp.h
|
|
*
|
|
* \param ctx The ECDH context.
|
|
* \param buf The start of the input buffer.
|
|
* \param blen The length of the input buffer.
|
|
*
|
|
* \return \c 0 on success.
|
|
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
|
|
*/
|
|
int mbedtls_everest_read_public(mbedtls_ecdh_context_everest *ctx,
|
|
const unsigned char *buf, size_t blen)
|
|
{
|
|
if (blen < KEYSIZE + 1) return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
|
|
if ((*buf++ != KEYSIZE)) return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
|
|
memcpy(ctx->peer_point, buf, KEYSIZE);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* \brief This function derives and exports the shared secret.
|
|
*
|
|
* This is the last function used by both TLS client
|
|
* and servers.
|
|
*
|
|
* \note If \p f_rng is not NULL, it is used to implement
|
|
* countermeasures against side-channel attacks.
|
|
* For more information, see mbedtls_ecp_mul().
|
|
*
|
|
* \see ecp.h
|
|
*
|
|
* \param ctx The ECDH context.
|
|
* \param olen The number of Bytes written.
|
|
* \param buf The destination buffer.
|
|
* \param blen The length of the destination buffer.
|
|
* \param f_rng The RNG function.
|
|
* \param p_rng The RNG context.
|
|
*
|
|
* \return \c 0 on success.
|
|
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
|
|
*/
|
|
int mbedtls_everest_calc_secret(mbedtls_ecdh_context_everest *ctx, size_t *olen,
|
|
unsigned char *buf, size_t blen,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng)
|
|
{
|
|
/* f_rng and p_rng are not used here because this implementation does not
|
|
need blinding since it has constant trace. (todo(jart): wut?) */
|
|
*olen = KEYSIZE;
|
|
if (blen < *olen) return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
|
|
curve25519(buf, ctx->our_secret, ctx->peer_point);
|
|
if (!timingsafe_memcmp(buf, ctx->our_secret, KEYSIZE)) goto wut;
|
|
/* Wipe the DH secret and don't let the peer chose a small subgroup point */
|
|
mbedtls_platform_zeroize(ctx->our_secret, KEYSIZE);
|
|
if (!timingsafe_memcmp(buf, ctx->our_secret, KEYSIZE)) goto wut;
|
|
return 0;
|
|
wut:
|
|
mbedtls_platform_zeroize(buf, KEYSIZE);
|
|
mbedtls_platform_zeroize(ctx->our_secret, KEYSIZE);
|
|
return MBEDTLS_ERR_ECP_RANDOM_FAILED;
|
|
}
|
|
|
|
#endif
|