1a8e1175bSopenharmony_ci/* 2a8e1175bSopenharmony_ci * Diffie-Hellman-Merkle key exchange (client side) 3a8e1175bSopenharmony_ci * 4a8e1175bSopenharmony_ci * Copyright The Mbed TLS Contributors 5a8e1175bSopenharmony_ci * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6a8e1175bSopenharmony_ci */ 7a8e1175bSopenharmony_ci 8a8e1175bSopenharmony_ci#include "mbedtls/build_info.h" 9a8e1175bSopenharmony_ci 10a8e1175bSopenharmony_ci#include "mbedtls/platform.h" 11a8e1175bSopenharmony_ci/* md.h is included this early since MD_CAN_XXX macros are defined there. */ 12a8e1175bSopenharmony_ci#include "mbedtls/md.h" 13a8e1175bSopenharmony_ci 14a8e1175bSopenharmony_ci#if defined(MBEDTLS_AES_C) && defined(MBEDTLS_DHM_C) && \ 15a8e1175bSopenharmony_ci defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_NET_C) && \ 16a8e1175bSopenharmony_ci defined(MBEDTLS_RSA_C) && defined(MBEDTLS_SHA256_C) && \ 17a8e1175bSopenharmony_ci defined(MBEDTLS_FS_IO) && defined(MBEDTLS_CTR_DRBG_C) 18a8e1175bSopenharmony_ci#include "mbedtls/net_sockets.h" 19a8e1175bSopenharmony_ci#include "mbedtls/aes.h" 20a8e1175bSopenharmony_ci#include "mbedtls/dhm.h" 21a8e1175bSopenharmony_ci#include "mbedtls/rsa.h" 22a8e1175bSopenharmony_ci#include "mbedtls/sha256.h" 23a8e1175bSopenharmony_ci#include "mbedtls/entropy.h" 24a8e1175bSopenharmony_ci#include "mbedtls/ctr_drbg.h" 25a8e1175bSopenharmony_ci 26a8e1175bSopenharmony_ci#include <stdio.h> 27a8e1175bSopenharmony_ci#include <string.h> 28a8e1175bSopenharmony_ci#endif 29a8e1175bSopenharmony_ci 30a8e1175bSopenharmony_ci#define SERVER_NAME "localhost" 31a8e1175bSopenharmony_ci#define SERVER_PORT "11999" 32a8e1175bSopenharmony_ci 33a8e1175bSopenharmony_ci#if !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_DHM_C) || \ 34a8e1175bSopenharmony_ci !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_NET_C) || \ 35a8e1175bSopenharmony_ci !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_SHA256_C) || \ 36a8e1175bSopenharmony_ci !defined(MBEDTLS_FS_IO) || !defined(MBEDTLS_CTR_DRBG_C) 37a8e1175bSopenharmony_ciint main(void) 38a8e1175bSopenharmony_ci{ 39a8e1175bSopenharmony_ci mbedtls_printf("MBEDTLS_AES_C and/or MBEDTLS_DHM_C and/or MBEDTLS_ENTROPY_C " 40a8e1175bSopenharmony_ci "and/or MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or " 41a8e1175bSopenharmony_ci "MBEDTLS_MD_CAN_SHA256 and/or MBEDTLS_FS_IO and/or " 42a8e1175bSopenharmony_ci "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_SHA1_C not defined.\n"); 43a8e1175bSopenharmony_ci mbedtls_exit(0); 44a8e1175bSopenharmony_ci} 45a8e1175bSopenharmony_ci 46a8e1175bSopenharmony_ci#elif defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT) 47a8e1175bSopenharmony_ciint main(void) 48a8e1175bSopenharmony_ci{ 49a8e1175bSopenharmony_ci mbedtls_printf("MBEDTLS_BLOCK_CIPHER_NO_DECRYPT defined.\n"); 50a8e1175bSopenharmony_ci mbedtls_exit(0); 51a8e1175bSopenharmony_ci} 52a8e1175bSopenharmony_ci#else 53a8e1175bSopenharmony_ci 54a8e1175bSopenharmony_ci 55a8e1175bSopenharmony_ciint main(void) 56a8e1175bSopenharmony_ci{ 57a8e1175bSopenharmony_ci FILE *f; 58a8e1175bSopenharmony_ci 59a8e1175bSopenharmony_ci int ret = 1; 60a8e1175bSopenharmony_ci int exit_code = MBEDTLS_EXIT_FAILURE; 61a8e1175bSopenharmony_ci unsigned int mdlen; 62a8e1175bSopenharmony_ci size_t n, buflen; 63a8e1175bSopenharmony_ci mbedtls_net_context server_fd; 64a8e1175bSopenharmony_ci 65a8e1175bSopenharmony_ci unsigned char *p, *end; 66a8e1175bSopenharmony_ci unsigned char buf[2048]; 67a8e1175bSopenharmony_ci unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 68a8e1175bSopenharmony_ci mbedtls_mpi N, E; 69a8e1175bSopenharmony_ci const char *pers = "dh_client"; 70a8e1175bSopenharmony_ci 71a8e1175bSopenharmony_ci mbedtls_entropy_context entropy; 72a8e1175bSopenharmony_ci mbedtls_ctr_drbg_context ctr_drbg; 73a8e1175bSopenharmony_ci mbedtls_rsa_context rsa; 74a8e1175bSopenharmony_ci mbedtls_dhm_context dhm; 75a8e1175bSopenharmony_ci mbedtls_aes_context aes; 76a8e1175bSopenharmony_ci 77a8e1175bSopenharmony_ci mbedtls_net_init(&server_fd); 78a8e1175bSopenharmony_ci mbedtls_dhm_init(&dhm); 79a8e1175bSopenharmony_ci mbedtls_aes_init(&aes); 80a8e1175bSopenharmony_ci mbedtls_ctr_drbg_init(&ctr_drbg); 81a8e1175bSopenharmony_ci mbedtls_mpi_init(&N); 82a8e1175bSopenharmony_ci mbedtls_mpi_init(&E); 83a8e1175bSopenharmony_ci 84a8e1175bSopenharmony_ci /* 85a8e1175bSopenharmony_ci * 1. Setup the RNG 86a8e1175bSopenharmony_ci */ 87a8e1175bSopenharmony_ci mbedtls_printf("\n . Seeding the random number generator"); 88a8e1175bSopenharmony_ci fflush(stdout); 89a8e1175bSopenharmony_ci 90a8e1175bSopenharmony_ci mbedtls_entropy_init(&entropy); 91a8e1175bSopenharmony_ci if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, 92a8e1175bSopenharmony_ci (const unsigned char *) pers, 93a8e1175bSopenharmony_ci strlen(pers))) != 0) { 94a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret); 95a8e1175bSopenharmony_ci goto exit; 96a8e1175bSopenharmony_ci } 97a8e1175bSopenharmony_ci 98a8e1175bSopenharmony_ci /* 99a8e1175bSopenharmony_ci * 2. Read the server's public RSA key 100a8e1175bSopenharmony_ci */ 101a8e1175bSopenharmony_ci mbedtls_printf("\n . Reading public key from rsa_pub.txt"); 102a8e1175bSopenharmony_ci fflush(stdout); 103a8e1175bSopenharmony_ci 104a8e1175bSopenharmony_ci if ((f = fopen("rsa_pub.txt", "rb")) == NULL) { 105a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! Could not open rsa_pub.txt\n" \ 106a8e1175bSopenharmony_ci " ! Please run rsa_genkey first\n\n"); 107a8e1175bSopenharmony_ci goto exit; 108a8e1175bSopenharmony_ci } 109a8e1175bSopenharmony_ci 110a8e1175bSopenharmony_ci mbedtls_rsa_init(&rsa); 111a8e1175bSopenharmony_ci if ((ret = mbedtls_mpi_read_file(&N, 16, f)) != 0 || 112a8e1175bSopenharmony_ci (ret = mbedtls_mpi_read_file(&E, 16, f)) != 0 || 113a8e1175bSopenharmony_ci (ret = mbedtls_rsa_import(&rsa, &N, NULL, NULL, NULL, &E) != 0)) { 114a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_mpi_read_file returned %d\n\n", ret); 115a8e1175bSopenharmony_ci fclose(f); 116a8e1175bSopenharmony_ci goto exit; 117a8e1175bSopenharmony_ci } 118a8e1175bSopenharmony_ci fclose(f); 119a8e1175bSopenharmony_ci 120a8e1175bSopenharmony_ci /* 121a8e1175bSopenharmony_ci * 3. Initiate the connection 122a8e1175bSopenharmony_ci */ 123a8e1175bSopenharmony_ci mbedtls_printf("\n . Connecting to tcp/%s/%s", SERVER_NAME, 124a8e1175bSopenharmony_ci SERVER_PORT); 125a8e1175bSopenharmony_ci fflush(stdout); 126a8e1175bSopenharmony_ci 127a8e1175bSopenharmony_ci if ((ret = mbedtls_net_connect(&server_fd, SERVER_NAME, 128a8e1175bSopenharmony_ci SERVER_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) { 129a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_net_connect returned %d\n\n", ret); 130a8e1175bSopenharmony_ci goto exit; 131a8e1175bSopenharmony_ci } 132a8e1175bSopenharmony_ci 133a8e1175bSopenharmony_ci /* 134a8e1175bSopenharmony_ci * 4a. First get the buffer length 135a8e1175bSopenharmony_ci */ 136a8e1175bSopenharmony_ci mbedtls_printf("\n . Receiving the server's DH parameters"); 137a8e1175bSopenharmony_ci fflush(stdout); 138a8e1175bSopenharmony_ci 139a8e1175bSopenharmony_ci memset(buf, 0, sizeof(buf)); 140a8e1175bSopenharmony_ci 141a8e1175bSopenharmony_ci if ((ret = mbedtls_net_recv(&server_fd, buf, 2)) != 2) { 142a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_net_recv returned %d\n\n", ret); 143a8e1175bSopenharmony_ci goto exit; 144a8e1175bSopenharmony_ci } 145a8e1175bSopenharmony_ci 146a8e1175bSopenharmony_ci n = buflen = (buf[0] << 8) | buf[1]; 147a8e1175bSopenharmony_ci if (buflen < 1 || buflen > sizeof(buf)) { 148a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! Got an invalid buffer length\n\n"); 149a8e1175bSopenharmony_ci goto exit; 150a8e1175bSopenharmony_ci } 151a8e1175bSopenharmony_ci 152a8e1175bSopenharmony_ci /* 153a8e1175bSopenharmony_ci * 4b. Get the DHM parameters: P, G and Ys = G^Xs mod P 154a8e1175bSopenharmony_ci */ 155a8e1175bSopenharmony_ci memset(buf, 0, sizeof(buf)); 156a8e1175bSopenharmony_ci 157a8e1175bSopenharmony_ci if ((ret = mbedtls_net_recv(&server_fd, buf, n)) != (int) n) { 158a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_net_recv returned %d\n\n", ret); 159a8e1175bSopenharmony_ci goto exit; 160a8e1175bSopenharmony_ci } 161a8e1175bSopenharmony_ci 162a8e1175bSopenharmony_ci p = buf, end = buf + buflen; 163a8e1175bSopenharmony_ci 164a8e1175bSopenharmony_ci if ((ret = mbedtls_dhm_read_params(&dhm, &p, end)) != 0) { 165a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_dhm_read_params returned %d\n\n", ret); 166a8e1175bSopenharmony_ci goto exit; 167a8e1175bSopenharmony_ci } 168a8e1175bSopenharmony_ci 169a8e1175bSopenharmony_ci n = mbedtls_dhm_get_len(&dhm); 170a8e1175bSopenharmony_ci if (n < 64 || n > 512) { 171a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! Invalid DHM modulus size\n\n"); 172a8e1175bSopenharmony_ci goto exit; 173a8e1175bSopenharmony_ci } 174a8e1175bSopenharmony_ci 175a8e1175bSopenharmony_ci /* 176a8e1175bSopenharmony_ci * 5. Check that the server's RSA signature matches 177a8e1175bSopenharmony_ci * the SHA-256 hash of (P,G,Ys) 178a8e1175bSopenharmony_ci */ 179a8e1175bSopenharmony_ci mbedtls_printf("\n . Verifying the server's RSA signature"); 180a8e1175bSopenharmony_ci fflush(stdout); 181a8e1175bSopenharmony_ci 182a8e1175bSopenharmony_ci p += 2; 183a8e1175bSopenharmony_ci 184a8e1175bSopenharmony_ci if ((n = (size_t) (end - p)) != mbedtls_rsa_get_len(&rsa)) { 185a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! Invalid RSA signature size\n\n"); 186a8e1175bSopenharmony_ci goto exit; 187a8e1175bSopenharmony_ci } 188a8e1175bSopenharmony_ci 189a8e1175bSopenharmony_ci mdlen = (unsigned int) mbedtls_md_get_size(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256)); 190a8e1175bSopenharmony_ci if (mdlen == 0) { 191a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! Invalid digest type\n\n"); 192a8e1175bSopenharmony_ci goto exit; 193a8e1175bSopenharmony_ci } 194a8e1175bSopenharmony_ci 195a8e1175bSopenharmony_ci if ((ret = mbedtls_sha256(buf, (int) (p - 2 - buf), hash, 0)) != 0) { 196a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_sha256 returned %d\n\n", ret); 197a8e1175bSopenharmony_ci goto exit; 198a8e1175bSopenharmony_ci } 199a8e1175bSopenharmony_ci 200a8e1175bSopenharmony_ci if ((ret = mbedtls_rsa_pkcs1_verify(&rsa, MBEDTLS_MD_SHA256, 201a8e1175bSopenharmony_ci mdlen, hash, p)) != 0) { 202a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_rsa_pkcs1_verify returned %d\n\n", ret); 203a8e1175bSopenharmony_ci goto exit; 204a8e1175bSopenharmony_ci } 205a8e1175bSopenharmony_ci 206a8e1175bSopenharmony_ci /* 207a8e1175bSopenharmony_ci * 6. Send our public value: Yc = G ^ Xc mod P 208a8e1175bSopenharmony_ci */ 209a8e1175bSopenharmony_ci mbedtls_printf("\n . Sending own public value to server"); 210a8e1175bSopenharmony_ci fflush(stdout); 211a8e1175bSopenharmony_ci 212a8e1175bSopenharmony_ci n = mbedtls_dhm_get_len(&dhm); 213a8e1175bSopenharmony_ci if ((ret = mbedtls_dhm_make_public(&dhm, (int) n, buf, n, 214a8e1175bSopenharmony_ci mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { 215a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_dhm_make_public returned %d\n\n", ret); 216a8e1175bSopenharmony_ci goto exit; 217a8e1175bSopenharmony_ci } 218a8e1175bSopenharmony_ci 219a8e1175bSopenharmony_ci if ((ret = mbedtls_net_send(&server_fd, buf, n)) != (int) n) { 220a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_net_send returned %d\n\n", ret); 221a8e1175bSopenharmony_ci goto exit; 222a8e1175bSopenharmony_ci } 223a8e1175bSopenharmony_ci 224a8e1175bSopenharmony_ci /* 225a8e1175bSopenharmony_ci * 7. Derive the shared secret: K = Ys ^ Xc mod P 226a8e1175bSopenharmony_ci */ 227a8e1175bSopenharmony_ci mbedtls_printf("\n . Shared secret: "); 228a8e1175bSopenharmony_ci fflush(stdout); 229a8e1175bSopenharmony_ci 230a8e1175bSopenharmony_ci if ((ret = mbedtls_dhm_calc_secret(&dhm, buf, sizeof(buf), &n, 231a8e1175bSopenharmony_ci mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { 232a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_dhm_calc_secret returned %d\n\n", ret); 233a8e1175bSopenharmony_ci goto exit; 234a8e1175bSopenharmony_ci } 235a8e1175bSopenharmony_ci 236a8e1175bSopenharmony_ci for (n = 0; n < 16; n++) { 237a8e1175bSopenharmony_ci mbedtls_printf("%02x", buf[n]); 238a8e1175bSopenharmony_ci } 239a8e1175bSopenharmony_ci 240a8e1175bSopenharmony_ci /* 241a8e1175bSopenharmony_ci * 8. Setup the AES-256 decryption key 242a8e1175bSopenharmony_ci * 243a8e1175bSopenharmony_ci * This is an overly simplified example; best practice is 244a8e1175bSopenharmony_ci * to hash the shared secret with a random value to derive 245a8e1175bSopenharmony_ci * the keying material for the encryption/decryption keys, 246a8e1175bSopenharmony_ci * IVs and MACs. 247a8e1175bSopenharmony_ci */ 248a8e1175bSopenharmony_ci mbedtls_printf("...\n . Receiving and decrypting the ciphertext"); 249a8e1175bSopenharmony_ci fflush(stdout); 250a8e1175bSopenharmony_ci 251a8e1175bSopenharmony_ci ret = mbedtls_aes_setkey_dec(&aes, buf, 256); 252a8e1175bSopenharmony_ci if (ret != 0) { 253a8e1175bSopenharmony_ci goto exit; 254a8e1175bSopenharmony_ci } 255a8e1175bSopenharmony_ci 256a8e1175bSopenharmony_ci memset(buf, 0, sizeof(buf)); 257a8e1175bSopenharmony_ci 258a8e1175bSopenharmony_ci if ((ret = mbedtls_net_recv(&server_fd, buf, 16)) != 16) { 259a8e1175bSopenharmony_ci mbedtls_printf(" failed\n ! mbedtls_net_recv returned %d\n\n", ret); 260a8e1175bSopenharmony_ci goto exit; 261a8e1175bSopenharmony_ci } 262a8e1175bSopenharmony_ci 263a8e1175bSopenharmony_ci ret = mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_DECRYPT, buf, buf); 264a8e1175bSopenharmony_ci if (ret != 0) { 265a8e1175bSopenharmony_ci goto exit; 266a8e1175bSopenharmony_ci } 267a8e1175bSopenharmony_ci buf[16] = '\0'; 268a8e1175bSopenharmony_ci mbedtls_printf("\n . Plaintext is \"%s\"\n\n", (char *) buf); 269a8e1175bSopenharmony_ci 270a8e1175bSopenharmony_ci exit_code = MBEDTLS_EXIT_SUCCESS; 271a8e1175bSopenharmony_ci 272a8e1175bSopenharmony_ciexit: 273a8e1175bSopenharmony_ci 274a8e1175bSopenharmony_ci mbedtls_net_free(&server_fd); 275a8e1175bSopenharmony_ci 276a8e1175bSopenharmony_ci mbedtls_aes_free(&aes); 277a8e1175bSopenharmony_ci mbedtls_rsa_free(&rsa); 278a8e1175bSopenharmony_ci mbedtls_dhm_free(&dhm); 279a8e1175bSopenharmony_ci mbedtls_ctr_drbg_free(&ctr_drbg); 280a8e1175bSopenharmony_ci mbedtls_entropy_free(&entropy); 281a8e1175bSopenharmony_ci mbedtls_mpi_free(&N); 282a8e1175bSopenharmony_ci mbedtls_mpi_free(&E); 283a8e1175bSopenharmony_ci 284a8e1175bSopenharmony_ci mbedtls_exit(exit_code); 285a8e1175bSopenharmony_ci} 286a8e1175bSopenharmony_ci#endif /* MBEDTLS_AES_C && MBEDTLS_DHM_C && MBEDTLS_ENTROPY_C && 287a8e1175bSopenharmony_ci MBEDTLS_NET_C && MBEDTLS_RSA_C && MBEDTLS_MD_CAN_SHA256 && 288a8e1175bSopenharmony_ci MBEDTLS_FS_IO && MBEDTLS_CTR_DRBG_C */ 289