Many bug fixes for secio
This commit is contained in:
parent
6d9473069b
commit
0e0b6b1546
19 changed files with 602 additions and 133 deletions
|
@ -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)
|
||||
|
|
84
crypto/aes.c
84
crypto/aes.c
|
@ -1,20 +1,92 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
332
secio/secio.c
332
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);
|
||||
|
|
47
test/crypto/test_aes.h
Normal file
47
test/crypto/test_aes.h
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#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)) {
|
||||
|
|
Loading…
Reference in a new issue