/* * * Embedded Linux library * * 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 * */ #ifdef HAVE_CONFIG_H #include #endif #include #include "private.h" #include "ecc-private.h" #include "ecc.h" #include "ecdh.h" #include "random.h" /* * Some sane maximum for calculating the public key. */ #define ECDH_MAX_ITERATIONS 20 /* * IETF draft-jivsov-ecc-compact-00 Section 4.2.1 * * The following algorithm calculates a key pair {k, Q=k*G=(x,y)}, where k is * the private key and Q=(x,y) is the public key. * * Black box generation: * 1. Generate a key pair {k, Q=k*G=(x,y)} with KG * 2. if( y != min(y,p-y) ) goto step 1 * 3. output {k, Q=(x,y)} as a key pair */ LIB_EXPORT bool l_ecdh_generate_key_pair(const struct l_ecc_curve *curve, struct l_ecc_scalar **out_private, struct l_ecc_point **out_public) { bool compliant = false; int iter = 0; uint64_t p2[L_ECC_MAX_DIGITS]; _ecc_calculate_p2(curve, p2); *out_public = l_ecc_point_new(curve); while (!compliant && iter++ < ECDH_MAX_ITERATIONS) { *out_private = l_ecc_scalar_new_random(curve); _ecc_point_mult(*out_public, &curve->g, (*out_private)->c, NULL, curve->p); /* ensure public key is compliant */ if (_vli_cmp((*out_public)->y, p2, curve->ndigits) >= 0) { compliant = true; break; } l_ecc_scalar_free(*out_private); } if (!compliant) { l_ecc_point_free(*out_public); return false; } return true; } LIB_EXPORT bool l_ecdh_generate_shared_secret( const struct l_ecc_scalar *private_key, const struct l_ecc_point *other_public, struct l_ecc_scalar **secret) { const struct l_ecc_curve *curve = private_key->curve; struct l_ecc_scalar *z; struct l_ecc_point *product; z = l_ecc_scalar_new_random(curve); product = l_ecc_point_new(curve); _ecc_point_mult(product, other_public, private_key->c, z->c, curve->p); *secret = _ecc_constant_new(curve, product->x, curve->ndigits * 8); l_ecc_point_free(product); l_ecc_scalar_free(z); return true; }