You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
5.8 KiB
161 lines
5.8 KiB
/* test_client_server.c - TinyCrypt test for client-server key exchange and encryption */ |
|
|
|
/* |
|
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions are met: |
|
* |
|
* - Redistributions of source code must retain the above copyright notice, |
|
* this list of conditions and the following disclaimer. |
|
* |
|
* - Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* |
|
* - Neither the name of Intel Corporation nor the names of its contributors |
|
* may be used to endorse or promote products derived from this software |
|
* without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
* POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
|
|
|
#include <tinycrypt/ecc.h> |
|
#include <tinycrypt/ecc_dh.h> |
|
#include <tinycrypt/aes.h> |
|
#include <tinycrypt/ctr_mode.h> |
|
#include <tinycrypt/constants.h> |
|
#include <tinycrypt/ecc_platform_specific.h> |
|
#include <test_utils.h> |
|
|
|
#include <stdint.h> |
|
#include <stdio.h> |
|
#include <string.h> |
|
#include <stdlib.h> |
|
|
|
static int test_key_exchange_and_encrypt(void) |
|
{ |
|
const struct uECC_Curve_t *curve = uECC_secp256r1(); |
|
|
|
/* Client key pair */ |
|
uint8_t client_private[NUM_ECC_BYTES]; |
|
uint8_t client_public[2 * NUM_ECC_BYTES]; |
|
|
|
/* Server key pair */ |
|
uint8_t server_private[NUM_ECC_BYTES]; |
|
uint8_t server_public[2 * NUM_ECC_BYTES]; |
|
|
|
/* Shared secrets */ |
|
uint8_t client_secret[NUM_ECC_BYTES]; |
|
uint8_t server_secret[NUM_ECC_BYTES]; |
|
|
|
TC_PRINT("Generating client key pair...\n"); |
|
if (!uECC_make_key(client_public, client_private, curve)) { |
|
TC_ERROR("Failed to generate client key pair\n"); |
|
return TC_FAIL; |
|
} |
|
|
|
TC_PRINT("Generating server key pair...\n"); |
|
if (!uECC_make_key(server_public, server_private, curve)) { |
|
TC_ERROR("Failed to generate server key pair\n"); |
|
return TC_FAIL; |
|
} |
|
|
|
/* Compute shared secret on client side */ |
|
TC_PRINT("Computing shared secret on client side...\n"); |
|
if (!uECC_shared_secret(server_public, client_private, client_secret, curve)) { |
|
TC_ERROR("Failed to compute client shared secret\n"); |
|
return TC_FAIL; |
|
} |
|
|
|
/* Compute shared secret on server side */ |
|
TC_PRINT("Computing shared secret on server side...\n"); |
|
if (!uECC_shared_secret(client_public, server_private, server_secret, curve)) { |
|
TC_ERROR("Failed to compute server shared secret\n"); |
|
return TC_FAIL; |
|
} |
|
|
|
/* Verify that both shared secrets match */ |
|
if (memcmp(client_secret, server_secret, NUM_ECC_BYTES) != 0) { |
|
TC_ERROR("Shared secrets do not match\n"); |
|
show_str("Client secret", client_secret, NUM_ECC_BYTES); |
|
show_str("Server secret", server_secret, NUM_ECC_BYTES); |
|
return TC_FAIL; |
|
} |
|
TC_PRINT("Shared secrets match.\n"); |
|
|
|
/* Derive AES key from shared secret (first 16 bytes) */ |
|
uint8_t aes_key[TC_AES_KEY_SIZE]; |
|
memcpy(aes_key, client_secret, TC_AES_KEY_SIZE); |
|
|
|
/* Prepare test data */ |
|
const char *plaintext = "Hello, secure world!"; |
|
size_t plaintext_len = strlen(plaintext) + 1; /* include null terminator */ |
|
uint8_t ciphertext[plaintext_len]; |
|
uint8_t decrypted[plaintext_len]; |
|
|
|
/* Initialize AES key schedule */ |
|
struct tc_aes_key_sched_struct sched; |
|
if (tc_aes128_set_encrypt_key(&sched, aes_key) != TC_CRYPTO_SUCCESS) { |
|
TC_ERROR("Failed to set AES encryption key\n"); |
|
return TC_FAIL; |
|
} |
|
|
|
/* Initialize counter (little-endian 32-bit) */ |
|
uint8_t ctr[TC_AES_BLOCK_SIZE] = {0}; /* zero-initialized counter */ |
|
|
|
TC_PRINT("Encrypting plaintext...\n"); |
|
if (tc_ctr_mode(ciphertext, plaintext_len, (const uint8_t *)plaintext, |
|
plaintext_len, ctr, &sched) != TC_CRYPTO_SUCCESS) { |
|
TC_ERROR("Encryption failed\n"); |
|
return TC_FAIL; |
|
} |
|
|
|
/* Reset counter for decryption (CTR mode uses same counter sequence) */ |
|
memset(ctr, 0, TC_AES_BLOCK_SIZE); |
|
|
|
TC_PRINT("Decrypting ciphertext...\n"); |
|
if (tc_ctr_mode(decrypted, plaintext_len, ciphertext, |
|
plaintext_len, ctr, &sched) != TC_CRYPTO_SUCCESS) { |
|
TC_ERROR("Decryption failed\n"); |
|
return TC_FAIL; |
|
} |
|
|
|
/* Verify decrypted matches original */ |
|
if (memcmp(plaintext, decrypted, plaintext_len) != 0) { |
|
TC_ERROR("Decrypted text does not match original\n"); |
|
show_str("Original", (const uint8_t *)plaintext, plaintext_len); |
|
show_str("Decrypted", decrypted, plaintext_len); |
|
return TC_FAIL; |
|
} |
|
TC_PRINT("Decryption successful. Test passed.\n"); |
|
|
|
return TC_PASS; |
|
} |
|
|
|
int main(void) |
|
{ |
|
unsigned int result = TC_PASS; |
|
|
|
TC_START("Performing client-server key exchange and encryption test:"); |
|
|
|
/* Setup cryptographically secure PRNG */ |
|
uECC_set_rng(&default_CSPRNG); |
|
|
|
result = test_key_exchange_and_encrypt(); |
|
|
|
TC_END_RESULT(result); |
|
TC_END_REPORT(result); |
|
|
|
return result; |
|
} |