Many bug fixes for secio

This commit is contained in:
John Jones 2017-03-06 19:03:04 -05:00
parent 6d9473069b
commit 0e0b6b1546
19 changed files with 602 additions and 133 deletions

View file

@ -2,7 +2,7 @@ CC = gcc
CFLAGS = -O0 -I../include -I../../c-protobuf -I../../c-multihash/include -g3 CFLAGS = -O0 -I../include -I../../c-protobuf -I../../c-multihash/include -g3
LFLAGS = LFLAGS =
DEPS = 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) %.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS) $(CC) -c -o $@ $< $(CFLAGS)

View file

@ -1,20 +1,92 @@
#include <string.h>
#include <stdlib.h>
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/aes.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 * Encrypt a block of text
* @param key the aes key * @param key the aes key (32 bytes)
* @param iv the random part of encryption * @param iv the random part of encryption (16 bytes)
* @param input the text to encrypt * @param input the text to encrypt
* @param input_size the length of the array * @param input_size the length of the array
* @param output where the output will be placed * @param output where the output will be placed
* @param output_size the length of the memory allocated for output * @param output_size the length of the memory allocated for output
* @returns true(1) on success, otherwise false(0) * @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_context ctx;
mbedtls_aes_init(&ctx); mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, key, 256); mbedtls_aes_setkey_enc(&ctx, key, 256);
mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 24, iv, input, output); // turn input into a multiple of 16
//TODO Implement this method new_size = input_size;
return 0; 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;
} }

View file

@ -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; int byteLen = (bit_size + 7) >> 3;
*results = (unsigned char*)malloc(2*byteLen+1); *results = (unsigned char*)malloc(2*byteLen+1);
memset(*results, 0, 2*byteLen+1);
*results[0] = 4; // uncompressed point *results[0] = 4; // uncompressed point
int uint64_len = 8; int uint64_len = 8;
unsigned char buffer[8]; unsigned char buffer[8];
serialize_uint64(x, &buffer[0]); 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]); 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; *bytes_written = 2 * byteLen + 1;
return 1; return 1;
} }

View file

@ -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 * @param output where the output is placed NOTE: mut be preallocated
* @returns the number of bytes written, or 0 on error * @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_CTX ctx;
SHA1_Init(&ctx); SHA1_Init(&ctx);
SHA1_Update(&ctx, input, input_length); SHA1_Update(&ctx, input, input_length);

View file

@ -7,7 +7,7 @@
* @param output where to place the results, should be 32 bytes * @param output where to place the results, should be 32 bytes
* @returns 1 * @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); mbedtls_sha256(input, input_length, output, 0);
return 32; return 32;
} }

View file

@ -7,7 +7,7 @@
* @param output where to place the results * @param output where to place the results
* @returns 1 * @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); mbedtls_sha512(input, input_length, output, 0);
return 64; return 64;
} }

View file

@ -1,11 +1,32 @@
#pragma once #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 * 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 the text to encrypt
* @param input_size the length of the array * @param input_size the length of the array
* @param output where the output will be placed * @param output where the output will be placed
* @param output_size the length of the memory allocated for output * @param output_size the length of the memory allocated for output
* @returns true(1) on success, otherwise false(0) * @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);

View file

