From a007c49d6fe44f9775ca83568896a8dddca6b854 Mon Sep 17 00:00:00 2001 From: HowJMay Date: Wed, 29 Jul 2020 16:50:18 +0800 Subject: [PATCH] feat(mam): Implement ECDH for MAM key exchange For #560 --- common/logger.h | 14 ++++++ common/ta_errors.c | 8 +++ common/ta_errors.h | 9 ++++ crypto/BUILD | 10 ++++ crypto/ecdh.c | 97 +++++++++++++++++++++++++++++++++++++ crypto/ecdh.h | 89 ++++++++++++++++++++++++++++++++++ tests/unit-test/BUILD | 11 +++++ tests/unit-test/test_ecdh.c | 57 ++++++++++++++++++++++ 8 files changed, 295 insertions(+) create mode 100644 crypto/BUILD create mode 100644 crypto/ecdh.c create mode 100644 crypto/ecdh.h create mode 100644 tests/unit-test/test_ecdh.c diff --git a/common/logger.h b/common/logger.h index 9fe6aaa3..b95a4381 100644 --- a/common/logger.h +++ b/common/logger.h @@ -294,6 +294,20 @@ void br_logger_init(); */ int br_logger_release(); +/** + * Initialize logger for ECDH + */ +void ecdh_logger_init(); + +/** + * Release logger + * + * @return + * - zero on success + * - EXIT_FAILURE on error + */ +int ecdh_logger_release(); + #ifdef __cplusplus } #endif diff --git a/common/ta_errors.c b/common/ta_errors.c index 572cb7b0..5c16acb5 100644 --- a/common/ta_errors.c +++ b/common/ta_errors.c @@ -197,6 +197,14 @@ const char* ta_error_to_string(status_t err) { case SC_ENDPOINT_DNS_RESOLVE_ERROR: return "Error occurred when resolving the domain name"; + // Crypto + case SC_CRYPTO_RAND_ERR: + return "Failed to generate random number generator"; + case SC_CRYPTO_GENKEY_ERR: + return "Failed to generate ECDH public key"; + case SC_CRYPTO_SECRET_ERR: + return "Failed to compute ECDH shared secret"; + default: return "Unknown error."; } diff --git a/common/ta_errors.h b/common/ta_errors.h index 51c2290f..173e64b1 100644 --- a/common/ta_errors.h +++ b/common/ta_errors.h @@ -57,6 +57,7 @@ extern "C" { #define SC_MODULE_STORAGE (0x0A << SC_MODULE_SHIFT) #define SC_MODULE_CORE (0x0B << SC_MODULE_SHIFT) #define SC_MODULE_ENDPOINT (0x0C << SC_MODULE_SHIFT) +#define SC_MODULE_CRYPTO (0x0D << SC_MODULE_SHIFT) /** @} */ /** @name serverity code */ @@ -255,6 +256,14 @@ typedef enum { SC_ENDPOINT_DNS_RESOLVE_ERROR = 0x0B | SC_MODULE_ENDPOINT | SC_SEVERITY_FATAL, /**< Failed to resolve the domain name address */ + // Crypto module + SC_CRYPTO_RAND_ERR = 0x01 | SC_MODULE_CRYPTO | SC_SEVERITY_FATAL, + /**< Failed to generate random number generator */ + SC_CRYPTO_GENKEY_ERR = 0x02 | SC_MODULE_CRYPTO | SC_SEVERITY_FATAL, + /**< Failed to generate ECDH public key */ + SC_CRYPTO_SECRET_ERR = 0x03 | SC_MODULE_CRYPTO | SC_SEVERITY_FATAL, + /**< Failed to compute ECDH shared secret */ + } status_t; typedef enum { 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..594da468 --- /dev/null +++ b/crypto/ecdh.c @@ -0,0 +1,97 @@ +/* + * 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. + */ +#include "crypto/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 rand_gen_init(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_ctr_drbg_init(ctr_drbg); + 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); + sc = SC_CRYPTO_RAND_ERR; + } + + 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); + sc = SC_CRYPTO_GENKEY_ERR; + 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); + sc = SC_CRYPTO_GENKEY_ERR; + goto exit; + } + + ret = mbedtls_mpi_write_binary(&ctx->Q.X, pkey, SHARE_DATA_LEN); + if (ret != 0) { + ta_log_error("mbedtls_mpi_write_binary returned %d\n", ret); + sc = SC_CRYPTO_GENKEY_ERR; + } + +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); + sc = SC_CRYPTO_SECRET_ERR; + goto exit; + } + + ret = mbedtls_mpi_read_binary(&ctx->Qp.X, input_shared_data, SHARE_DATA_LEN); + if (ret != 0) { + ta_log_error("mbedtls_mpi_read_binary returned %d\n", ret); + sc = SC_CRYPTO_SECRET_ERR; + 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); + sc = SC_CRYPTO_SECRET_ERR; + } + +exit: + return sc; +} + +void rand_gen_release(mbedtls_entropy_context *entropy, mbedtls_ctr_drbg_context *ctr_drbg) { + 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..f369ee24 --- /dev/null +++ b/crypto/ecdh.h @@ -0,0 +1,89 @@ +/* + * 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 + +#define SHARE_DATA_LEN 32 + +typedef struct rand_gen_s { + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; +} rand_gen_t; + +/** + * @brief Initialize mbedtls random number generator + * + * @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 rand_gen_init(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 random number generator + * + * @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 rand_gen_release(mbedtls_entropy_context *entropy, mbedtls_ctr_drbg_context *ctr_drbg); + +#ifdef __cplusplus +} +#endif + +#endif // ECDH_COMMON_H diff --git a/tests/unit-test/BUILD b/tests/unit-test/BUILD index 20e633be..1e5bcb06 100644 --- a/tests/unit-test/BUILD +++ b/tests/unit-test/BUILD @@ -98,3 +98,14 @@ cc_test( "//utils:tryte_byte_conv", ], ) + +cc_test( + name = "test_ecdh", + srcs = ["test_ecdh.c"], + deps = [ + "//crypto:ecdh", + "//tests:logger_lib", + "//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..256147df --- /dev/null +++ b/tests/unit-test/test_ecdh.c @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#include "crypto/ecdh.h" +#include "tests/test_define.h" + +void test_srv_cli_communication(void) { + rand_gen_t rand_gen; + mbedtls_ecdh_context ecdh_srv, ecdh_cli; + unsigned char cli_to_srv[SHARE_DATA_LEN], srv_to_cli[SHARE_DATA_LEN]; + + // initialize ECDH object for server side and client side + mbedtls_ecdh_init(&ecdh_srv); + mbedtls_ecdh_init(&ecdh_cli); + + TEST_ASSERT_EQUAL_INT32(SC_OK, + rand_gen_init(&rand_gen.entropy, &rand_gen.ctr_drbg, TEST_UUID, strlen(TEST_UUID) + 1)); + + // [client] initialize ECDH context and generate public key + TEST_ASSERT_EQUAL_INT32(SC_OK, ecdh_gen_public_key(&ecdh_cli, &rand_gen.ctr_drbg, cli_to_srv)); + + // [server] initialize ECDH context and generate public key + TEST_ASSERT_EQUAL_INT32(SC_OK, ecdh_gen_public_key(&ecdh_srv, &rand_gen.ctr_drbg, srv_to_cli)); + + // [server] compute shared secret with peer's public key + TEST_ASSERT_EQUAL_INT32(SC_OK, ecdh_compute_shared_secret(&ecdh_srv, &rand_gen.ctr_drbg, cli_to_srv)); + + // [client] compute shared secret with peer's public key + TEST_ASSERT_EQUAL_INT32(SC_OK, ecdh_compute_shared_secret(&ecdh_cli, &rand_gen.ctr_drbg, srv_to_cli)); + + // Check if the two shared secret are the same + TEST_ASSERT_EQUAL_INT32(0, mbedtls_mpi_cmp_mpi(&ecdh_cli.z, &ecdh_srv.z)); + + rand_gen_release(&rand_gen.entropy, &rand_gen.ctr_drbg); + mbedtls_ecdh_free(&ecdh_srv); + mbedtls_ecdh_free(&ecdh_cli); +} + +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(); +}