From 0e0b6b15465c224235e78f91056d5dc0accf23e3 Mon Sep 17 00:00:00 2001 From: John Jones Date: Mon, 6 Mar 2017 19:03:04 -0500 Subject: [PATCH] Many bug fixes for secio --- crypto/Makefile | 2 +- crypto/aes.c | 84 +++++++- crypto/ephemeral.c | 7 +- crypto/sha1.c | 2 +- crypto/sha256.c | 2 +- crypto/sha512.c | 2 +- include/libp2p/crypto/aes.h | 23 ++- include/libp2p/crypto/ephemeral.h | 4 +- include/libp2p/crypto/sha1.h | 2 +- include/libp2p/crypto/sha256.h | 2 +- include/libp2p/crypto/sha512.h | 2 +- include/libp2p/secio/secio.h | 23 ++- secio/exchange.c | 13 +- secio/secio.c | 332 ++++++++++++++++++++++-------- test/crypto/test_aes.h | 47 +++++ test/crypto/test_ephemeral.h | 75 ++++++- test/crypto/test_rsa.h | 19 +- test/test_secio.h | 81 +++++++- test/testit.c | 13 +- 19 files changed, 602 insertions(+), 133 deletions(-) create mode 100644 test/crypto/test_aes.h diff --git a/crypto/Makefile b/crypto/Makefile index 2fb00a8..18867a3 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -2,7 +2,7 @@ CC = gcc CFLAGS = -O0 -I../include -I../../c-protobuf -I../../c-multihash/include -g3 LFLAGS = DEPS = -OBJS = rsa.o sha256.o sha512.o sha1.o key.o peerutils.o ephemeral.o +OBJS = rsa.o sha256.o sha512.o sha1.o key.o peerutils.o ephemeral.o aes.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/crypto/aes.c b/crypto/aes.c index e719ed3..52f3af6 100644 --- a/crypto/aes.c +++ b/crypto/aes.c @@ -1,20 +1,92 @@ +#include +#include + +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" #include "mbedtls/aes.h" +/** + * functions for aes encryption + */ + +/** + * Generate a new AES key + * @param key where to store the 32 byte key + * @returns true(1) on success + */ +int libp2p_crypto_aes_key_generate(char* key) { + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + + mbedtls_entropy_init(&entropy); + + char* pers = "aes generate key"; + + mbedtls_ctr_drbg_init(&ctr_drbg); + + if (mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, + (const unsigned char *) pers, + strlen( pers )) != 0) + return 0; + + if (mbedtls_ctr_drbg_random(&ctr_drbg, key, 32) != 0) + return 0; + + return 1; +} + /** * Encrypt a block of text - * @param key the aes key - * @param iv the random part of encryption + * @param key the aes key (32 bytes) + * @param iv the random part of encryption (16 bytes) * @param input the text to encrypt * @param input_size the length of the array * @param output where the output will be placed * @param output_size the length of the memory allocated for output * @returns true(1) on success, otherwise false(0) */ -int libp2p_crypto_aes_encrypt(char* key, char* iv, char* input, size_t input_size, unsigned char* output, size_t* output_size) { +int libp2p_crypto_aes_encrypt(char* key, char* iv, char* input, size_t input_size, unsigned char** output, size_t* output_size) { + int new_size = 0; mbedtls_aes_context ctx; mbedtls_aes_init(&ctx); mbedtls_aes_setkey_enc(&ctx, key, 256); - mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 24, iv, input, output); - //TODO Implement this method - return 0; + // turn input into a multiple of 16 + new_size = input_size; + if (new_size % 16 != 0) { + new_size += new_size % 16; + } + char* padded_input = malloc(new_size); + memcpy(padded_input, input, input_size); + if (new_size != input_size) + memset(&padded_input[input_size], 0, new_size - input_size); + // make room for the output + *output = malloc(new_size); + *output_size = new_size; + int retVal = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, new_size, iv, padded_input, *output); + free(padded_input); + if (retVal != 0) + free(output); + return retVal == 0; +} + +/** + * Decrypt a block of text + * @param key the aes key (32 bytes) + * @param iv the random part of encryption (16 bytes) + * @param input the text to encrypt + * @param input_size the length of the array + * @param output where the output will be placed + * @param output_size the length of the memory allocated for output + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_crypto_aes_decrypt(char* key, char* iv, char* input, size_t input_size, unsigned char** output, size_t* output_size) { + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + mbedtls_aes_setkey_dec(&ctx, key, 256); + // make room for the output + *output = malloc(input_size); + *output_size = input_size; + if (mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, input_size, iv, input, *output) != 0) + return 0; + return 1; } diff --git a/crypto/ephemeral.c b/crypto/ephemeral.c index f7110c0..702d49e 100644 --- a/crypto/ephemeral.c +++ b/crypto/ephemeral.c @@ -105,13 +105,16 @@ int libp2p_crypto_ephemeral_point_marshal(int bit_size, uint64_t x, uint64_t y, int byteLen = (bit_size + 7) >> 3; *results = (unsigned char*)malloc(2*byteLen+1); + memset(*results, 0, 2*byteLen+1); *results[0] = 4; // uncompressed point int uint64_len = 8; unsigned char buffer[8]; serialize_uint64(x, &buffer[0]); - memcpy(&(*results)[1 + byteLen - uint64_len], &buffer[0], 8); + int pos = 1 + byteLen - uint64_len; + memcpy(&(*results)[pos], &buffer[0], 8); serialize_uint64(y, &buffer[0]); - memcpy(&(*results)[1 + 2*byteLen - uint64_len], &buffer[0], 8); + pos = 1 + 2*byteLen - uint64_len; + memcpy(&(*results)[pos], &buffer[0], 8); *bytes_written = 2 * byteLen + 1; return 1; } diff --git a/crypto/sha1.c b/crypto/sha1.c index 332f854..50784c8 100644 --- a/crypto/sha1.c +++ b/crypto/sha1.c @@ -272,7 +272,7 @@ void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]) * @param output where the output is placed NOTE: mut be preallocated * @returns the number of bytes written, or 0 on error */ -int libp2p_crypto_hashing_sha1(const char* input, size_t input_length, unsigned char* output) { +int libp2p_crypto_hashing_sha1(const unsigned char* input, size_t input_length, unsigned char* output) { SHA1_CTX ctx; SHA1_Init(&ctx); SHA1_Update(&ctx, input, input_length); diff --git a/crypto/sha256.c b/crypto/sha256.c index 92d745e..4c6ac87 100644 --- a/crypto/sha256.c +++ b/crypto/sha256.c @@ -7,7 +7,7 @@ * @param output where to place the results, should be 32 bytes * @returns 1 */ -int libp2p_crypto_hashing_sha256(const char* input, size_t input_length, unsigned char* output) { +int libp2p_crypto_hashing_sha256(const unsigned char* input, size_t input_length, unsigned char* output) { mbedtls_sha256(input, input_length, output, 0); return 32; } diff --git a/crypto/sha512.c b/crypto/sha512.c index 4301af5..bb73a28 100644 --- a/crypto/sha512.c +++ b/crypto/sha512.c @@ -7,7 +7,7 @@ * @param output where to place the results * @returns 1 */ -int libp2p_crypto_hashing_sha512(const char* input, size_t input_length, unsigned char* output) { +int libp2p_crypto_hashing_sha512(const unsigned char* input, size_t input_length, unsigned char* output) { mbedtls_sha512(input, input_length, output, 0); return 64; } diff --git a/include/libp2p/crypto/aes.h b/include/libp2p/crypto/aes.h index 660c891..8cadff9 100644 --- a/include/libp2p/crypto/aes.h +++ b/include/libp2p/crypto/aes.h @@ -1,11 +1,32 @@ #pragma once +/** + * Generate a new AES key + * @param key where to store the 32 byte key + * @returns true(1) on success + */ +int libp2p_crypto_aes_key_generate(char* key); + /** * Encrypt a block of text + * @param key the aes key (32 bytes) + * @param iv the random part of encryption (16 bytes) * @param input the text to encrypt * @param input_size the length of the array * @param output where the output will be placed * @param output_size the length of the memory allocated for output * @returns true(1) on success, otherwise false(0) */ -int libp2p_crypto_aes_encrypt(char* input, size_t input_size, unsigned char* output, size_t& output_size); +int libp2p_crypto_aes_encrypt(char* key, char* iv, char* input, size_t input_size, unsigned char** output, size_t* output_size); + +/** + * Decrypt a block of text + * @param key the aes key (32 bytes) + * @param iv the random part of encryption (16 bytes) + * @param input the text to encrypt + * @param input_size the length of the array + * @param output where the output will be placed + * @param output_size the length of the memory allocated for output + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_crypto_aes_decrypt(char* key, char* iv, char* input, size_t input_size, unsigned char** output, size_t* output_size); diff --git a/include/libp2p/crypto/ephemeral.h b/include/libp2p/crypto/ephemeral.h index 3c02f3e..ea95551 100644 --- a/include/libp2p/crypto/ephemeral.h +++ b/include/libp2p/crypto/ephemeral.h @@ -7,9 +7,9 @@ */ struct StretchedKey { - char* iv; + unsigned char* iv; size_t iv_size; - char* cipher_key; + unsigned char* cipher_key; size_t cipher_size; unsigned char* mac_key; size_t mac_size; diff --git a/include/libp2p/crypto/sha1.h b/include/libp2p/crypto/sha1.h index 5565d4a..17be904 100644 --- a/include/libp2p/crypto/sha1.h +++ b/include/libp2p/crypto/sha1.h @@ -23,6 +23,6 @@ void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]); * @param output where the output is placed, should be 40 bytes in width * @returns the number of bytes written, or 0 on error */ -int libp2p_crypto_hashing_sha1(const char* input, size_t input_length, unsigned char* output); +int libp2p_crypto_hashing_sha1(const unsigned char* input, size_t input_length, unsigned char* output); #endif /* _SHA1_H */ diff --git a/include/libp2p/crypto/sha256.h b/include/libp2p/crypto/sha256.h index 8a8b5fb..4b45e19 100644 --- a/include/libp2p/crypto/sha256.h +++ b/include/libp2p/crypto/sha256.h @@ -8,6 +8,6 @@ * @param output where to place the results * @returns 1 */ -int libp2p_crypto_hashing_sha256(const char* input, size_t input_length, unsigned char* output); +int libp2p_crypto_hashing_sha256(const unsigned char* input, size_t input_length, unsigned char* output); #endif diff --git a/include/libp2p/crypto/sha512.h b/include/libp2p/crypto/sha512.h index f9a8628..0c74136 100644 --- a/include/libp2p/crypto/sha512.h +++ b/include/libp2p/crypto/sha512.h @@ -7,5 +7,5 @@ * @param output where to place the results, should be 64 bytes * @returns number of bytes written, or 0 */ -int libp2p_crypto_hashing_sha512(const char* input, size_t input_length, unsigned char* output); +int libp2p_crypto_hashing_sha512(const unsigned char* input, size_t input_length, unsigned char* output); diff --git a/include/libp2p/secio/secio.h b/include/libp2p/secio/secio.h index 4502a53..5d371ca 100644 --- a/include/libp2p/secio/secio.h +++ b/include/libp2p/secio/secio.h @@ -16,26 +16,35 @@ struct SecureSession { enum IPTrafficType traffic_type; // once the connection is established struct Stream* stream; - struct PublicKey remote_key; - char* remote_peer_id; // filled in during negotiations char* chosen_curve; char* chosen_cipher; char* chosen_hash; - unsigned char* ephemeral_public_key; // bytes of x and y - size_t ephemeral_public_key_size; unsigned char* shared_key; // a shared key based off of the ephemeral private key size_t shared_key_size; - char nonce[16]; - struct StretchedKey* stretched_key; unsigned char* mac; size_t mac_size; + int (*mac_function)(const unsigned char*, size_t, unsigned char*); + // local only stuff + char local_nonce[16]; + unsigned char* ephemeral_public_key; // bytes of x and y + size_t ephemeral_public_key_size; + struct StretchedKey* local_stretched_key; + // remote stuff + char remote_nonce[16]; + struct PublicKey remote_key; + char* remote_peer_id; + unsigned char* remote_ephemeral_public_key; + size_t remote_ephemeral_public_key_size; + struct StretchedKey* remote_stretched_key; }; /*** * performs initial communication over an insecure channel to share * keys, IDs, and initiate connection. This is a framed messaging system * @param session the secure session to be filled + * @param private_key the local private key to use + * @param remote_requested the other side is who asked for the upgrade * @returns true(1) on success, false(0) otherwise */ -int libp2p_secio_handshake(struct SecureSession* session, struct RsaPrivateKey* private_key); +int libp2p_secio_handshake(struct SecureSession* session, struct RsaPrivateKey* private_key, int remote_requested); diff --git a/secio/exchange.c b/secio/exchange.c index 1d98b2e..d49b542 100644 --- a/secio/exchange.c +++ b/secio/exchange.c @@ -9,11 +9,14 @@ enum WireType secio_exchange_message_fields[] = { WIRETYPE_LENGTH_DELIMITED, WIR struct Exchange* libp2p_secio_exchange_new() { - struct Exchange* retVal = (struct Exchange*)malloc(sizeof(struct Exchange)); - if (retVal == NULL) - return NULL; - memset((void*)retVal, 0, sizeof(struct Exchange)); - return retVal; + struct Exchange* out = (struct Exchange*)malloc(sizeof(struct Exchange)); + if (out != NULL) { + out->epubkey = NULL; + out->epubkey_size = 0; + out->signature = NULL; + out->signature_size = 0; + } + return out; } void libp2p_secio_exchange_free( struct Exchange* in) { diff --git a/secio/secio.c b/secio/secio.c index c69da8c..19ed101 100644 --- a/secio/secio.c +++ b/secio/secio.c @@ -63,7 +63,7 @@ int libp2p_secio_generate_nonce(char* results, int length) { */ int libp2p_secio_hash(struct Propose* in, unsigned char result[32]) { // append public key and nonce - char buffer[in->public_key_size + in->rand_size]; + unsigned char buffer[in->public_key_size + in->rand_size]; memcpy(buffer, in->public_key, in->public_key_size); memcpy(&buffer[in->public_key_size], in->rand, in->rand_size); return libp2p_crypto_hashing_sha256(buffer, in->public_key_size + in->rand_size, result); @@ -197,6 +197,15 @@ int libp2p_secio_verify_signature(struct PublicKey* public_key, const unsigned c return 0; } +/** + * Sign data + * @param private_key the key to use + * @param in the bytes to sign + * @param in_length the number of bytes + * @param signature the result + * @param signature_size the size of the result + * @returns true(1) on success, otherwise false(0) + */ int libp2p_secio_sign(struct PrivateKey* private_key, const char* in, size_t in_length, unsigned char** signature, size_t* signature_size) { if (private_key->type == KEYTYPE_RSA) { struct RsaPrivateKey rsa_key = {0}; @@ -224,11 +233,11 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s struct StretchedKey* k2; unsigned char* result = NULL;; size_t result_size = 0; - int (*hash_func)(const char* input, size_t input_length, unsigned char* results); // pointer to hash function - char* first_seed = "key_expansion"; - char* second_seed = NULL; - char* temp = NULL; - int seed_size = strlen(first_seed); + int (*hash_func)(const unsigned char* input, size_t input_length, unsigned char* results); // pointer to hash function + unsigned char* first_seed = (unsigned char*)"key_expansion"; + unsigned char* second_seed = NULL; + unsigned char* temp = NULL; + int seed_size = strlen((char*)first_seed); unsigned char* current_hash = NULL; k1 = libp2p_crypto_ephemeral_stretched_key_new(); @@ -279,7 +288,7 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s seed_size += secret_size; second_seed = malloc(seed_size); memcpy(second_seed, secret, secret_size); - memcpy(&second_seed[secret_size], first_seed, strlen(first_seed)); + memcpy(&second_seed[secret_size], first_seed, strlen((char*)first_seed)); current_hash = malloc(hash_size); hash_func(second_seed, seed_size, current_hash); @@ -295,11 +304,11 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s free(temp); temp = NULL; } - seed_size = secret_size + strlen(first_seed) + hash_size; + seed_size = secret_size + strlen((char*)first_seed) + hash_size; temp = malloc(seed_size); memcpy(temp, secret, secret_size); memcpy(&temp[secret_size], current_hash, hash_size); - memcpy(&temp[secret_size + hash_size], first_seed, strlen(first_seed)); + memcpy(&temp[secret_size + hash_size], first_seed, strlen((char*)first_seed)); // make a new hash hash_func(temp, seed_size, current_hash); // copy the hash to results @@ -318,7 +327,8 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s // now we have a big result. Cut it up into pieces if (temp != NULL) free(temp); - temp = (char*)result; + temp = result; + k1->mac_size = hash_size; k1->iv = malloc(k1->iv_size); memcpy(k1->iv, temp, k1->iv_size); temp += k1->iv_size; @@ -329,6 +339,7 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s memcpy(k1->mac_key, temp, k1->mac_size); temp += k1->mac_size; + k2->mac_size = hash_size; k2->iv = malloc(k2->iv_size); memcpy(k2->iv, temp, k2->iv_size); temp += k2->iv_size; @@ -366,39 +377,42 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s return retVal; } -int libp2p_secio_make_mac_and_cipher(struct SecureSession* session) { +int libp2p_secio_make_mac_and_cipher(struct SecureSession* session, struct StretchedKey* stretched_key) { // mac - int (*mac_func)(const char*, size_t, unsigned char*); if (strcmp(session->chosen_hash, "SHA1") == 0) { - session->stretched_key->mac_size = 40; - mac_func = libp2p_crypto_hashing_sha1; + stretched_key->mac_size = 40; } else if (strcmp(session->chosen_hash, "SHA512") == 0) { - session->stretched_key->mac_size = 32; - mac_func = libp2p_crypto_hashing_sha512; + stretched_key->mac_size = 32; } else if (strcmp(session->chosen_hash, "SHA256") == 0) { - session->stretched_key->mac_size = 16; - mac_func = libp2p_crypto_hashing_sha256; + stretched_key->mac_size = 16; } else { return 0; } - session->stretched_key->mac_key = malloc(session->stretched_key->mac_size); - mac_func(session->stretched_key->cipher_key, session->stretched_key->cipher_size, session->stretched_key->mac_key); + stretched_key->mac_key = malloc(stretched_key->mac_size); + session->mac_function(stretched_key->cipher_key, stretched_key->cipher_size, stretched_key->mac_key); // block cipher - if (strcmp(session->chosen_cipher, "AES-128") == 0) { - - } else if (strcmp(session->chosen_cipher, "AES-256") == 0) { - + if (strcmp(session->chosen_cipher, "AES-128") || strcmp(session->chosen_cipher, "AES-256") == 0) { + //we already have the key } else if (strcmp(session->chosen_cipher, "Blowfish") == 0) { - + //TODO: Implement blowfish + return 0; } else { return 0; } + //TODO: set up the encrypted streams return 1; } -int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size_t data_length) { +/*** + * Write bytes to an unencrypted stream + * @param session the session information + * @param bytes the bytes to write + * @param data_length the number of bytes to write + * @returns the number of bytes written + */ +int libp2p_secio_unencrypted_write(struct SecureSession* session, unsigned char* bytes, size_t data_length) { int num_bytes = 0; if (data_length > 0) { // only do this is if there is something to send @@ -421,7 +435,6 @@ int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size left = left - written_this_time; } while (left > 0); // then send the actual data - fprintf(stderr, "About to send %lu bytes (aka %u)\n", data_length, size); left = data_length; written = 0; do { @@ -443,7 +456,14 @@ int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size return num_bytes; } -int libp2p_secio_read(struct SecureSession* session, unsigned char** results, size_t* results_size) { +/*** + * Read bytes from the incoming stream + * @param session the session information + * @param results where to put the bytes read + * @param results_size the size of the results + * @returns the number of bytes read + */ +int libp2p_secio_unencrypted_read(struct SecureSession* session, unsigned char** results, size_t* results_size) { uint32_t buffer_size; // first read the 4 byte integer @@ -458,7 +478,7 @@ int libp2p_secio_read(struct SecureSession* session, unsigned char** results, si if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) { // TODO: use epoll or select to wait for socket to be writable } else { - fprintf(stderr, "Error in libp2p_secio_read: %s\n", strerror(errno)); + fprintf(stderr, "Error in libp2p_secio_unencrypted_read: %s\n", strerror(errno)); return 0; } } @@ -497,15 +517,122 @@ int libp2p_secio_read(struct SecureSession* session, unsigned char** results, si return buffer_size; } +/** + * XOR the bytes into a buffer + * @param key the key + * @param key_size the key size + * @param incoming the incoming data + * @param incoming_size the size of the incoming buffer + * @param outgoing where to put the results. Must be the same size or larger than incoming_size + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_secio_xor(const unsigned char* key, size_t key_size, const unsigned char* incoming, size_t incoming_size, unsigned char* outgoing) { + for(int i = 0; i < incoming_size; i++) { + int key_pos = i; + if (key_pos > key_size) + key_pos = key_pos % key_size; + outgoing[i] = incoming[i] ^ key[key_pos]; + } + return 1; +} + +/** + * Encrypt data before being sent out an insecure stream + * @param session the session information + * @param incoming the incoming data + * @param incoming_size the size of the incoming data + * @param outgoing where to put the results + * @param outgoing_size the amount of memory allocated + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_secio_encrypt(const struct SecureSession* session, const unsigned char* incoming, size_t incoming_size, unsigned char** outgoing, size_t* outgoing_size) { + // 4 for the size + // num_bytes for the bytes + // mac_size for the mac + size_t buffer_size = 4 + incoming_size + session->local_stretched_key->mac_size; + *outgoing = malloc(buffer_size); + unsigned char* buffer = *outgoing; + // XOR the bytes into a new area + libp2p_secio_xor(session->local_stretched_key->cipher_key, session->local_stretched_key->cipher_size, incoming, incoming_size, &buffer[4]); + // mac the data, and append it + if (session->mac_function != NULL) + session->mac_function(&buffer[4], incoming_size, &buffer[4 + incoming_size]); + // add size of just the data + mac section to beginning + uint32_t size = htonl(buffer_size - 4); + char* size_as_char = (char*)&size; + memcpy(&buffer[0], size_as_char, 4); + *outgoing_size = buffer_size; + return 1; +} + +/** + * Write to an encrypted stream + * @param session the session parameters + * @param bytes the bytes to write + * @param num_bytes the number of bytes to write + * @returns the number of bytes written + */ +int libp2p_secio_encrypted_write(struct SecureSession* session, unsigned char* bytes, size_t num_bytes) { + // writer uses the local cipher and mac + unsigned char* buffer = NULL; + size_t buffer_size = 0; + if (!libp2p_secio_encrypt(session, bytes, num_bytes, &buffer, &buffer_size)) + return 0; + return libp2p_secio_unencrypted_write(session, buffer, buffer_size); +} + +/** + * Unencrypt data that was read from the stream + * @param session the session information + * @param incoming the incoming bytes + * @param incoming_size the number of incoming bytes + * @param outgoing where to put the results + * @param outgoing_size the amount of memory allocated for the results + * @returns number of unencrypted bytes + */ +int libp2p_secio_decrypt(const struct SecureSession* session, const unsigned char* incoming, size_t incoming_size, unsigned char** outgoing, size_t* outgoing_size) { + uint32_t data_section_size; + char* temp = (char*)&data_section_size; + memcpy(temp, incoming, 4); + temp[4] = 0; + data_section_size = ntohl(data_section_size) - session->remote_stretched_key->mac_size; + // TODO: verify MAC + // unencrypt data + *outgoing = malloc(data_section_size); + libp2p_secio_xor(session->remote_stretched_key->cipher_key, session->remote_stretched_key->cipher_size, &incoming[4], data_section_size, *outgoing); + *outgoing_size = data_section_size; + // return data + return data_section_size; + +} + +/** + * Read from an encrypted stream + * @param session the session parameters + * @param bytes where the bytes will be stored + * @param num_bytes the number of bytes read from the stream + * @returns the number of bytes read + */ +int libp2p_secio_encrypted_read(struct SecureSession* session, unsigned char** bytes, size_t* num_bytes) { + // reader uses the remote cipher and mac + // read the data + unsigned char* incoming = NULL; + size_t incoming_size = 0; + if (libp2p_secio_unencrypted_read(session, &incoming, &incoming_size) <= 0) + return 0; + return libp2p_secio_decrypt(session, incoming, incoming_size, bytes, num_bytes); +} + /*** * performs initial communication over an insecure channel to share * keys, IDs, and initiate connection. This is a framed messaging system * NOTE: session must contain a valid socket_descriptor that is a multistream. - * @param session the secure session to be filled + * @param local_session the secure session to be filled * @param private_key our private key to use + * @param remote_requested it is the other side that requested the upgrade to secio * @returns true(1) on success, false(0) otherwise */ -int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivateKey* private_key) { +int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivateKey* private_key, int remote_requested) { int retVal = 0; size_t results_size = 0, bytes_written = 0; unsigned char* propose_in_bytes = NULL; // the remote protobuf @@ -523,11 +650,11 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat struct Exchange* exchange_out = NULL; unsigned char* exchange_out_protobuf = NULL; size_t exchange_out_protobuf_size = 0; - struct Libp2pVector* char_buffer = NULL; + char* char_buffer = NULL; + size_t char_buffer_length = 0; struct StretchedKey* k1 = NULL, *k2 = NULL; - struct PrivateKey priv = {0}; + struct PrivateKey* priv = NULL; struct PublicKey pub_key = {0}; - struct SecureSession remote_session = {0}; char* remote_peer_id = NULL; struct EphemeralPrivateKey* e_private_key = NULL; @@ -545,23 +672,25 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat if (bytes_written <= 0) goto exit; - // we should get back the secio confirmation - bytes_written = libp2p_net_multistream_read(local_session->stream, &results, &results_size); - if (bytes_written < 5 || strstr((char*)results, "secio") == NULL) - goto exit; + if (!remote_requested) { + // we should get back the secio confirmation + bytes_written = libp2p_net_multistream_read(local_session->stream, &results, &results_size); + if (bytes_written < 5 || strstr((char*)results, "secio") == NULL) + goto exit; - free(results); - results = NULL; - results_size = 0; + free(results); + results = NULL; + results_size = 0; + } // generate 16 byte nonce - if (!libp2p_secio_generate_nonce(&local_session->nonce[0], 16)) { + if (!libp2p_secio_generate_nonce(&local_session->local_nonce[0], 16)) { goto exit; } // Build the proposal to be sent to the new connection: propose_out = libp2p_secio_propose_new(); - libp2p_secio_propose_set_property((void**)&propose_out->rand, &propose_out->rand_size, local_session->nonce, 16); + libp2p_secio_propose_set_property((void**)&propose_out->rand, &propose_out->rand_size, local_session->local_nonce, 16); // public key - protobuf it and stick it in propose_out pub_key.type = KEYTYPE_RSA; @@ -600,30 +729,28 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat goto exit; - bytes_written = libp2p_secio_write(local_session, propose_out_bytes, propose_out_size); + bytes_written = libp2p_secio_unencrypted_write(local_session, propose_out_bytes, propose_out_size); if (bytes_written < propose_out_size) goto exit; // now receive the proposal from the new connection - bytes_written = libp2p_secio_read(local_session, &propose_in_bytes, &propose_in_size); + bytes_written = libp2p_secio_unencrypted_read(local_session, &propose_in_bytes, &propose_in_size); if (bytes_written <= 0) goto exit; if (!libp2p_secio_propose_protobuf_decode(propose_in_bytes, propose_in_size, &propose_in)) goto exit; + // get their nonce + if (propose_in->rand_size != 16) + goto exit; + memcpy(local_session->remote_nonce, propose_in->rand, 16); // get public key and put it in a struct PublicKey if (!libp2p_crypto_public_key_protobuf_decode(propose_in->public_key, propose_in->public_key_size, &public_key)) goto exit; // generate their peer id libp2p_crypto_public_key_to_peer_id(public_key, &remote_peer_id); - // receive Exchange packet - bytes_written = libp2p_secio_read(local_session, &results, &results_size); - if (bytes_written == 0) - goto exit; - libp2p_secio_exchange_protobuf_decode(results, results_size, &exchange_in); - // negotiate encryption parameters NOTE: SelectBest must match, otherwise this won't work // first determine order libp2p_secio_hash(propose_in, order_hash_in); @@ -639,41 +766,44 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat if (libp2p_secio_select_best(order, propose_out->hashes, propose_out->hashes_size, propose_in->hashes, propose_in->hashes_size, &local_session->chosen_hash) == 0) goto exit; - // prepare exchange of encryption parameters - remote_session.chosen_cipher = local_session->chosen_cipher; - remote_session.chosen_curve = local_session->chosen_curve; - remote_session.chosen_hash = local_session->chosen_hash; - // generate EphemeralPubKey if (libp2p_crypto_ephemeral_keypair_generate(local_session->chosen_curve, &e_private_key) == 0) goto exit; - local_session->ephemeral_public_key = malloc(e_private_key->public_key->bytes_size); - memcpy(local_session->ephemeral_public_key, e_private_key->public_key->bytes, e_private_key->public_key->bytes_size); local_session->ephemeral_public_key_size = e_private_key->public_key->bytes_size; + local_session->ephemeral_public_key = malloc(local_session->ephemeral_public_key_size); + memcpy(local_session->ephemeral_public_key, e_private_key->public_key->bytes, local_session->ephemeral_public_key_size); libp2p_crypto_ephemeral_key_free(e_private_key); e_private_key = NULL; // build buffer to sign - char_buffer = libp2p_utils_vector_new(); + char_buffer_length = propose_in_size + propose_out_size + local_session->ephemeral_public_key_size; + char_buffer = malloc(char_buffer_length); if (char_buffer == NULL) goto exit; - libp2p_utils_vector_add(char_buffer, propose_in_bytes, propose_in_size); - libp2p_utils_vector_add(char_buffer, propose_out_bytes, propose_out_size); - libp2p_utils_vector_add(char_buffer, local_session->ephemeral_public_key, local_session->ephemeral_public_key_size); + memcpy(&char_buffer[0], propose_in_bytes, propose_in_size); + memcpy(&char_buffer[propose_in_size], propose_out_bytes, propose_out_size); + memcpy(&char_buffer[propose_in_size + propose_out_size], local_session->ephemeral_public_key, local_session->ephemeral_public_key_size); // send Exchange packet exchange_out = libp2p_secio_exchange_new(); + if (exchange_out == NULL) + goto exit; exchange_out->epubkey = (unsigned char*)malloc(local_session->ephemeral_public_key_size); + if (exchange_out->epubkey == NULL) + goto exit; memcpy(exchange_out->epubkey, local_session->ephemeral_public_key, local_session->ephemeral_public_key_size); exchange_out->epubkey_size = local_session->ephemeral_public_key_size; - priv.type = KEYTYPE_RSA; - priv.data = (unsigned char*)private_key->der; - priv.data_size = private_key->der_length; - libp2p_secio_sign(&priv, (char*)char_buffer->buffer, char_buffer->buffer_size, &exchange_out->signature, &exchange_out->signature_size); - libp2p_utils_vector_free(char_buffer); + priv = libp2p_crypto_private_key_new(); + priv->type = KEYTYPE_RSA; + priv->data = (unsigned char*)private_key->der; + priv->data_size = private_key->der_length; + libp2p_secio_sign(priv, char_buffer, char_buffer_length, &exchange_out->signature, &exchange_out->signature_size); + free(char_buffer); char_buffer = NULL; + // yes, this is an improper disposal, but it gets the job done without fuss + free(priv); exchange_out_protobuf_size = libp2p_secio_exchange_protobuf_encode_size(exchange_out); exchange_out_protobuf = (unsigned char*)malloc(exchange_out_protobuf_size); @@ -681,28 +811,37 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat goto exit; libp2p_secio_exchange_protobuf_encode(exchange_out, exchange_out_protobuf, exchange_out_protobuf_size, &bytes_written); exchange_out_protobuf_size = bytes_written; - libp2p_secio_exchange_free(exchange_out); - exchange_out = NULL; - bytes_written = libp2p_secio_write(local_session, exchange_out_protobuf, exchange_out_protobuf_size); + + bytes_written = libp2p_secio_unencrypted_write(local_session, exchange_out_protobuf, exchange_out_protobuf_size); if (exchange_out_protobuf_size != bytes_written) goto exit; free(exchange_out_protobuf); exchange_out_protobuf = NULL; + // end of send Exchange packet + + // receive Exchange packet + bytes_written = libp2p_secio_unencrypted_read(local_session, &results, &results_size); + if (bytes_written == 0) + goto exit; + libp2p_secio_exchange_protobuf_decode(results, results_size, &exchange_in); + free(results); + results = NULL; + // end of receive Exchange packet // parse and verify - remote_session.ephemeral_public_key = exchange_in->epubkey; - remote_session.ephemeral_public_key_size = exchange_in->epubkey_size; + local_session->remote_ephemeral_public_key = exchange_in->epubkey; + local_session->remote_ephemeral_public_key_size = exchange_in->epubkey_size; - char_buffer = libp2p_utils_vector_new(); + char_buffer = malloc(propose_in_size + propose_out_size + local_session->remote_ephemeral_public_key_size); if (char_buffer == NULL) goto exit; - libp2p_utils_vector_add(char_buffer, propose_in_bytes, propose_in_size); - libp2p_utils_vector_add(char_buffer, propose_out_bytes, propose_out_size); - libp2p_utils_vector_add(char_buffer, remote_session.ephemeral_public_key, remote_session.ephemeral_public_key_size); + memcpy(&char_buffer[0], propose_in_bytes, propose_in_size); + memcpy(&char_buffer[propose_in_size], propose_out_bytes, propose_out_size); + memcpy(&char_buffer[propose_in_size + propose_out_size], local_session->remote_ephemeral_public_key, local_session->remote_ephemeral_public_key_size); // TODO: signature verification //if (!libp2p_secio_verify_signature(public_key, char_buffer->buffer, char_buffer->buffer_size, exchange_in->signature)) // goto exit; - libp2p_utils_vector_free(char_buffer); + free(char_buffer); char_buffer = NULL; // 2.2 generate shared key NOTE: this was done above @@ -711,26 +850,41 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat libp2p_secio_stretch_keys(local_session->chosen_cipher, local_session->chosen_hash, local_session->shared_key, local_session->shared_key_size, &k1, &k2); if (order > 1) { - local_session->stretched_key = k1; - remote_session.stretched_key = k2; + local_session->local_stretched_key = k1; + local_session->remote_stretched_key = k2; } else { - local_session->stretched_key = k2; - remote_session.stretched_key = k1; + local_session->local_stretched_key = k2; + local_session->remote_stretched_key = k1; } // prepare MAC + cipher + if (strcmp(local_session->chosen_hash, "SHA1") == 0) { + local_session->mac_function = libp2p_crypto_hashing_sha1; + } else if (strcmp(local_session->chosen_hash, "SHA512") == 0) { + local_session->mac_function = libp2p_crypto_hashing_sha512; + } else if (strcmp(local_session->chosen_hash, "SHA256") == 0) { + local_session->mac_function = libp2p_crypto_hashing_sha256; + } else { + return 0; + } - libp2p_secio_make_mac_and_cipher(local_session); - libp2p_secio_make_mac_and_cipher(&remote_session); + libp2p_secio_make_mac_and_cipher(local_session, local_session->local_stretched_key); + // ?? Do we need this half? + libp2p_secio_make_mac_and_cipher(local_session, local_session->remote_stretched_key); - // send expected message (local nonce) to verify encryption works - libp2p_secio_write(local_session, (unsigned char*)local_session->nonce, 16); - libp2p_secio_read(local_session, &results, &results_size); + /* temporarily comment this out to chase memory bug... + // send expected message (their nonce) to verify encryption works + if (libp2p_secio_encrypted_write(local_session, (unsigned char*)local_session->remote_nonce, 16) <= 0) + goto exit; + // receive our nonce to verify encryption works + if (libp2p_secio_encrypted_read(local_session, &results, &results_size) <= 0) + goto exit; if (results_size != 16) goto exit; - if (libp2p_secio_bytes_compare((char*)results, local_session->nonce, 16) != 0) + if (libp2p_secio_bytes_compare((char*)results, local_session->local_nonce, 16) != 0) goto exit; + */ retVal = 1; exit: @@ -742,7 +896,7 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat if (results != NULL) free(results); if (char_buffer != NULL) - libp2p_utils_vector_free(char_buffer); + free(char_buffer); if (public_key != NULL) libp2p_crypto_public_key_free(public_key); if (remote_peer_id != NULL) @@ -753,6 +907,8 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat libp2p_crypto_ephemeral_key_free(e_private_key); if (exchange_out_protobuf != NULL) free(exchange_out_protobuf); + if (exchange_in != NULL) + libp2p_secio_exchange_free(exchange_in); libp2p_secio_propose_free(propose_out); libp2p_secio_propose_free(propose_in); diff --git a/test/crypto/test_aes.h b/test/crypto/test_aes.h new file mode 100644 index 0000000..a1434d2 --- /dev/null +++ b/test/crypto/test_aes.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +#include "libp2p/crypto/aes.h" + +int test_aes() { + char key[32]; + char iv[17] = "ae287j789wcqe46a"; + char iv_original[17] = "ae287j789wcqe46a"; + unsigned char* encrypted = NULL; + size_t output_size = 0; + char* input = "inc the null, this is 40 bytes of data"; + unsigned char* unencrypted = NULL; + size_t input_size = 40; + int retVal = 0; + + if (libp2p_crypto_aes_key_generate(key) != 1) + goto exit; + + if (libp2p_crypto_aes_encrypt(key, iv, input, input_size, &encrypted, &output_size) != 1) + goto exit; + + if (output_size != 48) + goto exit; + + if (encrypted == NULL) + goto exit; + + if (libp2p_crypto_aes_decrypt(key, iv_original, encrypted, output_size, &unencrypted, &output_size) != 1) + goto exit; + + if (output_size != 48) + goto exit; + + if (strncmp(input, unencrypted, input_size) != 0) + goto exit; + + retVal = 1; + exit: + if (encrypted != NULL) + free(encrypted); + if (unencrypted != NULL) + free(unencrypted); + return retVal; +} diff --git a/test/crypto/test_ephemeral.h b/test/crypto/test_ephemeral.h index 5959fc2..a622a0b 100644 --- a/test/crypto/test_ephemeral.h +++ b/test/crypto/test_ephemeral.h @@ -5,9 +5,76 @@ * Try to generate an ephemeral private key */ int test_ephemeral_key_generate() { + int retVal = 0; struct EphemeralPrivateKey* private_key; - int retVal = libp2p_crypto_ephemeral_keypair_generate("P-256", &private_key); - if (retVal && private_key->secret_key > 0 && private_key->public_key->x > 0 && private_key->public_key->y > 0) - return 1; - return 0; + + if (!libp2p_crypto_ephemeral_keypair_generate("P-256", &private_key)) + goto exit; + + if (private_key->secret_key <= 0 || private_key->public_key->x <= 0 || private_key->public_key->y <= 0) + goto exit; + + retVal = 1; + exit: + libp2p_crypto_ephemeral_key_free(private_key); + return retVal; +} + +/** + * RSA Sign an ephemeral public key + */ +int test_ephemeral_key_sign() { + int retVal = 0; + struct EphemeralPrivateKey* e_private_key; + char* orig_priv_key = "CAASpwkwggSjAgEAAoIBAQCo+BYd213u8PNHNcnXZ6TcUc7oXEoCtWL12XJEFqAiC7emadkp+WtujmuR993L6uCRPU/+mNXIvetodMQ5GORq0MxsPlKFNuVuqHS4PCdWYYFKeel4QsG17T3XMo72Kxm7/pQ1Dbs6tzWD4Ie4Zsa7ziyffjeak1/EExkFf0AKtj4UdXErNRI5gZhkDnWp6Si117Z2VVTslE+kKXWpLK0RYZ4w8DhhZa+ykt2tleOOJt8ocJ3s3yVZQxOafL1lwA8f10VEEeJLPGKJ1Y7mmW7OJhLmrq9tvdTLhum1H5kdYu/pheCm5b6/NSGKS+XbQztu5zedsKSPHsOlYhxYu3GJAgMBAAECggEAZIz93Fam14Jbw4ymyKDM4q9sSapiAKqgcV0tOoecU6ZVa5qhuPDMlcX7DapLOwZTDRtHd2LMFeGvLUIPY0sE4uvOOrv7r3qznd5xVxG09xqfLgrOfNp9HB5KJr3XhXawocclu0yolpBgMFJ1ca73pNtUgrVBsaLx4mTbBwJqwfQpQb/Xdkrdgc663bwXkSl4vApwhZGzi5CFJ6SFC6l6fMKoteWM1ay5e2VCfxi/1g41EINkrqm+QPWhy11bo21ScozxiFiywcxQ8Huo+I5GDHI5EUfIHP97NSRG24/IDSebxsGTukMdpLmiiwizV7hHP2eDlikHAhxBBAF2GkbkAQKBgQDg69jPHrETvHGlKjlEDE8sYQUrwpmGLHfsfZYqBxcz65jPYFAypG4icIU6f8Uhz9c42jLEBssNPT8LyLl2uY467hZZA2SkeWKS66Vi5wBGTN5qOBWUejhzTx8UzasYroWl/0RqFZhU9Xhwg4YqT9X8jYw5mXyOMLatp/d/Y96p0QKBgQDAUQodQZc9yc7olsmNvbuHZtBA+VndKCokFOuJ6YLRK69AL7y6n6eUjne6JqcEIKDC7vr33ryuOdFI+zNzMsdYykE8xcg2c5itWRqG7EdMxgR1dYLUqGC5ustRM/mmhmRzW8DXy88sS+vM4U84yPKv/rfeKAoYgE722R0kkpQCOQKBgQCKfm63yiw6/NP1YXR1hCbUKsFmWqLxzTvisMngAxG0dKNZPfLj2/+80RAYH0ihMztQ1Hph3dT1x/qkJOqeQk9j1eqI0OANrniWAueJaLfwkbB6MyKGlGNiDRwUUTfDMOM2fWIA+F8eITASB8p7D0GyCu6HIQ1i+HfjogNxu2sFoQKBgE4ZGthiqH6JE6NUiKks4ZjM4clg+WNcSjC45iXtVBiJevO/7w6Cg1VKvcg0piKA9Yfz8Kr0Iv9Fr33JtU0U0+t0xyVc1D94lgnfY2xjS1kcGPdyLx0Y+56xApwJVVqQvP4zxo5bz9gXRLzAyqEuyY87C4QGEoN8p5SK+tC9TanRAoGAbC+uVaBtqRqv3LY16+H58BW8lVfN+8dqtBOWluM2uImB1qL2EbKk0X/OChz3Dgzef5VTox6nHcMyYPwXLirS9aIYPggjdpDTjfbWPxUcwYmIB1U++F/mRk1IeDgl9g7t/OlPMg4snxQGEzMPPDVrj/KeLEKv5x+T5yFZ/y+8xNo="; + char* orig_peer_id = "QmZigcoDKaAafGSwot2tchJarCafxKapoRmnYTrZ69ckjb"; + struct RsaPrivateKey* rsa_private_key = NULL; + size_t decode_base64_size = 0; + unsigned char* decode_base64 = NULL; + unsigned char* result; + size_t result_size; + + // build the RSA key + + struct PrivateKey* r_private_key = NULL; + + // 1) take the private key and turn it back into bytes (decode base 64) + decode_base64_size = libp2p_crypto_encoding_base64_decode_size(strlen(orig_priv_key)); + decode_base64 = (unsigned char*)malloc(decode_base64_size); + memset(decode_base64, 0, decode_base64_size); + + if (!libp2p_crypto_encoding_base64_decode((unsigned char*)orig_priv_key, strlen(orig_priv_key), &decode_base64[0], decode_base64_size, &decode_base64_size)) + goto exit; + + if (!libp2p_crypto_private_key_protobuf_decode(decode_base64, decode_base64_size, &r_private_key)) + goto exit; + + // 2) take the bytes of the private key and turn it back into an RSA private key struct + //TODO: should verify that this key is RSA + rsa_private_key = libp2p_crypto_rsa_rsa_private_key_new(); + if (!libp2p_crypto_encoding_x509_der_to_private_key(r_private_key->data, r_private_key->data_size, rsa_private_key)) + goto exit; + + // 2b) take the private key and fill in the public key DER + if (!libp2p_crypto_rsa_private_key_fill_public_key(rsa_private_key)) + goto exit; + + + if (!libp2p_crypto_ephemeral_keypair_generate("P-256", &e_private_key)) + goto exit; + + // attempt to sign + libp2p_crypto_rsa_sign(rsa_private_key, e_private_key->public_key->bytes, e_private_key->public_key->bytes_size, &result, &result_size); + + retVal = 1; + exit: + libp2p_crypto_ephemeral_key_free(e_private_key); + if (result != NULL) + free(result); + libp2p_crypto_rsa_rsa_private_key_free(rsa_private_key); + if (decode_base64 != NULL) + free(decode_base64); + if (r_private_key != NULL) + libp2p_crypto_private_key_free(r_private_key); + return retVal; } diff --git a/test/crypto/test_rsa.h b/test/crypto/test_rsa.h index 0ca7475..f13f7ce 100644 --- a/test/crypto/test_rsa.h +++ b/test/crypto/test_rsa.h @@ -56,12 +56,14 @@ int test_crypto_x509_der_to_private() { if (retVal == 0) return 0; // we now have the bytes, but we must strip off the type (5 bytes) - struct RsaPrivateKey private_key = {0}; + struct RsaPrivateKey* private_key = libp2p_crypto_rsa_rsa_private_key_new(); int bytesToStrip = 5; - retVal = libp2p_crypto_encoding_x509_der_to_private_key(&b[bytesToStrip], ultimate_length-bytesToStrip, &private_key); + retVal = libp2p_crypto_encoding_x509_der_to_private_key(&b[bytesToStrip], ultimate_length-bytesToStrip, private_key); if (retVal == 0) return 0; - return private_key.D > 0; + retVal = private_key->D > 0; + libp2p_crypto_rsa_rsa_private_key_free(private_key); + return retVal; } int test_public_der_to_private_der() { @@ -174,12 +176,12 @@ int test_crypto_rsa_public_key_to_peer_id() { int test_crypto_rsa_signing() { // generate a public and private key pair - struct RsaPrivateKey private_key; - libp2p_crypto_rsa_generate_keypair(&private_key, 2048); + struct RsaPrivateKey* private_key = libp2p_crypto_rsa_rsa_private_key_new(); + libp2p_crypto_rsa_generate_keypair(private_key, 2048); struct RsaPublicKey public_key; - public_key.der = private_key.public_key_der; - public_key.der_length = private_key.public_key_length; + public_key.der = private_key->public_key_der; + public_key.der_length = private_key->public_key_length; // generate some bytes to test with size_t num_bytes = 1000; @@ -196,7 +198,7 @@ int test_crypto_rsa_signing() { size_t result_size; // sign the buffer - if (libp2p_crypto_rsa_sign(&private_key, bytes, num_bytes, &result, &result_size) == 0) { + if (libp2p_crypto_rsa_sign(private_key, bytes, num_bytes, &result, &result_size) == 0) { if (result != NULL) free(result); return 0; @@ -208,6 +210,7 @@ int test_crypto_rsa_signing() { return 0; } free(result); + libp2p_crypto_rsa_rsa_private_key_free(private_key); return 1; } diff --git a/test/test_secio.h b/test/test_secio.h index 961b713..0e603d9 100644 --- a/test/test_secio.h +++ b/test/test_secio.h @@ -1,6 +1,7 @@ #include #include "libp2p/secio/secio.h" +#include "libp2p/secio/exchange.h" #include "libp2p/net/multistream.h" #include "libp2p/net/p2pnet.h" @@ -43,6 +44,7 @@ int test_secio_handshake() { goto exit; secure_session.host = "www.jmjatlanta.com"; + //secure_session.host = "127.0.0.1"; secure_session.port = 4001; secure_session.traffic_type = TCP; // connect to host @@ -52,13 +54,20 @@ int test_secio_handshake() { goto exit; } - if (!libp2p_secio_handshake(&secure_session, rsa_private_key)) { + + if (!libp2p_secio_handshake(&secure_session, rsa_private_key, 0)) { fprintf(stderr, "test_secio_handshake: Unable to do handshake\n"); goto exit; } retVal = 1; exit: + if (secure_session.stream != NULL) + libp2p_net_multistream_stream_free(secure_session.stream); + if (secure_session.local_stretched_key != NULL) + libp2p_crypto_ephemeral_stretched_key_free(secure_session.local_stretched_key); + if (secure_session.remote_stretched_key != NULL) + libp2p_crypto_ephemeral_stretched_key_free(secure_session.remote_stretched_key); if (secure_session.ephemeral_public_key != NULL) free(secure_session.ephemeral_public_key); if (secure_session.chosen_cipher != NULL) @@ -75,3 +84,73 @@ int test_secio_handshake() { libp2p_crypto_rsa_rsa_private_key_free(rsa_private_key); return retVal; } + +int libp2p_secio_encrypt(const struct SecureSession* session, const unsigned char* incoming, size_t incoming_size, unsigned char** outgoing, size_t* outgoing_size); +int libp2p_secio_decrypt(const struct SecureSession* session, const unsigned char* incoming, size_t incoming_size, unsigned char** outgoing, size_t* outgoing_size); + +int test_secio_encrypt_decrypt() { + unsigned char* original = "This is a test message"; + int retVal = 0; + unsigned char* encrypted = NULL; + size_t encrypted_size = 0; + unsigned char* results = NULL; + size_t results_size = 0; + struct SecureSession secure_session; + struct StretchedKey stretched_key; + secure_session.local_stretched_key = &stretched_key; + secure_session.remote_stretched_key = &stretched_key; + + secure_session.local_stretched_key->cipher_key = (unsigned char*)"abcdefghijklmnopqrstuvwxyzabcdef"; + secure_session.local_stretched_key->cipher_size = 32; + secure_session.local_stretched_key->mac_size = 0; + secure_session.mac_function = NULL; + + + if (!libp2p_secio_encrypt(&secure_session, original, strlen((char*)original), &encrypted, &encrypted_size)) + goto exit; + + if (!libp2p_secio_decrypt(&secure_session, encrypted, encrypted_size, &results, &results_size)) + goto exit; + + if (results_size != strlen((char*)original)) + goto exit; + + if (strcmp(original, results) != 0) + goto exit; + + retVal = 1; + exit: + return retVal; +} + +int test_secio_exchange_protobuf_encode() { + char* protobuf = NULL; + size_t protobuf_size = 0, actual_size = 0; + struct Exchange* exch = libp2p_secio_exchange_new(); + int retVal = 0; + + exch->epubkey_size = 100; + exch->epubkey = malloc(exch->epubkey_size); + for(int i = 0; i < exch->epubkey_size; i++) { + exch->epubkey[i] = i; + } + exch->signature_size = 32; + exch->signature = malloc(exch->signature_size); + for(int i = 0; i < exch->signature_size; i++) { + exch->signature[i] = i; + } + + protobuf_size = libp2p_secio_exchange_protobuf_encode_size(exch); + protobuf = malloc(protobuf_size); + + libp2p_secio_exchange_protobuf_encode(exch, protobuf, protobuf_size, &actual_size); + + if (actual_size > protobuf_size) + goto exit; + + retVal = 1; + exit: + free(protobuf); + libp2p_secio_exchange_free(exch); + return retVal; +} diff --git a/test/testit.c b/test/testit.c index 4cafc5b..0d9b03d 100644 --- a/test/testit.c +++ b/test/testit.c @@ -1,5 +1,6 @@ #include +#include "crypto/test_aes.h" #include "crypto/test_rsa.h" #include "crypto/test_base58.h" #include "crypto/test_base32.h" @@ -35,9 +36,12 @@ const char* names[] = { "test_crypto_encoding_base32_encode", "test_protobuf_private_key", "test_secio_handshake", + "test_secio_encrypt_decrypt", + "test_secio_exchange_protobuf_encode", "test_multistream_connect", "test_multistream_get_list", "test_ephemeral_key_generate", + "test_ephemeral_key_sign", "test_dialer_new", "test_dialer_dial", "test_dialer_dial_multistream", @@ -46,7 +50,8 @@ const char* names[] = { "test_record_peer_protobuf", "test_record_message_protobuf", "test_peer", - "test_peerstore" + "test_peerstore", + "test_aes" }; int (*funcs[])(void) = { @@ -72,9 +77,12 @@ int (*funcs[])(void) = { test_crypto_encoding_base32_encode, test_protobuf_private_key, test_secio_handshake, + test_secio_encrypt_decrypt, + test_secio_exchange_protobuf_encode, test_multistream_connect, test_multistream_get_list, test_ephemeral_key_generate, + test_ephemeral_key_sign, test_dialer_new, test_dialer_dial, test_dialer_dial_multistream, @@ -83,7 +91,8 @@ int (*funcs[])(void) = { test_record_peer_protobuf, test_record_message_protobuf, test_peer, - test_peerstore + test_peerstore, + test_aes }; int testit(const char* name, int (*func)(void)) {