diff --git a/crypto/BUILD b/crypto/BUILD new file mode 100644 index 00000000..f7a087c3 --- /dev/null +++ b/crypto/BUILD @@ -0,0 +1,10 @@ +cc_library( + name = "ecdh", + srcs = ["ecdh.c"], + hdrs = ["ecdh.h"], + visibility = ["//visibility:public"], + deps = [ + "//common", + "@mbedtls", + ], +) diff --git a/crypto/ecdh.c b/crypto/ecdh.c new file mode 100644 index 00000000..e46fe982 --- /dev/null +++ b/crypto/ecdh.c @@ -0,0 +1,94 @@ +#include "ecdh.h" + +#define ECDH_LOGGER "ecdh" +static logger_id_t logger_id; + +void ecdh_logger_init() { logger_id = logger_helper_enable(ECDH_LOGGER, LOGGER_DEBUG, true); } + +int ecdh_logger_release() { + logger_helper_release(logger_id); + return 0; +} + +status_t ecdh_ctx_init(ecdh_ctx_t *ecdh_ctx, mbedtls_entropy_context *entropy, mbedtls_ctr_drbg_context *ctr_drbg, + char *rand_seed, uint16_t seed_len) { + int ret = 1; + status_t sc = SC_OK; + mbedtls_ecdh_init(&ecdh_ctx->ctx); + + if (entropy && ctr_drbg) { + mbedtls_ctr_drbg_init(ctr_drbg); + + /* + * Initialize random number generation + */ + mbedtls_entropy_init(entropy); + if ((ret = mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy, (const unsigned char *)rand_seed, + seed_len)) != 0) { + ta_log_error("mbedtls_ctr_drbg_seed returned %d\n", ret); + goto exit; + } + } + +exit: + return sc; +} + +status_t ecdh_gen_public_key(mbedtls_ecdh_context *ctx, mbedtls_ctr_drbg_context *ctr_drbg, unsigned char *pkey) { + int ret = 1; + status_t sc = SC_OK; + + ret = mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_CURVE25519); + if (ret != 0) { + ta_log_error("mbedtls_ecp_group_load returned %d\n", ret); + goto exit; + } + + ret = mbedtls_ecdh_gen_public(&ctx->grp, &ctx->d, &ctx->Q, mbedtls_ctr_drbg_random, ctr_drbg); + if (ret != 0) { + ta_log_error("mbedtls_ecdh_gen_public returned %d\n", ret); + goto exit; + } + + ret = mbedtls_mpi_write_binary(&ctx->Q.X, pkey, 32); + if (ret != 0) { + ta_log_error("mbedtls_mpi_write_binary returned %d\n", ret); + goto exit; + } + +exit: + return sc; +} + +status_t ecdh_compute_shared_secret(mbedtls_ecdh_context *ctx, mbedtls_ctr_drbg_context *ctr_drbg, + unsigned char *input_shared_data) { + int ret = 1; + status_t sc = SC_OK; + + ret = mbedtls_mpi_lset(&ctx->Qp.Z, 1); + if (ret != 0) { + ta_log_error("mbedtls_mpi_lset returned %d\n", ret); + goto exit; + } + + ret = mbedtls_mpi_read_binary(&ctx->Qp.X, input_shared_data, 32); + if (ret != 0) { + ta_log_error("mbedtls_mpi_read_binary returned %d\n", ret); + goto exit; + } + + ret = mbedtls_ecdh_compute_shared(&ctx->grp, &ctx->z, &ctx->Qp, &ctx->d, mbedtls_ctr_drbg_random, ctr_drbg); + if (ret != 0) { + ta_log_error("mbedtls_ecdh_compute_shared returned %d\n", ret); + goto exit; + } + +exit: + return sc; +} + +void ecdh_ctx_release(ecdh_ctx_t *ecdh_ctx, mbedtls_entropy_context *entropy, mbedtls_ctr_drbg_context *ctr_drbg) { + mbedtls_ecdh_free(&ecdh_ctx->ctx); + mbedtls_ctr_drbg_free(ctr_drbg); + mbedtls_entropy_free(entropy); +} diff --git a/crypto/ecdh.h b/crypto/ecdh.h new file mode 100644 index 00000000..4641304a --- /dev/null +++ b/crypto/ecdh.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 BiiLabs Co., Ltd. and Contributors + * All Rights Reserved. + * This is free software; you can redistribute it and/or modify it under the + * terms of the MIT license. A copy of the license can be found in the file + * "LICENSE" at the root of this distribution. + */ + +#ifndef ECDH_COMMON_H +#define ECDH_COMMON_H + +#include "common/logger.h" +#include "common/ta_errors.h" +#include "mbedtls/config.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/entropy.h" +#include "mbedtls/platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ecdh_ctx_s { + mbedtls_ecdh_context ctx; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; +} ecdh_ctx_t; + +void ecdh_logger_init(); + +int ecdh_logger_release(); + +/** + * @brief Initialize tangle-accelerator ECDH object and random number generator + * + * @param[in] ecdh_ctx tangle-accelerator ECDH object + * @param[in] entropy Entropy contrext for randomess + * @param[in] ctr_drbg Counter-mode block-cipher-based Deterministic Random Bit Generator object + * @param[in] rand_seed Random seed for random number generator + * @param[in] seed_len The length of random seed + * + * @return + * - SC_OK on success + * - non-zero on error + */ +status_t ecdh_ctx_init(ecdh_ctx_t *ecdh_ctx, mbedtls_entropy_context *entropy, mbedtls_ctr_drbg_context *ctr_drbg, + char *rand_seed, uint16_t seed_len); + +/** + * @brief Initialize ECDH context and generate ECDH keypair + * + * @param[in] ctx ECDH context + * @param[in] ctr_drbg Counter-mode block-cipher-based Deterministic Random Bit Generator object + * @param[out] pkey Output public key which would be sent to counterpart + * + * @return + * - SC_OK on success + * - non-zero on error + */ +status_t ecdh_gen_public_key(mbedtls_ecdh_context *ctx, mbedtls_ctr_drbg_context *ctr_drbg, unsigned char *pkey); + +/** + * @brief Compute the shared secret by Diffie–Hellman key exchange protocol + * + * @param[in] ctx ECDH context + * @param[in] ctr_drbg Counter-mode block-cipher-based Deterministic Random Bit Generator object + * @param[in] input_shared_data The public key sent by counterpart + * + * @return + * - SC_OK on success + * - non-zero on error + */ +status_t ecdh_compute_shared_secret(mbedtls_ecdh_context *ctx, mbedtls_ctr_drbg_context *ctr_drbg, + unsigned char *input_shared_data); + +/** + * @brief Release tangle-accelerator ECDH object and random number generator + * + * @param[in] ecdh_ctx tangle-accelerator ECDH object + * @param[in] entropy Entropy contrext for randomess + * @param[in] ctr_drbg Counter-mode block-cipher-based Deterministic Random Bit Generator object + * + * @return + * - SC_OK on success + * - non-zero on error + */ +void ecdh_ctx_release(ecdh_ctx_t *ecdh_ctx, mbedtls_entropy_context *entropy, mbedtls_ctr_drbg_context *ctr_drbg); + +#ifdef __cplusplus +} +#endif + +#endif // ECDH_COMMON_H diff --git a/tests/endpoint/common.sh b/tests/endpoint/common.sh index bd5ade59..4d05e99f 100644 --- a/tests/endpoint/common.sh +++ b/tests/endpoint/common.sh @@ -34,7 +34,7 @@ function validate_host() { if [[ $1 =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then return 0 fi - if host "$1" > /dev/null 2>&1; then + if host "$1" >/dev/null 2>&1; then return 0 fi echo "Please enter a valid host or ip address" diff --git a/tests/unit-test/BUILD b/tests/unit-test/BUILD index 20e633be..fea2837b 100644 --- a/tests/unit-test/BUILD +++ b/tests/unit-test/BUILD @@ -98,3 +98,13 @@ cc_test( "//utils:tryte_byte_conv", ], ) + +cc_binary( + name = "test_ecdh", + srcs = ["test_ecdh.c"], + deps = [ + "//crypto:ecdh", + "//tests:test_define", + "@mbedtls", + ], +) diff --git a/tests/unit-test/test_ecdh.c b/tests/unit-test/test_ecdh.c new file mode 100644 index 00000000..688c38fc --- /dev/null +++ b/tests/unit-test/test_ecdh.c @@ -0,0 +1,51 @@ +#include "crypto/ecdh.h" +#include "tests/test_define.h" + +void test_srv_cli_communication(void) { + ecdh_ctx_t ecdh_cli, ecdh_srv; + unsigned char cli_to_srv[32], srv_to_cli[32]; + + TEST_ASSERT_EQUAL_INT32( + SC_OK, ecdh_ctx_init(&ecdh_srv, &ecdh_srv.entropy, &ecdh_srv.ctr_drbg, TEST_UUID, strlen(TEST_UUID) + 1)); + TEST_ASSERT_EQUAL_INT32(SC_OK, ecdh_ctx_init(&ecdh_cli, NULL, NULL, NULL, 0)); + + TEST_ASSERT_EQUAL_INT32(SC_OK, ecdh_gen_public_key(&ecdh_cli.ctx, &ecdh_srv.ctr_drbg, cli_to_srv)); + + /* + * Server: initialize context and generate keypair + */ + TEST_ASSERT_EQUAL_INT32(SC_OK, ecdh_gen_public_key(&ecdh_srv.ctx, &ecdh_srv.ctr_drbg, srv_to_cli)); + + /* + * Server: read peer's key and generate shared secret + */ + TEST_ASSERT_EQUAL_INT32(SC_OK, ecdh_compute_shared_secret(&ecdh_srv.ctx, &ecdh_srv.ctr_drbg, cli_to_srv)); + + /* + * Client: read peer's key and generate shared secret + */ + TEST_ASSERT_EQUAL_INT32(SC_OK, ecdh_compute_shared_secret(&ecdh_cli.ctx, &ecdh_srv.ctr_drbg, srv_to_cli)); + + /* + * Verification: are the computed secrets equal? + */ + TEST_ASSERT_EQUAL_INT32(0, mbedtls_mpi_cmp_mpi(&ecdh_cli.ctx.z, &ecdh_srv.ctx.z)); + + ecdh_ctx_release(&ecdh_srv, &ecdh_srv.entropy, &ecdh_srv.ctr_drbg); + mbedtls_ecdh_free(&ecdh_cli.ctx); +} + +int main(void) { + UNITY_BEGIN(); + + // Initialize logger + if (ta_logger_init() != SC_OK) { + return EXIT_FAILURE; + } + + ecdh_logger_init(); + RUN_TEST(test_srv_cli_communication); + ecdh_logger_release(); + + return UNITY_END(); +}