@ -7,9 +7,9 @@
*/ */
struct StretchedKey { struct StretchedKey {
char* iv; unsigned char* iv;
size_t iv_size; size_t iv_size;
char* cipher_key; unsigned char* cipher_key;
size_t cipher_size; size_t cipher_size;
unsigned char* mac_key; unsigned char* mac_key;
size_t mac_size; size_t mac_size;

View file

@ -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 * @param output where the output is placed, should be 40 bytes in width
* @returns the number of bytes written, or 0 on error * @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 */ #endif /* _SHA1_H */

View file

@ -8,6 +8,6 @@
* @param output where to place the results * @param output where to place the results
* @returns 1 * @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 #endif

View file

@ -7,5 +7,5 @@
* @param output where to place the results, should be 64 bytes * @param output where to place the results, should be 64 bytes
* @returns number of bytes written, or 0 * @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);

View file

@ -16,26 +16,35 @@ struct SecureSession {
enum IPTrafficType traffic_type; enum IPTrafficType traffic_type;
// once the connection is established // once the connection is established
struct Stream* stream; struct Stream* stream;
struct PublicKey remote_key;
char* remote_peer_id;
// filled in during negotiations // filled in during negotiations
char* chosen_curve; char* chosen_curve;
char* chosen_cipher; char* chosen_cipher;
char* chosen_hash; 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 unsigned char* shared_key; // a shared key based off of the ephemeral private key
size_t shared_key_size; size_t shared_key_size;
char nonce[16];
struct StretchedKey* stretched_key;
unsigned char* mac; unsigned char* mac;
size_t mac_size; 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 * performs initial communication over an insecure channel to share
* keys, IDs, and initiate connection. This is a framed messaging system * keys, IDs, and initiate connection. This is a framed messaging system
* @param session the secure session to be filled * @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 * @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);

View file

@ -9,11 +9,14 @@ enum WireType secio_exchange_message_fields[] = { WIRETYPE_LENGTH_DELIMITED, WIR
struct Exchange* libp2p_secio_exchange_new() { struct Exchange* libp2p_secio_exchange_new() {
struct Exchange* retVal = (struct Exchange*)malloc(sizeof(struct Exchange)); struct Exchange* out = (struct Exchange*)malloc(sizeof(struct Exchange));
if (retVal == NULL) if (out != NULL) {
return NULL; out->epubkey = NULL;
memset((void*)retVal, 0, sizeof(struct Exchange)); out->epubkey_size = 0;
return retVal; out->signature = NULL;
out->signature_size = 0;
}
return out;
} }
void libp2p_secio_exchange_free( struct Exchange* in) { void libp2p_secio_exchange_free( struct Exchange* in) {

View file

@ -63,7 +63,7 @@ int libp2p_secio_generate_nonce(char* results, int length) {
*/ */
int libp2p_secio_hash(struct Propose* in, unsigned char result[32]) { int libp2p_secio_hash(struct Propose* in, unsigned char result[32]) {
// append public key and nonce // 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, in->public_key_size);
memcpy(&buffer[in->public_key_size], in->rand, in->rand_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); 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; 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) { 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) { if (private_key->type == KEYTYPE_RSA) {
struct RsaPrivateKey rsa_key = {0}; struct RsaPrivateKey rsa_key = {0};
@ -224,11 +233,11 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s
struct StretchedKey* k2; struct StretchedKey* k2;
unsigned char* result = NULL;; unsigned char* result = NULL;;
size_t result_size = 0; size_t result_size = 0;
int (*hash_func)(const char* input, size_t input_length, unsigned char* results); // pointer to hash function int (*hash_func)(const unsigned char* input, size_t input_length, unsigned char* results); // pointer to hash function
char* first_seed = "key_expansion"; unsigned char* first_seed = (unsigned char*)"key_expansion";
char* second_seed = NULL; unsigned char* second_seed = NULL;
char* temp = NULL; unsigned char* temp = NULL;
int seed_size = strlen(first_seed); int seed_size = strlen((char*)first_seed);
unsigned char* current_hash = NULL; unsigned char* current_hash = NULL;
k1 = libp2p_crypto_ephemeral_stretched_key_new(); 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; seed_size += secret_size;
second_seed = malloc(seed_size); second_seed = malloc(seed_size);
memcpy(second_seed, secret, secret_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); current_hash = malloc(hash_size);
hash_func(second_seed, seed_size, current_hash); 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); free(temp);
temp = NULL; 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); temp = malloc(seed_size);
memcpy(temp, secret, secret_size); memcpy(temp, secret, secret_size);
memcpy(&temp[secret_size], current_hash, hash_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 // make a new hash
hash_func(temp, seed_size, current_hash); hash_func(temp, seed_size, current_hash);
// copy the hash to results // 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 // now we have a big result. Cut it up into pieces
if (temp != NULL) if (temp != NULL)
free(temp); free(temp);
temp = (char*)result; temp = result;
k1->mac_size = hash_size;
k1->iv = malloc(k1->iv_size); k1->iv = malloc(k1->iv_size);
memcpy(k1->iv, temp, k1->iv_size); memcpy(k1->iv, temp, k1->iv_size);
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); memcpy(k1->mac_key, temp, k1->mac_size);
temp += k1->mac_size; temp += k1->mac_size;
k2->mac_size = hash_size;
k2->iv = malloc(k2->iv_size); k2->iv = malloc(k2->iv_size);
memcpy(k2->iv, temp, k2->iv_size); memcpy(k2->iv, temp, k2->iv_size);
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; 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 // mac
int (*mac_func)(const char*, size_t, unsigned char*);
if (strcmp(session->chosen_hash, "SHA1") == 0) { if (strcmp(session->chosen_hash, "SHA1") == 0) {
session->stretched_key->mac_size = 40; stretched_key->mac_size = 40;
mac_func = libp2p_crypto_hashing_sha1;
} else if (strcmp(session->chosen_hash, "SHA512") == 0) { } else if (strcmp(session->chosen_hash, "SHA512") == 0) {
session->stretched_key->mac_size = 32; stretched_key->mac_size = 32;
mac_func = libp2p_crypto_hashing_sha512;
} else if (strcmp(session->chosen_hash, "SHA256") == 0) { } else if (strcmp(session->chosen_hash, "SHA256") == 0) {
session->stretched_key->mac_size = 16; stretched_key->mac_size = 16;
mac_func = libp2p_crypto_hashing_sha256;
} else { } else {
return 0; return 0;
} }
session->stretched_key->mac_key = malloc(session->stretched_key->mac_size); stretched_key->mac_key = malloc(stretched_key->mac_size);
mac_func(session->stretched_key->cipher_key, session->stretched_key->cipher_size, session->stretched_key->mac_key); session->mac_function(stretched_key->cipher_key, stretched_key->cipher_size, stretched_key->mac_key);
// block cipher // block cipher
if (strcmp(session->chosen_cipher, "AES-128") == 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, "AES-256") == 0) {
} else if (strcmp(session->chosen_cipher, "Blowfish") == 0) { } else if (strcmp(session->chosen_cipher, "Blowfish") == 0) {
//TODO: Implement blowfish
return 0;
} else { } else {
return 0; return 0;
} }
//TODO: set up the encrypted streams
return 1; 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; int num_bytes = 0;
if (data_length > 0) { // only do this is if there is something to send 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; left = left - written_this_time;
} while (left > 0); } while (left > 0);
// then send the actual data // then send the actual data
fprintf(stderr, "About to send %lu bytes (aka %u)\n", data_length, size);
left = data_length; left = data_length;
written = 0; written = 0;
do { do {
@ -443,7 +456,14 @@ int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size
return num_bytes; 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; uint32_t buffer_size;
// first read the 4 byte integer // 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)) { if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) {
// TODO: use epoll or select to wait for socket to be writable // TODO: use epoll or select to wait for socket to be writable
} else { } 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; return 0;
} }
} }
@ -497,15 +517,122 @@ int libp2p_secio_read(struct SecureSession* session, unsigned char** results, si
return buffer_size; 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 * performs initial communication over an insecure channel to share
* keys, IDs, and initiate connection. This is a framed messaging system * keys, IDs, and initiate connection. This is a framed messaging system
* NOTE: session must contain a valid socket_descriptor that is a multistream. * 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 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 * @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; int retVal = 0;
size_t results_size = 0, bytes_written = 0; size_t results_size = 0, bytes_written = 0;
unsigned char* propose_in_bytes = NULL; // the remote protobuf 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; struct Exchange* exchange_out = NULL;
unsigned char* exchange_out_protobuf = NULL; unsigned char* exchange_out_protobuf = NULL;
size_t exchange_out_protobuf_size = 0; 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 StretchedKey* k1 = NULL, *k2 = NULL;
struct PrivateKey priv = {0}; struct PrivateKey* priv = NULL;
struct PublicKey pub_key = {0}; struct PublicKey pub_key = {0};
struct SecureSession remote_session = {0};
char* remote_peer_id = NULL; char* remote_peer_id = NULL;
struct EphemeralPrivateKey* e_private_key = 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) if (bytes_written <= 0)
goto exit; goto exit;
// we should get back the secio confirmation if (!remote_requested) {
bytes_written = libp2p_net_multistream_read(local_session->stream, &results, &results_size); // we should get back the secio confirmation
if (bytes_written < 5 || strstr((char*)results, "secio") == NULL) bytes_written = libp2p_net_multistream_read(local_session->stream, &results, &results_size);
goto exit; if (bytes_written < 5 || strstr((char*)results, "secio") == NULL)
goto exit;
free(results); free(results);
results = NULL; results = NULL;
results_size = 0; results_size = 0;
}
// generate 16 byte nonce // 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; goto exit;
} }
// Build the proposal to be sent to the new connection: // Build the proposal to be sent to the new connection:
propose_out = libp2p_secio_propose_new(); 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 // public key - protobuf it and stick it in propose_out
pub_key.type = KEYTYPE_RSA; pub_key.type = KEYTYPE_RSA;
@ -600,30 +729,28 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
goto exit; 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) if (bytes_written < propose_out_size)
goto exit; goto exit;
// now receive the proposal from the new connection // 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) if (bytes_written <= 0)
goto exit; goto exit;
if (!libp2p_secio_propose_protobuf_decode(propose_in_bytes, propose_in_size, &propose_in)) if (!libp2p_secio_propose_protobuf_decode(propose_in_bytes, propose_in_size, &propose_in))
goto exit; 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 // 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)) if (!libp2p_crypto_public_key_protobuf_decode(propose_in->public_key, propose_in->public_key_size, &public_key))
goto exit; goto exit;
// generate their peer id // generate their peer id
libp2p_crypto_public_key_to_peer_id(public_key, &remote_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 // negotiate encryption parameters NOTE: SelectBest must match, otherwise this won't work
// first determine order // first determine order
libp2p_secio_hash(propose_in, order_hash_in); 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) 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; 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 // generate EphemeralPubKey
if (libp2p_crypto_ephemeral_keypair_generate(local_session->chosen_curve, &e_private_key) == 0) if (libp2p_crypto_ephemeral_keypair_generate(local_session->chosen_curve, &e_private_key) == 0)
goto exit; 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_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); libp2p_crypto_ephemeral_key_free(e_private_key);
e_private_key = NULL; e_private_key = NULL;
// build buffer to sign // 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) if (char_buffer == NULL)
goto exit; goto exit;
libp2p_utils_vector_add(char_buffer, propose_in_bytes, propose_in_size); memcpy(&char_buffer[0], propose_in_bytes, propose_in_size);
libp2p_utils_vector_add(char_buffer, propose_out_bytes, propose_out_size); memcpy(&char_buffer[propose_in_size], 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[propose_in_size + propose_out_size], local_session->ephemeral_public_key, local_session->ephemeral_public_key_size);
// send Exchange packet // send Exchange packet
exchange_out = libp2p_secio_exchange_new(); exchange_out = libp2p_secio_exchange_new();
if (exchange_out == NULL)
goto exit;
exchange_out->epubkey = (unsigned char*)malloc(local_session->ephemeral_public_key_size); 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); 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; exchange_out->epubkey_size = local_session->ephemeral_public_key_size;
priv.type = KEYTYPE_RSA; priv = libp2p_crypto_private_key_new();
priv.data = (unsigned char*)private_key->der; priv->type = KEYTYPE_RSA;
priv.data_size = private_key->der_length; priv->data = (unsigned char*)private_key->der;
libp2p_secio_sign(&priv, (char*)char_buffer->buffer, char_buffer->buffer_size, &exchange_out->signature, &exchange_out->signature_size); priv->data_size = private_key->der_length;
libp2p_utils_vector_free(char_buffer); libp2p_secio_sign(priv, char_buffer, char_buffer_length, &exchange_out->signature, &exchange_out->signature_size);
free(char_buffer);
char_buffer = NULL; 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_size = libp2p_secio_exchange_protobuf_encode_size(exchange_out);
exchange_out_protobuf = (unsigned char*)malloc(exchange_out_protobuf_size); 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; goto exit;
libp2p_secio_exchange_protobuf_encode(exchange_out, exchange_out_protobuf, exchange_out_protobuf_size, &bytes_written); libp2p_secio_exchange_protobuf_encode(exchange_out, exchange_out_protobuf, exchange_out_protobuf_size, &bytes_written);
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_unencrypted_write(local_session, exchange_out_protobuf, exchange_out_protobuf_size);
bytes_written = libp2p_secio_write(local_session, exchange_out_protobuf, exchange_out_protobuf_size);
if (exchange_out_protobuf_size != bytes_written) if (exchange_out_protobuf_size != bytes_written)
goto exit; goto exit;
free(exchange_out_protobuf); free(exchange_out_protobuf);
exchange_out_protobuf = NULL; 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 // parse and verify
remote_session.ephemeral_public_key = exchange_in->epubkey; local_session->remote_ephemeral_public_key = exchange_in->epubkey;
remote_session.ephemeral_public_key_size = exchange_in->epubkey_size; 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) if (char_buffer == NULL)
goto exit; goto exit;
libp2p_utils_vector_add(char_buffer, propose_in_bytes, propose_in_size); memcpy(&char_buffer[0], propose_in_bytes, propose_in_size);
libp2p_utils_vector_add(char_buffer, propose_out_bytes, propose_out_size); memcpy(&char_buffer[propose_in_size], 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[propose_in_size + propose_out_size], local_session->remote_ephemeral_public_key, local_session->remote_ephemeral_public_key_size);
// TODO: signature verification // TODO: signature verification
//if (!libp2p_secio_verify_signature(public_key, char_buffer->buffer, char_buffer->buffer_size, exchange_in->signature)) //if (!libp2p_secio_verify_signature(public_key, char_buffer->buffer, char_buffer->buffer_size, exchange_in->signature))
// goto exit; // goto exit;
libp2p_utils_vector_free(char_buffer); free(char_buffer);
char_buffer = NULL; char_buffer = NULL;
// 2.2 generate shared key NOTE: this was done above // 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); 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) { if (order > 1) {
local_session->stretched_key = k1; local_session->local_stretched_key = k1;
remote_session.stretched_key = k2; local_session->remote_stretched_key = k2;
} else { } else {
local_session->stretched_key = k2; local_session->local_stretched_key = k2;
remote_session.stretched_key = k1; local_session->remote_stretched_key = k1;
} }
// prepare MAC + cipher // 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(local_session, local_session->local_stretched_key);
libp2p_secio_make_mac_and_cipher(&remote_session); // ?? 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 /* temporarily comment this out to chase memory bug...
libp2p_secio_write(local_session, (unsigned char*)local_session->nonce, 16); // send expected message (their nonce) to verify encryption works
libp2p_secio_read(local_session, &results, &results_size); 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) if (results_size != 16)
goto exit; 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; goto exit;
*/
retVal = 1; retVal = 1;
exit: exit:
@ -742,7 +896,7 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
if (results != NULL) if (results != NULL)
free(results); free(results);
if (char_buffer != NULL) if (char_buffer != NULL)
libp2p_utils_vector_free(char_buffer); free(char_buffer);
if (public_key != NULL) if (public_key != NULL)
libp2p_crypto_public_key_free(public_key); libp2p_crypto_public_key_free(public_key);
if (remote_peer_id != NULL) 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); libp2p_crypto_ephemeral_key_free(e_private_key);
if (exchange_out_protobuf != NULL) if (exchange_out_protobuf != NULL)
free(exchange_out_protobuf); 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_out);
libp2p_secio_propose_free(propose_in); libp2p_secio_propose_free(propose_in);

