Path: blob/main/crypto/libecc/src/examples/basic/curve_ecdh.c
34889 views
/*1* Copyright (C) 2017 - This file is part of libecc project2*3* Authors:4* Ryad BENADJILA <[email protected]>5* Arnaud EBALARD <[email protected]>6* Jean-Pierre FLORI <[email protected]>7*8* Contributors:9* Nicolas VIVET <[email protected]>10* Karim KHALFALLAH <[email protected]>11*12* This software is licensed under a dual BSD and GPL v2 license.13* See LICENSE file at the root folder of the project.14*/15#include <libecc/lib_ecc_config.h>16#include <libecc/libec.h>1718/* We include the printf external dependency for printf output */19#include <libecc/external_deps/print.h>2021/*22* The purpose of this example is to implement a 'toy'23* ECDH (Elliptic curve Diffie-Hellman) protocol. Alice24* and Bob want to derive a secret 'x' without sharing the25* same secret key (using asymmetric cryptography). In order26* to do this, they agree upon a public Elliptic Curve with27* a generator G. Alice (resp. Bob) generates a private value28* d_Alice (resp. d_Bob) < q, where q is the order of G.29* Alice (resp. Bob) computes and shares Q_Alice = d_Alice x G30* (resp. Q_Bob = d_Bob x G) over a public channel. Alice31* and Bob now both can compute the same point Q such that32* Q = d_Alice x Q_Bob = d_Bob x Q_Alice, and the shared33* secret 'x' is the first coordinate of the curve point Q.34* External passive observers cannot compute 'x'.35*36* NOTE: We don't seek for communication bandwidth37* optimization here, this is why we use arrays to38* exchange affine coordinates points (and not39* the compressed x coordinate since the40* curve equation can be used).41*42* XXX NOTE: for a robust implementation of the ECDH43* primitives, please use the APIs provided in src/ecdh44* of libecc as they are suitable for "production". The45* purpose of the current toy example is only to show how46* one can manipulate the curve level APIs.47*48*/4950/* Zero buffer to detect empty buffers */51static u8 zero[2 * NN_MAX_BYTE_LEN] = { 0 };5253/*54* The following global variables simulate our shared "data bus"55* where Alice and Bob exchange data.56*/5758/* Global array holding Alice to Bob public value59* Q_Alice = d_Alice x G.60* This is a serialized affine EC point, holding61* 2 coordinates, meaning that its maximum size is62* 2 * NN_MAX_BYTE_LEN (i.e. this will work for63* all our curves).64*/65static u8 Alice_to_Bob[2 * NN_MAX_BYTE_LEN] = { 0 };6667/* Global array holding Bob to Alice public value68* Q_Bob = d_Bob x G.69* This is a serialized affine EC point, holding70* 2 coordinates, meaning that its maximum size is71* 2 * NN_MAX_BYTE_LEN. (i.e. this will work for72* all our curves).73*/74static u8 Bob_to_Alice[2 * NN_MAX_BYTE_LEN] = { 0 };7576static const u8 Alice[] = "Alice";77static const u8 Bob[] = "Bob";78#define CHECK_SIZE LOCAL_MIN(sizeof(Alice), sizeof(Bob))7980ATTRIBUTE_WARN_UNUSED_RET int ECDH_helper(const u8 *curve_name, const u8 *role);81int ECDH_helper(const u8 *curve_name, const u8 *role)82{83int ret, check1, check2;84/* The projective point we will use */85prj_pt Q;86/* The private scalar value for Alice and Bob, as well as their87* respective shared secrets.88* These are 'static' in order to keep them across multiple calls89* of the function.90*/91static nn d_Alice, d_Bob;92nn_t d = NULL;93static fp x_Alice, x_Bob;94fp_t x = NULL;95const char *x_str;96/* Pointers to the communication buffers */97u8 *our_public_buffer, *other_public_buffer;98u32 len;99100const ec_str_params *the_curve_const_parameters;101/* libecc internal structure holding the curve parameters */102ec_params curve_params;103104Q.magic = WORD(0);105106MUST_HAVE((curve_name != NULL) && (role != NULL), ret, err);107108/****** Alice => Bob *********************************************************/109ret = are_equal(role, Alice, CHECK_SIZE, &check1); EG(ret, err);110ret = are_equal(role, Bob, CHECK_SIZE, &check2); EG(ret, err);111if (check1) {112our_public_buffer = Alice_to_Bob;113other_public_buffer = Bob_to_Alice;114d = &d_Alice;115x = &x_Alice;116x_str = " x_Alice";117}118/****** Bob => Alice *********************************************************/119else if (check2) {120our_public_buffer = Bob_to_Alice;121other_public_buffer = Alice_to_Bob;122d = &d_Bob;123x = &x_Bob;124x_str = " x_Bob ";125}126else {127/* Unknown role, get out */128ext_printf(" Error: unknown role %s for ECDH\n", role);129ret = -1;130goto err;131}132133/* Importing specific curve parameters from the constant static134* buffers describing it:135* It is possible to import a curve set of parameters by its name.136*/137ret = local_strnlen((const char *)curve_name, MAX_CURVE_NAME_LEN, &len); EG(ret, err);138len += 1;139MUST_HAVE((len < 256), ret, err);140ret = ec_get_curve_params_by_name(curve_name,141(u8)len, &the_curve_const_parameters); EG(ret, err);142/* Get out if getting the parameters went wrong */143if (the_curve_const_parameters == NULL) {144ext_printf(" Error: error when importing curve %s "145"parameters ...\n", curve_name);146ret = -1;147goto err;148}149/* Now map the curve parameters to our libecc internal representation */150ret = import_params(&curve_params, the_curve_const_parameters); EG(ret, err);151152/* Initialize our projective point with the curve parameters */153ret = prj_pt_init(&Q, &(curve_params.ec_curve)); EG(ret, err);154ret = are_equal(our_public_buffer, zero, sizeof(zero), &check1); EG(ret, err);155if (!check1) {156/* We have already generated and sent our parameters, skip to157* the state where we wait for the other party to generate and158* send us data.159*/160goto generate_shared_secret;161}162163/* Generate our ECDH parameters: a private scalar d and a public value Q = dG where G is the164* curve generator.165* d = random mod (q) where q is the order of the generator G.166*/167ret = nn_init(d, 0); EG(ret, err);168ret = nn_get_random_mod(d, &(curve_params.ec_gen_order)); EG(ret, err);169170/* Q = dG */171ret = prj_pt_mul(&Q, d, &(curve_params.ec_gen)); EG(ret, err);172173/* Now send the public value Q to the other party, get the other party174* public value and compute the shared secret.175* Our export size is exactly 2 coordinates in Fp (affine point representation),176* so this should be 2 times the size of an element in Fp.177*/178ret = prj_pt_export_to_aff_buf(&Q, our_public_buffer,179(u32)(2 * BYTECEIL(curve_params.ec_fp.p_bitlen))); EG(ret, err);180181generate_shared_secret:182/* Now (non blocking) wait for the other party to send us its public value */183ret = are_equal(other_public_buffer, zero, sizeof(zero), &check1); EG(ret, err);184if (check1) {185/* Other party has not sent its public value yet! */186ret = 0;187goto err;188}189/* If our private value d is not initialized, this means that we have already190* done the job of computing the shared secret!191*/192if (nn_check_initialized(d)) {193ret = 1;194goto err;195}196/* Import the shared value as a projective point from an affine point buffer197*/198ret = prj_pt_import_from_aff_buf(&Q, other_public_buffer,199(u16)(2 * BYTECEIL(curve_params.ec_fp.p_bitlen)),200&(curve_params.ec_curve)); EG(ret, err);201/* Compute the shared value = first coordinate of dQ */202ret = prj_pt_mul(&Q, d, &Q); EG(ret, err);203/* Move to the unique representation */204/* Compute the affine coordinates to get the unique (x, y) representation205* (projective points are equivalent by a z scalar)206*/207ret = prj_pt_unique(&Q, &Q); EG(ret, err);208ext_printf(" ECDH shared secret computed by %s:\n", role);209/* The shared secret 'x' is the first coordinate of Q */210ret = fp_init(x, &(curve_params.ec_fp)); EG(ret, err);211ret = fp_copy(x, &(Q.X)); EG(ret, err);212fp_print(x_str, x);213214ret = 1;215216/* Uninit local variables */217prj_pt_uninit(&Q);218if(x != NULL){219fp_uninit(x);220}221if(d != NULL){222nn_uninit(d);223}224225err:226return ret;227}228229#ifdef CURVE_ECDH230int main(int argc, char *argv[])231{232unsigned int i;233u8 curve_name[MAX_CURVE_NAME_LEN] = { 0 };234int ret;235FORCE_USED_VAR(argc);236FORCE_USED_VAR(argv);237238/* Traverse all the possible curves we have at our disposal (known curves and239* user defined curves).240*/241for (i = 0; i < EC_CURVES_NUM; i++) {242ret = local_memset(Alice_to_Bob, 0, sizeof(Alice_to_Bob)); EG(ret, err);243ret = local_memset(Bob_to_Alice, 0, sizeof(Bob_to_Alice)); EG(ret, err);244/* All our possible curves are in ../curves/curves_list.h245* We can get the curve name from its internal type.246*/247if(ec_get_curve_name_by_type(ec_maps[i].type, curve_name,248sizeof(curve_name))){249ret = -1;250ext_printf("Error: error when treating %s\n", curve_name);251goto err;252}253/* Perform ECDH between Alice and Bob! */254ext_printf("[+] ECDH on curve %s\n", curve_name);255if(ECDH_helper(curve_name, Alice) != 0){256ret = -1;257ext_printf("Error: error in ECDH_helper\n");258goto err;259}260if(ECDH_helper(curve_name, Bob) != 1){261ret = -1;262ext_printf("Error: error in ECDH_helper\n");263goto err;264}265/* We have to call our ECDH helper again for Alice266* since she was waiting for Bob to send his public data.267* This is our loose way of dealing with 'concurrency'268* without threads ...269*/270if(ECDH_helper(curve_name, Alice) != 1){271ret = -1;272ext_printf("Error: error in ECDH_helper\n");273goto err;274}275ext_printf("==================================\n");276}277278ret = 0;279280err:281return ret;282}283#endif /* CURVE_ECDH */284285286