From 5811e729408067eea57b91000f58b55fd38e25b1 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 16 Nov 2018 14:22:48 -0800 Subject: [PATCH] ecdh: added ECDH module --- Makefile.am | 1 + src/ecdh.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ecdh.h | 27 +++++++++ 3 files changed, 200 insertions(+) create mode 100644 src/ecdh.c create mode 100644 src/ecdh.h diff --git a/Makefile.am b/Makefile.am index db64c385..8e7581ab 100644 --- a/Makefile.am +++ b/Makefile.am @@ -184,6 +184,7 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h \ src/adhoc.h src/adhoc.c \ src/sae.h src/sae.c \ src/nl80211util.h src/nl80211util.c \ + src/ecdh.h src/ecdh.c \ $(eap_sources) \ $(builtin_sources) src_iwd_LDADD = $(ell_ldadd) -ldl diff --git a/src/ecdh.c b/src/ecdh.c new file mode 100644 index 00000000..062bdfa9 --- /dev/null +++ b/src/ecdh.c @@ -0,0 +1,172 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#include "ecdh.h" +#include "ecc.h" + +static struct ecc_point p256_generator = CURVE_G_32; +static uint64_t p256_prime[4] = CURVE_P_32; +/* + * IETF - Compact representation of an elliptic curve point: + * https://tools.ietf.org/id/draft-jivsov-ecc-compact-00.xml + * + * "min(y,p-y) can be calculated with the help of the pre-calculated value + * p2=(p-1)/2. min(y,p-y) is y if y 64) + return false; + + while (!compliant && iter++ < ECDH_MAX_ITERATIONS) { + if (!l_getrandom(private, priv_len)) + return false; + + /* private * G(x,y) = public key */ + ecc_point_mult(&pub, &p256_generator, + (uint64_t *)private, NULL, + vli_num_bits((uint64_t *)private)); + + /* ensure public key is compliant */ + if (vli_cmp(pub.y, p2) >= 0) { + compliant = true; + break; + } + } + + if (!compliant) { + l_error("could not generate a compliant public key pair"); + return false; + } + + ecc_native2be(pub.x); + ecc_native2be(pub.y); + + memcpy(public, &pub, pub_len); + + return true; +} + +/* + * IETF draft-jivsov-ecc-compact-00 Section 4.1 + * Encoding and decoding of an elliptic curve point + * ... + * Decoding: + * Given the compact representation of Q, return canonical representation + * of Q=(x,y) as follows: + * 1. y' = sqrt( x^3 + a*x + b ), where y'>0 + * 2. y = min(y',p-y') + * 3. Q=(x,y) is the canonical representation of the point + */ +static bool decode_point(const uint64_t *x, struct ecc_point *point) +{ + uint64_t y_min[4]; + + if (!ecc_compute_y(y_min, (uint64_t *)x)) + return false; + + if (vli_cmp(y_min, p2) >= 0) + vli_mod_sub(point->y, p256_prime, y_min, p256_prime); + else + memcpy(point->y, y_min, 32); + + memcpy(point->x, x, 32); + + return true; +} + +bool ecdh_generate_shared_secret(const void *private, const void *other_public, + size_t pub_len, void *secret, + size_t secret_len) +{ + struct ecc_point product; + struct ecc_point public; + uint64_t z[4]; + uint64_t x[4]; + + if (secret_len > 32) + return false; + /* + * TODO: Once other ECC groups are added this will need to be modified + * to check for 1/2 the full public key lengths + */ + if (pub_len == 32) { + /* + * Only half the public key was given, the remainder (Y) must + * be decoded. + */ + memcpy(x, other_public, 32); + ecc_be2native(x); + + if (!decode_point(x, &public)) { + l_error("could not decode compressed public key"); + return false; + } + } else if (pub_len == 64) { + memcpy(&public, other_public, 64); + + ecc_be2native(public.x); + ecc_be2native(public.y); + } else { + l_error("unsupported public key length %ld", pub_len); + return false; + } + + if (!l_getrandom(z, sizeof(z))) + return false; + + ecc_point_mult(&product, &public, (uint64_t *)private, z, + vli_num_bits(private)); + + ecc_native2be(product.x); + + memcpy(secret, product.x, secret_len); + + return true; +} diff --git a/src/ecdh.h b/src/ecdh.h new file mode 100644 index 00000000..502fbab8 --- /dev/null +++ b/src/ecdh.h @@ -0,0 +1,27 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +bool ecdh_generate_key_pair(void *private, size_t priv_len, + void *public, size_t pub_len); +bool ecdh_generate_shared_secret(const void *private, const void *other_public, + size_t pub_len, void *secret, + size_t secret_len);