47
test/crypto/test_aes.h Normal file
View file

@ -0,0 +1,47 @@
#pragma once
#include <stdlib.h>
#include <string.h>
#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;
}

View file

@ -5,9 +5,76 @@
* Try to generate an ephemeral private key * Try to generate an ephemeral private key
*/ */
int test_ephemeral_key_generate() { int test_ephemeral_key_generate() {
int retVal = 0;
struct EphemeralPrivateKey* private_key; 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) if (!libp2p_crypto_ephemeral_keypair_generate("P-256", &private_key))
return 1; goto exit;
return 0;
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;
} }

View file

@ -56,12 +56,14 @@ int test_crypto_x509_der_to_private() {
if (retVal == 0) if (retVal == 0)
return 0; return 0;
// we now have the bytes, but we must strip off the type (5 bytes) // 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; 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) if (retVal == 0)
return 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() { 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() { int test_crypto_rsa_signing() {
// generate a public and private key pair // generate a public and private key pair
struct RsaPrivateKey private_key; struct RsaPrivateKey* private_key = libp2p_crypto_rsa_rsa_private_key_new();
libp2p_crypto_rsa_generate_keypair(&private_key, 2048); libp2p_crypto_rsa_generate_keypair(private_key, 2048);
struct RsaPublicKey public_key; struct RsaPublicKey public_key;
public_key.der = private_key.public_key_der; public_key.der = private_key->public_key_der;
public_key.der_length = private_key.public_key_length; public_key.der_length = private_key->public_key_length;
// generate some bytes to test with // generate some bytes to test with
size_t num_bytes = 1000; size_t num_bytes = 1000;
@ -196,7 +198,7 @@ int test_crypto_rsa_signing() {
size_t result_size; size_t result_size;
// sign the buffer // 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) if (result != NULL)
free(result); free(result);
return 0; return 0;
@ -208,6 +210,7 @@ int test_crypto_rsa_signing() {
return 0; return 0;
} }
free(result); free(result);
libp2p_crypto_rsa_rsa_private_key_free(private_key);
return 1; return 1;
} }

View file

@ -1,6 +1,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "libp2p/secio/secio.h" #include "libp2p/secio/secio.h"
#include "libp2p/secio/exchange.h"
#include "libp2p/net/multistream.h" #include "libp2p/net/multistream.h"
#include "libp2p/net/p2pnet.h" #include "libp2p/net/p2pnet.h"
@ -43,6 +44,7 @@ int test_secio_handshake() {
goto exit; goto exit;
secure_session.host = "www.jmjatlanta.com"; secure_session.host = "www.jmjatlanta.com";
//secure_session.host = "127.0.0.1";
secure_session.port = 4001; secure_session.port = 4001;
secure_session.traffic_type = TCP; secure_session.traffic_type = TCP;
// connect to host // connect to host
@ -52,13 +54,20 @@ int test_secio_handshake() {
goto exit; 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"); fprintf(stderr, "test_secio_handshake: Unable to do handshake\n");
goto exit; goto exit;
} }
retVal = 1; retVal = 1;
exit: 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) if (secure_session.ephemeral_public_key != NULL)
free(secure_session.ephemeral_public_key); free(secure_session.ephemeral_public_key);
if (secure_session.chosen_cipher != NULL) if (secure_session.chosen_cipher != NULL)
@ -75,3 +84,73 @@ int test_secio_handshake() {
libp2p_crypto_rsa_rsa_private_key_free(rsa_private_key); libp2p_crypto_rsa_rsa_private_key_free(rsa_private_key);
return retVal; 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;
}

View file

@ -1,5 +1,6 @@
#include <stdio.h> #include <stdio.h>
#include "crypto/test_aes.h"
#include "crypto/test_rsa.h" #include "crypto/test_rsa.h"
#include "crypto/test_base58.h" #include "crypto/test_base58.h"
#include "crypto/test_base32.h" #include "crypto/test_base32.h"
@ -35,9 +36,12 @@ const char* names[] = {
"test_crypto_encoding_base32_encode", "test_crypto_encoding_base32_encode",
"test_protobuf_private_key", "test_protobuf_private_key",
"test_secio_handshake", "test_secio_handshake",
"test_secio_encrypt_decrypt",
"test_secio_exchange_protobuf_encode",
"test_multistream_connect", "test_multistream_connect",
"test_multistream_get_list", "test_multistream_get_list",
"test_ephemeral_key_generate", "test_ephemeral_key_generate",
"test_ephemeral_key_sign",
"test_dialer_new", "test_dialer_new",
"test_dialer_dial", "test_dialer_dial",
"test_dialer_dial_multistream", "test_dialer_dial_multistream",
@ -46,7 +50,8 @@ const char* names[] = {
"test_record_peer_protobuf", "test_record_peer_protobuf",
"test_record_message_protobuf", "test_record_message_protobuf",
"test_peer", "test_peer",
"test_peerstore" "test_peerstore",
"test_aes"
}; };
int (*funcs[])(void) = { int (*funcs[])(void) = {
@ -72,9 +77,12 @@ int (*funcs[])(void) = {
test_crypto_encoding_base32_encode, test_crypto_encoding_base32_encode,
test_protobuf_private_key, test_protobuf_private_key,
test_secio_handshake, test_secio_handshake,
test_secio_encrypt_decrypt,
test_secio_exchange_protobuf_encode,
test_multistream_connect, test_multistream_connect,
test_multistream_get_list, test_multistream_get_list,
test_ephemeral_key_generate, test_ephemeral_key_generate,
test_ephemeral_key_sign,
test_dialer_new, test_dialer_new,
test_dialer_dial, test_dialer_dial,
test_dialer_dial_multistream, test_dialer_dial_multistream,
@ -83,7 +91,8 @@ int (*funcs[])(void) = {
test_record_peer_protobuf, test_record_peer_protobuf,
test_record_message_protobuf, test_record_message_protobuf,
test_peer, test_peer,
test_peerstore test_peerstore,
test_aes
}; };
int testit(const char* name, int (*func)(void)) { int testit(const char* name, int (*func)(void)) {