in the middle of ephemeral encryption implementation
This commit is contained in:
parent
6d5f7410c6
commit
783855fe26
19 changed files with 686 additions and 47 deletions
11
Makefile
11
Makefile
|
@ -8,9 +8,10 @@ OBJS = crypto/*.o crypto/encoding/*.o \
|
|||
net/*.o \
|
||||
record/*.o \
|
||||
routing/*.o \
|
||||
secio/*.o
|
||||
secio/*.o \
|
||||
utils/*.o
|
||||
|
||||
link: $(OBJS)
|
||||
link:
|
||||
ar rcs libp2p.a $(OBJS)
|
||||
|
||||
compile:
|
||||
|
@ -21,6 +22,7 @@ compile:
|
|||
cd record; make all;
|
||||
cd routing; make all;
|
||||
cd secio; make all;
|
||||
cd utils; make all;
|
||||
|
||||
test: compile link
|
||||
cd test; make all;
|
||||
|
@ -34,9 +36,10 @@ clean:
|
|||
cd hashmap; make clean;
|
||||
cd net; make clean;
|
||||
cd thirdparty; make clean
|
||||
cd test; make clean;
|
||||
cd record; make clean;
|
||||
cd routing; make clean;
|
||||
cd secio; make all;
|
||||
cd secio; make clean;
|
||||
cd utils; make clean;
|
||||
cd test; make clean;
|
||||
rm -rf libp2p.a
|
||||
|
||||
|
|
|
@ -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
|
||||
OBJS = rsa.o sha256.o sha512.o sha1.o key.o peerutils.o ephemeral.o
|
||||
|
||||
%.o: %.c $(DEPS)
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
|
73
crypto/ephemeral.c
Normal file
73
crypto/ephemeral.c
Normal file
|
@ -0,0 +1,73 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mbedtls/config.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "libp2p/crypto/ephemeral.h"
|
||||
|
||||
struct EphemeralPrivateKey* libp2p_crypto_ephemeral_key_new(uint64_t priv, uint64_t x, uint64_t y) {
|
||||
struct EphemeralPrivateKey* results = (struct EphemeralPrivateKey*)malloc(sizeof(struct EphemeralPrivateKey));
|
||||
if (results != NULL) {
|
||||
results->secret_key = priv;
|
||||
results->public_key = (struct EphemeralPublicKey*)malloc(sizeof(struct EphemeralPublicKey));
|
||||
if (results->public_key == NULL) {
|
||||
free(results);
|
||||
results = NULL;
|
||||
} else {
|
||||
results->public_key->x = x;
|
||||
results->public_key->y = y;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
void libp2p_crypto_ephemeral_key_free(struct EphemeralPrivateKey* in) {
|
||||
if (in != NULL) {
|
||||
if (in->public_key != NULL)
|
||||
free(in->public_key);
|
||||
free(in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a Ephemeral Public Key as well as a shared key
|
||||
* @param curve the curve to use (P-256, P-384, or P-521)
|
||||
* @param private_key the struct to store the generated key
|
||||
* @returns true(1) on success, otherwise false(0)
|
||||
*/
|
||||
int libp2p_crypto_ephemeral_key_generate(char* curve, struct EphemeralPrivateKey** private_key) {
|
||||
int retVal = 0;
|
||||
mbedtls_ecdsa_context ctx;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
|
||||
int selected_curve = 0;
|
||||
if (strcmp(curve, "P-256") == 0)
|
||||
selected_curve = MBEDTLS_ECP_DP_SECP256R1;
|
||||
else if (strcmp(curve, "P-384") == 0)
|
||||
selected_curve = MBEDTLS_ECP_DP_SECP384R1;
|
||||
else
|
||||
selected_curve = MBEDTLS_ECP_DP_SECP521R1;
|
||||
|
||||
char* pers = "bitShares";
|
||||
|
||||
mbedtls_ecdsa_init(&ctx);
|
||||
|
||||
// seed random number generator
|
||||
mbedtls_entropy_init(&entropy);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers)) != 0)
|
||||
goto exit;
|
||||
|
||||
if (mbedtls_ecdsa_genkey(&ctx, selected_curve, mbedtls_ctr_drbg_random, &ctr_drbg) != 0)
|
||||
goto exit;
|
||||
|
||||
*private_key = libp2p_crypto_ephemeral_key_new(*ctx.d->p, *ctx.Q->X.p, *ctx.Q->Y.p);
|
||||
retVal = 1;
|
||||
|
||||
exit:
|
||||
|
||||
return retVal;
|
||||
}
|
62
crypto/rsa.c
62
crypto/rsa.c
|
@ -236,24 +236,74 @@ int libp2p_crypto_rsa_rsa_private_key_free(struct RsaPrivateKey* private_key) {
|
|||
* @param result the resultant signature. Note: should be pre-allocated and be the size of the private key (i.e. 2048 bit key can store a sig in 256 bytes)
|
||||
* @returns true(1) on successs, otherwise false(0)
|
||||
*/
|
||||
int libp2p_crypto_rsa_sign(struct RsaPrivateKey* private_key, unsigned char* message, size_t message_length, unsigned char* result) {
|
||||
int libp2p_crypto_rsa_sign(struct RsaPrivateKey* private_key, const unsigned char* message, size_t message_length, unsigned char* result) {
|
||||
unsigned char output[32];
|
||||
libp2p_crypto_hashing_sha256(message, message_length, output);
|
||||
|
||||
mbedtls_rsa_context ctx;
|
||||
// make a pk_context from the private key
|
||||
mbedtls_pk_context private_context;
|
||||
mbedtls_pk_init(&private_context);
|
||||
mbedtls_pk_parse_key(&private_context, (unsigned char*)private_key->der, private_key->der_length, NULL, 0);
|
||||
|
||||
// gety just the RSA portion of the context
|
||||
mbedtls_rsa_context* ctx = mbedtls_pk_rsa(private_context);
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_rsa_init(&ctx, MBEDTLS_RSA_PKCS_V15, 0);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
int retVal = mbedtls_rsa_rsassa_pkcs1_v15_sign( &ctx,
|
||||
mbedtls_ctr_drbg_random,
|
||||
|
||||
// sign
|
||||
int retVal = mbedtls_rsa_rsassa_pkcs1_v15_sign(ctx,
|
||||
NULL, //mbedtls_ctr_drbg_random,
|
||||
&ctr_drbg,
|
||||
MBEDTLS_RSA_PRIVATE,
|
||||
MBEDTLS_MD_SHA256,
|
||||
32,
|
||||
output,
|
||||
result );
|
||||
//int retVal = mbedtls_rsa_private(&ctx, NULL, NULL, message, result);
|
||||
// cleanup
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
//mbetdls_rsa_free(ctx);
|
||||
mbedtls_pk_free(&private_context);
|
||||
return retVal == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* verify a signature
|
||||
*@param public_key the public key to use
|
||||
*@param message the message to compare to the signature
|
||||
*@param message_length the length of the message
|
||||
*@param signature the signature that was given
|
||||
*@returns true(1) if the signature matches the SHA2-256 hash of message, false(0) otherwise
|
||||
*/
|
||||
int libp2p_crypto_rsa_verify(struct RsaPublicKey* public_key, const unsigned char* message, size_t message_length, const unsigned char* signature) {
|
||||
|
||||
// hash the message
|
||||
unsigned char output[32];
|
||||
libp2p_crypto_hashing_sha256(message, message_length, output);
|
||||
|
||||
// make a pk_context from the public key
|
||||
mbedtls_pk_context public_context;
|
||||
mbedtls_pk_init(&public_context);
|
||||
mbedtls_pk_parse_public_key(&public_context, (unsigned char*)public_key->der, public_key->der_length);
|
||||
|
||||
mbedtls_rsa_context* ctx = mbedtls_pk_rsa(public_context);
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
|
||||
int retVal = mbedtls_rsa_rsassa_pkcs1_v15_verify(ctx, // the rsa public key has to be in the context
|
||||
NULL, // random number generator, but not needed because this is not a private key
|
||||
NULL, //mbedtls_ctr_drbg_random, // random number generator
|
||||
MBEDTLS_RSA_PUBLIC, // mode RSA_PUBLIC or RSA_PRIVATE
|
||||
MBEDTLS_MD_SHA256, // type of message digest
|
||||
32, // ignored because we know it from the parameter previous
|
||||
output, signature); // the actual signature to compare
|
||||
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
|
||||
return retVal == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
23
include/libp2p/crypto/ephemeral.h
Normal file
23
include/libp2p/crypto/ephemeral.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* General helpers for ephemeral keys
|
||||
*/
|
||||
|
||||
struct EphemeralPublicKey {
|
||||
uint64_t x;
|
||||
uint64_t y;
|
||||
};
|
||||
|
||||
struct EphemeralPrivateKey {
|
||||
uint64_t secret_key;
|
||||
struct EphemeralPublicKey* public_key;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a Ephemeral Public Key as well as a shared key
|
||||
* @param curve the curve to use (P-256, P-384, or P-521)
|
||||
* @param private_key where to store the private key
|
||||
* @reutrns true(1) on success, otherwise false(0)
|
||||
*/
|
||||
int libp2p_crypto_ephemeral_key_generate(char* curve, struct EphemeralPrivateKey* private_key);
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
struct RsaPublicKey {
|
||||
char* der;
|
||||
size_t der_length;
|
||||
};
|
||||
|
||||
struct RsaPrivateKey {
|
||||
// the basics of a key pair
|
||||
unsigned long long QP;
|
||||
|
@ -53,6 +58,8 @@ int libp2p_crypto_rsa_rsa_private_key_free(struct RsaPrivateKey* private_key);
|
|||
* @param result the resultant signature. Note: should be pre-allocated and be the size of the private key (i.e. 2048)
|
||||
* @returns true(1) on successs, otherwise false(0)
|
||||
*/
|
||||
int libp2p_crypto_rsa_sign(struct RsaPrivateKey* private_key, unsigned char* message, size_t message_length, unsigned char* result);
|
||||
int libp2p_crypto_rsa_sign(struct RsaPrivateKey* private_key, const unsigned char* message, size_t message_length, unsigned char* result);
|
||||
|
||||
int libp2p_crypto_rsa_verify(struct RsaPublicKey* public_key, const unsigned char* message, size_t message_length, const unsigned char* signature);
|
||||
|
||||
#endif /* rsa_h */
|
||||
|
|
|
@ -7,6 +7,8 @@ struct Exchange {
|
|||
size_t signature_size;
|
||||
};
|
||||
|
||||
struct Exchange* libp2p_secio_exchange_new();
|
||||
|
||||
/**
|
||||
* retrieves the approximate size of an encoded version of the passed in struct
|
||||
* @param in the struct to look at
|
||||
|
|
|
@ -18,6 +18,15 @@ struct SecureSession {
|
|||
int socket_descriptor;
|
||||
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;
|
||||
size_t ephemeral_public_key_size;
|
||||
unsigned char* shared_key;
|
||||
size_t shared_key_size;
|
||||
char nonce[16];
|
||||
};
|
||||
|
||||
/***
|
||||
|
|
8
include/libp2p/utils/string_list.h
Normal file
8
include/libp2p/utils/string_list.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
struct StringList {
|
||||
char* string;
|
||||
struct StringList* next;
|
||||
};
|
||||
|
||||
struct StringList* libp2p_utils_string_list_new();
|
||||
|
||||
void libp2p_utils_string_list_free(struct StringList* in);
|
24
include/libp2p/utils/vector.h
Normal file
24
include/libp2p/utils/vector.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
/***
|
||||
* A very simple vector implementation for unsigned chars
|
||||
*/
|
||||
|
||||
/**
|
||||
* The struct
|
||||
*/
|
||||
struct Libp2pVector {
|
||||
unsigned char* buffer;
|
||||
size_t buffer_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create and destroy
|
||||
*/
|
||||
struct Libp2pVector* libp2p_utils_vector_new();
|
||||
void libp2p_utils_vector_free(struct Libp2pVector* vector);
|
||||
|
||||
/**
|
||||
* Add bytes to vector
|
||||
*/
|
||||
int libp2p_utils_vector_add(struct Libp2pVector* vector, unsigned char* in_bytes, size_t in_size);
|
38
secio/char_vector.c
Normal file
38
secio/char_vector.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "libp2p/secio/char_vector.h"
|
||||
|
||||
struct UnsignedCharVector* char_vector_new() {
|
||||
struct UnsignedCharVector* vector = (struct UnsignedCharVector*)malloc(sizeof(struct UnsignedCharVector));
|
||||
vector->buffer = NULL;
|
||||
vector->buffer_size = 0;
|
||||
return vector;
|
||||
}
|
||||
|
||||
void char_vector_free(struct UnsignedCharVector* vector) {
|
||||
if (vector != NULL) {
|
||||
if (vector->buffer != NULL)
|
||||
free(vector->buffer);
|
||||
vector->buffer = NULL;
|
||||
vector->buffer_size = 0;
|
||||
free(vector);
|
||||
vector = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int char_vector_add(struct UnsignedCharVector* vector, unsigned char* in_bytes, size_t in_size) {
|
||||
// make new memory
|
||||
if (vector->buffer == NULL) {
|
||||
vector->buffer = (unsigned char*)malloc(in_size);
|
||||
if (vector->buffer == NULL)
|
||||
return 0;
|
||||
vector->buffer_size = in_size;
|
||||
} else {
|
||||
vector->buffer = (unsigned char*)realloc(vector->buffer_size + in_size);
|
||||
if (vector->buffer == NULL)
|
||||
return 0;
|
||||
memcpy(&vector->buffer[vector->buffer_size], in_bytes, in_size);
|
||||
vector->buffer_size = in_size + vector->buffer_size;
|
||||
}
|
||||
return 1;
|
||||
}
|
319
secio/secio.c
319
secio/secio.c
|
@ -5,8 +5,12 @@
|
|||
|
||||
#include "libp2p/secio/secio.h"
|
||||
#include "libp2p/secio/propose.h"
|
||||
//#include "libp2p/net/p2pnet.h"
|
||||
#include "libp2p/secio/exchange.h"
|
||||
#include "libp2p/net/multistream.h"
|
||||
#include "libp2p/crypto/sha256.h"
|
||||
#include "libp2p/crypto/ephemeral.h"
|
||||
#include "libp2p/utils/string_list.h"
|
||||
#include "libp2p/utils/vector.h"
|
||||
|
||||
const char* SupportedExchanges = "P-256,P-384,P-521";
|
||||
const char* SupportedCiphers = "AES-256,AES-128,Blowfish";
|
||||
|
@ -46,42 +50,246 @@ int libp2p_secio_generate_nonce(char* results, int length) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a hash based on a Propose struct
|
||||
* @param in the struct Propose
|
||||
* @param result where to put the result (should be char[32])
|
||||
* @returns true(1) on success
|
||||
*/
|
||||
int libp2p_secio_hash(struct Propose* in, unsigned char result[32]) {
|
||||
// append public key and nonce
|
||||
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);
|
||||
}
|
||||
|
||||
/***
|
||||
* Compare 2 hashes lexicographically
|
||||
* @param a the a side
|
||||
* @param b the b side
|
||||
* @param length the length of a and b
|
||||
* @returns a -1, 0, or 1
|
||||
*/
|
||||
int libp2p_secio_bytes_compare(const char* a, const char* b, int length) {
|
||||
for(int i = 0; i < length; i++) {
|
||||
if (b[i] > a[i])
|
||||
return -1;
|
||||
if (a[i] > b[i])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libp2p_secio_string_allocate(char* in, char** out) {
|
||||
*out = (char*)malloc(strlen(in) + 1);
|
||||
strcpy(*out, in);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct StringList* libp2p_secio_split_list(const char* list, int list_size) {
|
||||
struct StringList* head = NULL;
|
||||
struct StringList* last = NULL;
|
||||
struct StringList* current = NULL;
|
||||
char* curr_tok = NULL;
|
||||
|
||||
// make a copy
|
||||
char copy[list_size+1];
|
||||
memcpy(©[0], list, list_size);
|
||||
copy[list_size] = 0;
|
||||
|
||||
curr_tok = strtok(copy, ",");
|
||||
while (curr_tok != NULL) {
|
||||
current = libp2p_utils_string_list_new();
|
||||
libp2p_secio_string_allocate(curr_tok, ¤t->string);
|
||||
if ( head == NULL) {
|
||||
head = current;
|
||||
last = current;
|
||||
} else {
|
||||
last->next = current;
|
||||
}
|
||||
last = current;
|
||||
curr_tok = strtok(NULL, ",");
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare 2 lists, and pick the best one
|
||||
* @param order which carries more weight
|
||||
* @param local_list the list to compare
|
||||
* @param local_list_size the size of the list
|
||||
* @param remote_list the list to compare
|
||||
* @param remote_list_size the size of the list
|
||||
* @param results where to put the results (NOTE: Allocate memory for this)
|
||||
* @returns true(1) on success, otherwise, false(0)
|
||||
*/
|
||||
int libp2p_secio_select_best(int order, const char* local_list, int local_list_size, const char* remote_list, int remote_list_size, char** results) {
|
||||
struct StringList* lead_head = libp2p_secio_split_list(local_list, local_list_size);
|
||||
struct StringList* follower_head = NULL;
|
||||
struct StringList* lead = NULL;
|
||||
struct StringList* follower = NULL;
|
||||
int match = 0;
|
||||
|
||||
//shortcut
|
||||
if (order == 0)
|
||||
{
|
||||
libp2p_secio_string_allocate(lead_head->string, results);
|
||||
libp2p_utils_string_list_free(lead_head);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// this list doesn't match. Do further investigation
|
||||
if (order > 0) { // lead is local
|
||||
follower_head = libp2p_secio_split_list(remote_list, remote_list_size);
|
||||
} else {
|
||||
follower_head = lead_head;
|
||||
lead_head = libp2p_secio_split_list(remote_list, remote_list_size);
|
||||
}
|
||||
|
||||
lead = lead_head;
|
||||
follower = follower_head;
|
||||
// now work through the list, looking for a match
|
||||
while ( lead != NULL ) {
|
||||
while (follower != NULL) {
|
||||
if (strcmp(lead->string, follower->string) == 0) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
follower = follower->next;
|
||||
}
|
||||
if (match)
|
||||
break;
|
||||
follower = follower_head;
|
||||
lead = lead->next;
|
||||
}
|
||||
if (!match)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the signature is correct based on the given bytes in "in"
|
||||
* @param public_key the public key to use
|
||||
* @param in the bytes that were signed
|
||||
* @param in_length the number of bytes
|
||||
* @param signature the signature that was given to us
|
||||
* @param signature_length the length of the signature
|
||||
* @returns true(1) if the signature is correct, false(0) otherwise
|
||||
*/
|
||||
int libp2p_secio_verify_signature(struct PublicKey* public_key, const unsigned char* in, size_t in_length, unsigned char* signature) {
|
||||
if (public_key->type == KEYTYPE_RSA) {
|
||||
struct RsaPublicKey rsa_key;
|
||||
rsa_key.der = (char*)public_key->data;
|
||||
rsa_key.der_length = public_key->data_size;
|
||||
return libp2p_crypto_rsa_verify(&rsa_key, in, in_length, signature);
|
||||
}
|
||||
// TODO: Implement this method for non-RSA
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libp2p_secio_sign(struct PrivateKey* private_key, unsigned char* in, size_t in_length, unsigned char** signature, size_t* signature_size) {
|
||||
if (private_key->type == KEYTYPE_RSA) {
|
||||
struct RsaPrivateKey rsa_key;
|
||||
rsa_key.der = (char*)private_key->data;
|
||||
rsa_key.der_length = private_key->data_size;
|
||||
// SHA2-256 signatures are 32 bytes
|
||||
*signature = (unsigned char*)malloc(32);
|
||||
return libp2p_crypto_rsa_sign(&rsa_key, in, in_length, *signature);
|
||||
}
|
||||
// TODO: Implement this method for non-RSA
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will generate the ephimeral key and the shared key and place them in the session struct
|
||||
* @param in the incoming Exchange struct
|
||||
* @param session where to put the generated keys
|
||||
* @returns true(1) on success, otherwise 0
|
||||
*/
|
||||
int libp2p_secio_generate_public_and_shared_key(struct Exchange* in, struct SecureSession* session) {
|
||||
// TODO: Implement this method
|
||||
// pick the right curve method
|
||||
if (strcmp(session->chosen_curve, "P-256") == 0) {
|
||||
|
||||
} else if (strcmp(session->chosen_curve, "P-384") == 0) {
|
||||
|
||||
} else if (strcmp(session->chosen_curve, "P-521") == 0) {
|
||||
|
||||
}
|
||||
// generate priv, x, and y
|
||||
|
||||
// marshal x and y into a public key
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libp2p_secio_stretch_keys(struct SecureSession* local_session, struct SecureSession* remote_session, int order_preference) {
|
||||
// TODO: Implement this method
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libp2p_secio_make_mac_and_cipher(struct SecureSession* session) {
|
||||
// TODO: Implement this method
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size_t length) {
|
||||
// TODO: Implement this method
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libp2p_secio_read(struct SecureSession* session, unsigned char** bytes, size_t* bytes_read) {
|
||||
// TODO: Implement this method
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***
|
||||
* 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 private_key the private key to use
|
||||
* @param private_key our private key to use
|
||||
* @returns true(1) on success, false(0) otherwise
|
||||
*/
|
||||
int libp2p_secio_handshake(struct SecureSession* session, struct RsaPrivateKey* private_key) {
|
||||
int retVal = 0, bytes_written = 0;
|
||||
size_t protobuf_size = 0, results_size = 0;
|
||||
unsigned char* protobuf = 0;
|
||||
int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivateKey* private_key) {
|
||||
int retVal = 0;
|
||||
size_t results_size = 0, bytes_written = 0;
|
||||
unsigned char* propose_in_bytes = NULL; // the remote protobuf
|
||||
size_t propose_in_size = 0;
|
||||
unsigned char* propose_out_bytes = NULL; // the local protobuf
|
||||
size_t propose_out_size = 0;
|
||||
unsigned char* results = NULL;
|
||||
struct Propose* propose_out = NULL;
|
||||
struct Propose* propose_in = NULL;
|
||||
struct PublicKey* public_key = NULL;
|
||||
unsigned char order_hash_in[32];
|
||||
unsigned char order_hash_out[32];
|
||||
int order;
|
||||
struct Exchange* exchange_out;
|
||||
unsigned char* exchange_out_protobuf;
|
||||
size_t exchange_out_protobuf_size;
|
||||
struct Exchange* exchange_in;
|
||||
struct Libp2pVector* char_buffer;
|
||||
|
||||
const unsigned char* protocol = (unsigned char*)"/secio/1.0.0\n";
|
||||
|
||||
bytes_written = libp2p_net_multistream_send(session->socket_descriptor, protocol, strlen((char*)protocol));
|
||||
bytes_written = libp2p_net_multistream_send(local_session->socket_descriptor, protocol, strlen((char*)protocol));
|
||||
if (bytes_written <= 0)
|
||||
goto exit;
|
||||
|
||||
// we should get back the protocol to signify it was accepted, as well as the protobuf of the Propose struct
|
||||
bytes_written = libp2p_net_multistream_receive(session->socket_descriptor, (char**)&results, &results_size);
|
||||
bytes_written = libp2p_net_multistream_receive(local_session->socket_descriptor, (char**)&results, &results_size);
|
||||
if (bytes_written < 1 || strstr((char*)results, "secio") == NULL)
|
||||
goto exit;
|
||||
|
||||
// skip to the protobuf section
|
||||
protobuf = (unsigned char*)strchr((char*)results, '\n');
|
||||
if (protobuf == NULL)
|
||||
propose_in_bytes = (unsigned char*)strchr((char*)results, '\n');
|
||||
if (propose_in_bytes == NULL)
|
||||
goto exit;
|
||||
protobuf++;
|
||||
protobuf_size = results_size - (protobuf - results);
|
||||
propose_in_bytes++;
|
||||
propose_in_size = results_size - (propose_in_bytes - results);
|
||||
|
||||
if (!libp2p_secio_propose_protobuf_decode(protobuf, protobuf_size, &propose_in))
|
||||
if (!libp2p_secio_propose_protobuf_decode(propose_in_bytes, propose_in_size, &propose_in))
|
||||
goto exit;
|
||||
|
||||
// clear results
|
||||
|
@ -96,18 +304,17 @@ int libp2p_secio_handshake(struct SecureSession* session, struct RsaPrivateKey*
|
|||
char* remote_peer_id;
|
||||
libp2p_crypto_public_key_to_peer_id(public_key, &remote_peer_id);
|
||||
|
||||
//TODO: make sure we're not talking to ourself
|
||||
|
||||
// generate 16 byte nonce
|
||||
char nonceOut[16];
|
||||
if (!libp2p_secio_generate_nonce(&nonceOut[0], 16)) {
|
||||
if (!libp2p_secio_generate_nonce(&local_session->nonce[0], 16)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
propose_out = libp2p_secio_propose_new();
|
||||
libp2p_secio_propose_set_property((void**)&propose_out->rand, &propose_out->rand_size, nonceOut, 16);
|
||||
libp2p_secio_propose_set_property((void**)&propose_out->rand, &propose_out->rand_size, local_session->nonce, 16);
|
||||
|
||||
// we have their information, now we need to gather ours.
|
||||
|
||||
// will need:
|
||||
// public key
|
||||
propose_out->public_key_size = public_key->data_size;
|
||||
propose_out->public_key = (unsigned char*)malloc(public_key->data_size);
|
||||
|
@ -117,23 +324,89 @@ int libp2p_secio_handshake(struct SecureSession* session, struct RsaPrivateKey*
|
|||
// supported ciphers
|
||||
libp2p_secio_propose_set_property((void**)&propose_out->ciphers, &propose_out->ciphers_size, SupportedCiphers, strlen(SupportedCiphers));
|
||||
// supported hashes
|
||||
libp2p_secio_propose_set_property((void**)&propose_out->hashes, &propose_out->exchanges_size, SupportedHashes, strlen(SupportedHashes));
|
||||
libp2p_secio_propose_set_property((void**)&propose_out->hashes, &propose_out->hashes_size, SupportedHashes, strlen(SupportedHashes));
|
||||
// negotiate encryption parameters NOTE: SelectBest must match, otherwise this won't work
|
||||
// first determine order
|
||||
libp2p_secio_hash(propose_in, order_hash_in);
|
||||
libp2p_secio_hash(propose_out, order_hash_out);
|
||||
order = libp2p_secio_bytes_compare((char*)order_hash_in, (char*)order_hash_out, 32);
|
||||
// curve
|
||||
libp2p_secio_select_best(order, propose_out->exchanges, propose_out->exchanges_size, propose_in->exchanges, propose_in->exchanges_size, &local_session->chosen_curve);
|
||||
// cipher
|
||||
libp2p_secio_select_best(order, propose_out->ciphers, propose_out->ciphers_size, propose_in->ciphers, propose_in->ciphers_size, &local_session->chosen_cipher);
|
||||
// hash
|
||||
libp2p_secio_select_best(order, propose_out->hashes, propose_out->hashes_size, propose_in->hashes, propose_in->hashes_size, &local_session->chosen_hash);
|
||||
|
||||
// prepare exchange of encryption parameters
|
||||
struct SecureSession remote_session;
|
||||
remote_session.chosen_cipher = local_session->chosen_cipher;
|
||||
remote_session.chosen_curve = local_session->chosen_curve;
|
||||
remote_session.chosen_hash = local_session->chosen_hash;
|
||||
|
||||
// send
|
||||
// generate EphemeralPubKey
|
||||
struct EphemeralPrivateKey e_private_key;
|
||||
libp2p_crypto_ephemeral_key_generate(local_session->chosen_curve, &e_private_key);
|
||||
// build buffer to sign
|
||||
char_buffer = libp2p_utils_vector_new();
|
||||
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);
|
||||
// send Exchange packet
|
||||
exchange_out = libp2p_secio_exchange_new();
|
||||
exchange_out->epubkey = (unsigned char*)malloc(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;
|
||||
struct PrivateKey priv;
|
||||
priv.data = (unsigned char*)private_key->der;
|
||||
priv.data_size = private_key->der_length;
|
||||
libp2p_secio_sign(&priv, char_buffer->buffer, char_buffer->buffer_size, &exchange_out->signature, &exchange_out->signature_size);
|
||||
libp2p_utils_vector_free(char_buffer);
|
||||
|
||||
// receive
|
||||
exchange_out_protobuf_size = libp2p_secio_exchange_protobuf_encode_size(exchange_out);
|
||||
exchange_out_protobuf = (unsigned char*)malloc(exchange_out_protobuf_size);
|
||||
if (exchange_out_protobuf == NULL)
|
||||
goto exit;
|
||||
libp2p_secio_exchange_protobuf_encode(exchange_out, exchange_out_protobuf, exchange_out_protobuf_size, &bytes_written);
|
||||
bytes_written = libp2p_net_multistream_send(local_session->socket_descriptor, exchange_out_protobuf, exchange_out_protobuf_size);
|
||||
free(exchange_out_protobuf);
|
||||
|
||||
// receive Exchange packet
|
||||
bytes_written = libp2p_net_multistream_receive(local_session->socket_descriptor, (char**)&results, &results_size);
|
||||
libp2p_secio_exchange_protobuf_decode(results, results_size, &exchange_in);
|
||||
|
||||
// parse and verify
|
||||
remote_session.ephemeral_public_key = exchange_in->epubkey;
|
||||
remote_session.ephemeral_public_key_size = exchange_in->epubkey_size;
|
||||
|
||||
// generate keys for mac and encryption
|
||||
char_buffer = libp2p_utils_vector_new();
|
||||
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);
|
||||
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);
|
||||
|
||||
// 2.2 generate shared key NOTE: this was done above
|
||||
|
||||
// generate 2 sets of keys (stretching)
|
||||
libp2p_secio_stretch_keys(local_session, &remote_session, order);
|
||||
|
||||
// prepare MAC + cipher
|
||||
|
||||
libp2p_secio_make_mac_and_cipher(local_session);
|
||||
libp2p_secio_make_mac_and_cipher(&remote_session);
|
||||
|
||||
// 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);
|
||||
if (results_size != 16)
|
||||
goto exit;
|
||||
if (libp2p_secio_bytes_compare((char*)results, local_session->nonce, 16) != 0)
|
||||
goto exit;
|
||||
|
||||
retVal = 1;
|
||||
|
||||
|
@ -141,8 +414,6 @@ int libp2p_secio_handshake(struct SecureSession* session, struct RsaPrivateKey*
|
|||
|
||||
libp2p_secio_propose_free(propose_out);
|
||||
libp2p_secio_propose_free(propose_in);
|
||||
if (protobuf != NULL)
|
||||
free(protobuf);
|
||||
|
||||
return retVal;
|
||||
|
||||
|
|
13
test/crypto/test_ephemeral.h
Normal file
13
test/crypto/test_ephemeral.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "libp2p/crypto/ephemeral.h"
|
||||
/**
|
||||
* Try to generate an ephemeral private key
|
||||
*/
|
||||
int test_ephemeral_key_generate() {
|
||||
struct EphemeralPrivateKey private_key;
|
||||
int retVal = libp2p_crypto_ephemeral_key_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;
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
#ifndef test_rsa_h
|
||||
#define test_rsa_h
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -25,11 +24,6 @@ int test_crypto_rsa_private_key_der() {
|
|||
if (private_key.der == NULL)
|
||||
return 0;
|
||||
|
||||
// print out public key
|
||||
//for (int i = 0; i < private_key.public_key_length; i++) {
|
||||
// printf("%02x", private_key.public_key_der[i]);
|
||||
//}
|
||||
//printf("\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -178,5 +172,35 @@ int test_crypto_rsa_public_key_to_peer_id() {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int test_crypto_rsa_signing() {
|
||||
// generate a public and private key pair
|
||||
struct RsaPrivateKey private_key;
|
||||
libp2p_crypto_rsa_generate_keypair(&private_key, 2048);
|
||||
|
||||
#endif /* test_rsa_h */
|
||||
struct RsaPublicKey public_key;
|
||||
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;
|
||||
unsigned char bytes[num_bytes];
|
||||
int val = 0;
|
||||
for (size_t i = 0; i < num_bytes; i++) {
|
||||
if (val > 255)
|
||||
val = 0;
|
||||
bytes[i] = val;
|
||||
val++;
|
||||
}
|
||||
|
||||
char result[256];
|
||||
|
||||
// sign the buffer
|
||||
if (libp2p_crypto_rsa_sign(&private_key, bytes, num_bytes, &result[0]) == 0)
|
||||
return 0;
|
||||
|
||||
// verify the signature
|
||||
if (libp2p_crypto_rsa_verify(&public_key, bytes, num_bytes, &result[0]) == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "crypto/test_base58.h"
|
||||
#include "crypto/test_base32.h"
|
||||
#include "crypto/test_key.h"
|
||||
#include "crypto/test_ephemeral.h"
|
||||
#include "test_secio.h"
|
||||
#include "test_mbedtls.h"
|
||||
#include "test_multistream.h"
|
||||
|
@ -13,6 +14,7 @@ const char* names[] = {
|
|||
"test_mbedtls_varint_128_binary",
|
||||
"test_mbedtls_varint_128_string",
|
||||
"test_crypto_rsa_private_key_der",
|
||||
"test_crypto_rsa_signing",
|
||||
"test_crypto_rsa_public_key_to_peer_id",
|
||||
"test_crypto_x509_der_to_private2",
|
||||
"test_crypto_x509_der_to_private",
|
||||
|
@ -31,7 +33,8 @@ const char* names[] = {
|
|||
"test_protobuf_private_key",
|
||||
"test_secio_handshake",
|
||||
"test_multistream_connect",
|
||||
"test_multistream_get_list"
|
||||
"test_multistream_get_list",
|
||||
"test_ephemeral_key_generate"
|
||||
};
|
||||
|
||||
int (*funcs[])(void) = {
|
||||
|
@ -39,6 +42,7 @@ int (*funcs[])(void) = {
|
|||
test_mbedtls_varint_128_binary,
|
||||
test_mbedtls_varint_128_string,
|
||||
test_crypto_rsa_private_key_der,
|
||||
test_crypto_rsa_signing,
|
||||
test_crypto_rsa_public_key_to_peer_id,
|
||||
test_crypto_x509_der_to_private2,
|
||||
test_crypto_x509_der_to_private,
|
||||
|
@ -57,7 +61,8 @@ int (*funcs[])(void) = {
|
|||
test_protobuf_private_key,
|
||||
test_secio_handshake,
|
||||
test_multistream_connect,
|
||||
test_multistream_get_list
|
||||
test_multistream_get_list,
|
||||
test_ephemeral_key_generate,
|
||||
};
|
||||
|
||||
int testit(const char* name, int (*func)(void)) {
|
||||
|
|
3
thirdparty/Makefile
vendored
3
thirdparty/Makefile
vendored
|
@ -2,4 +2,5 @@ all:
|
|||
cd mbedtls; make all;
|
||||
|
||||
clean:
|
||||
cd mbedtls; make clean;
|
||||
# this is a waste of time. Uncomment if you make changes to mbedtls
|
||||
#cd mbedtls; make clean;
|
18
utils/Makefile
Normal file
18
utils/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
|||
CC = gcc
|
||||
CFLAGS = -O0 -Wall -I../include
|
||||
|
||||
ifdef DEBUG
|
||||
CFLAGS += -g3
|
||||
endif
|
||||
|
||||
LFLAGS =
|
||||
DEPS =
|
||||
OBJS = string_list.o vector.o
|
||||
|
||||
%.o: %.c $(DEPS)
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
all: $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
26
utils/string_list.c
Normal file
26
utils/string_list.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "libp2p/utils/string_list.h"
|
||||
|
||||
struct StringList* libp2p_utils_string_list_new() {
|
||||
struct StringList* list = (struct StringList*)malloc(sizeof(struct StringList));
|
||||
if (list != NULL)
|
||||
{
|
||||
list->next = NULL;
|
||||
list->string = NULL;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
void libp2p_utils_string_list_free(struct StringList* list) {
|
||||
struct StringList* current = list;
|
||||
struct StringList* temp = NULL;
|
||||
|
||||
while(current != NULL) {
|
||||
if (current->string != NULL)
|
||||
free(current->string);
|
||||
temp = current->next;
|
||||
free(current);
|
||||
current = temp;
|
||||
}
|
||||
}
|
44
utils/vector.c
Normal file
44
utils/vector.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libp2p/utils/vector.h"
|
||||
|
||||
/**
|
||||
* Allocate memory for a new Libp2pVector
|
||||
* @returns a new Libp2pVector or NULL if it couldn't do it
|
||||
*/
|
||||
struct Libp2pVector* libp2p_utils_vector_new() {
|
||||
struct Libp2pVector* out = (struct Libp2pVector*)malloc(sizeof(struct Libp2pVector));
|
||||
if (out != NULL) {
|
||||
out->buffer = NULL;
|
||||
out->buffer_size = 0;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void libp2p_utils_vector_free(struct Libp2pVector* vector) {
|
||||
if (vector != NULL) {
|
||||
if (vector->buffer != NULL)
|
||||
free(vector->buffer);
|
||||
vector->buffer_size = 0;
|
||||
free(vector);
|
||||
vector = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add bytes to vector
|
||||
*/
|
||||
int libp2p_utils_vector_add(struct Libp2pVector* vector, unsigned char* in_bytes, size_t in_size) {
|
||||
if (in_size > 0) {
|
||||
if (vector->buffer == NULL) {
|
||||
vector->buffer = (unsigned char*)malloc(in_size);
|
||||
memcpy(vector->buffer, in_bytes, in_size);
|
||||
} else {
|
||||
vector->buffer = (unsigned char*)realloc(vector->buffer, in_size + vector->buffer_size);
|
||||
memcpy(&vector->buffer[vector->buffer_size], in_bytes, in_size);
|
||||
vector->buffer_size += in_size;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
Loading…
Reference in a new issue