secio handshake compiles, now testing

This commit is contained in:
John Jones 2017-02-08 11:08:05 -05:00
parent 030b2b197d
commit e1a29128b6
10 changed files with 281 additions and 37 deletions

View file

@ -7,6 +7,31 @@
#include "mbedtls/ctr_drbg.h"
#include "libp2p/crypto/ephemeral.h"
struct StretchedKey* libp2p_crypto_ephemeral_stretched_key_new() {
struct StretchedKey* key = (struct StretchedKey*)malloc(sizeof(struct StretchedKey));
if (key != NULL) {
key->cipher_key = NULL;
key->cipher_size = 0;
key->iv = NULL;
key->iv_size = 0;
key->mac_key = NULL;
key->mac_size = 0;
}
return key;
}
void libp2p_crypto_ephemeral_stretched_key_free(struct StretchedKey* key) {
if (key != NULL) {
if (key->cipher_key != NULL)
free(key->cipher_key);
if (key->iv != NULL)
free(key->iv);
if (key->mac_key != NULL)
free(key->mac_key);
free(key);
}
}
struct EphemeralPrivateKey* libp2p_crypto_ephemeral_key_new(uint64_t priv, uint64_t x, uint64_t y, size_t num_bits) {
struct EphemeralPrivateKey* results = (struct EphemeralPrivateKey*)malloc(sizeof(struct EphemeralPrivateKey));
if (results != NULL) {
@ -17,9 +42,13 @@ struct EphemeralPrivateKey* libp2p_crypto_ephemeral_key_new(uint64_t priv, uint6
free(results);
results = NULL;
} else {
results->public_key->num_bits = num_bits;
results->public_key->x = x;
results->public_key->y = y;
results->public_key->num_bits = num_bits;
results->public_key->bytes = NULL;
results->public_key->bytes_size = 0;
results->public_key->shared_key = NULL;
results->public_key->shared_key_size = 0;
}
}
return results;
@ -27,8 +56,13 @@ struct EphemeralPrivateKey* libp2p_crypto_ephemeral_key_new(uint64_t priv, uint6
void libp2p_crypto_ephemeral_key_free(struct EphemeralPrivateKey* in) {
if (in != NULL) {
if (in->public_key != NULL)
if (in->public_key != NULL) {
if (in->public_key->bytes != NULL)
free(in->public_key->bytes);
if (in->public_key->shared_key != NULL)
free(in->public_key->shared_key);
free(in->public_key);
}
free(in);
}
}
@ -103,13 +137,16 @@ int libp2p_crypto_ephemeral_point_unmarshal(int bit_size, unsigned char* buffer,
* @param private_key the struct to store the generated key
* @returns true(1) on success, otherwise false(0)
*/
int libp2p_crypto_ephemeral_keypair_generate(char* curve, struct EphemeralPrivateKey** private_key) {
int libp2p_crypto_ephemeral_keypair_generate(char* curve, struct EphemeralPrivateKey** private_key_ptr) {
int retVal = 0;
mbedtls_ecdsa_context ctx;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
struct EphemeralPrivateKey* private_key = NULL;
struct EphemeralPublicKey* public_key = NULL;
int selected_curve = 0;
char* pers = "bitShares"; // data for seeding random number generator
if (strcmp(curve, "P-256") == 0)
selected_curve = MBEDTLS_ECP_DP_SECP256R1;
else if (strcmp(curve, "P-384") == 0)
@ -117,8 +154,6 @@ int libp2p_crypto_ephemeral_keypair_generate(char* curve, struct EphemeralPrivat
else
selected_curve = MBEDTLS_ECP_DP_SECP521R1;
char* pers = "bitShares";
mbedtls_ecdsa_init(&ctx);
// seed random number generator
@ -127,14 +162,39 @@ int libp2p_crypto_ephemeral_keypair_generate(char* curve, struct EphemeralPrivat
if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers)) != 0)
goto exit;
// generate key
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, ctx.grp.nbits);
*private_key_ptr = libp2p_crypto_ephemeral_key_new(*ctx.d.p, *ctx.Q.X.p, *ctx.Q.Y.p, ctx.grp.nbits);
private_key = *private_key_ptr;
public_key = private_key->public_key;
// Fill in more of the public key
libp2p_crypto_ephemeral_point_marshal(public_key->num_bits, public_key->x, public_key->y, &public_key->bytes, &public_key->bytes_size);
// build shared key, another part of public_key
//mbedtls_ecp_group grp;
mbedtls_ecp_point point;
//mbedtls_ecp_group_init(&grp);
mbedtls_ecp_point_init(&point);
if (mbedtls_ecp_mul(&ctx.grp, &point, &ctx.d, &ctx.Q, mbedtls_ctr_drbg_random, &ctr_drbg) != 0)
goto exit;
public_key->shared_key_size = 8;
public_key->shared_key = (unsigned char*)malloc(8);
serialize_uint64(*point.X.p, public_key->shared_key);
// ship all this stuff back to the caller
retVal = 1;
exit:
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
mbedtls_ecdsa_free(&ctx);
return retVal;
}

View file

@ -264,3 +264,19 @@ void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])
SHA1_Transform(context->state, context->buffer);
#endif
}
/***
* Hash the input using SHA1
* @param input the input to hash
* @param input_length the length of the input
* @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) {
SHA1_CTX ctx;
SHA1_Init(&ctx);
SHA1_Update(&ctx, input, input_length);
SHA1_Final(&ctx, output);
return 40;
}

View file

@ -4,10 +4,10 @@
* hash a string using SHA256
* @param input the input string
* @param input_length the length of the input string
* @param output where to place the results
* @param output where to place the results, should be 32 bytes
* @returns 1
*/
int libp2p_crypto_hashing_sha256(const unsigned char* input, size_t input_length, unsigned char output[32]) {
int libp2p_crypto_hashing_sha256(const char* input, size_t input_length, unsigned char* output) {
mbedtls_sha256(input, input_length, output, 0);
return 1;
return 32;
}

View file

@ -7,7 +7,7 @@
* @param output where to place the results
* @returns 1
*/
int libp2p_crypto_hashing_sha512(const unsigned char* input, size_t input_length, unsigned char output[128]) {
int libp2p_crypto_hashing_sha512(const char* input, size_t input_length, unsigned char* output) {
mbedtls_sha512(input, input_length, output, 0);
return 1;
return 64;
}

View file

@ -6,10 +6,23 @@
* General helpers for ephemeral keys
*/
struct StretchedKey {
char* iv;
size_t iv_size;
char* cipher_key;
size_t cipher_size;
char* mac_key;
size_t mac_size;
};
struct EphemeralPublicKey {
size_t num_bits;
uint64_t x;
uint64_t y;
unsigned char* bytes; // a public key in bytes (the combination of X and Y)
size_t bytes_size;
unsigned char* shared_key;
size_t shared_key_size;
};
struct EphemeralPrivateKey {
@ -25,3 +38,9 @@ struct EphemeralPrivateKey {
* @reutrns true(1) on success, otherwise false(0)
*/
int libp2p_crypto_ephemeral_keypair_generate(char* curve, struct EphemeralPrivateKey** private_key);
/**
* Routines to help with the StretchedKey struct
*/
struct StretchedKey* libp2p_crypto_ephemeral_stretched_key_new();
void libp2p_crypto_ephemeral_stretched_key_free(struct StretchedKey* in);

View file

@ -16,4 +16,13 @@ void SHA1_Init(SHA1_CTX* context);
void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len);
void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]);
/***
* Hash the input using SHA1
* @param input the input to hash
* @param input_length the length of the input
* @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);
#endif /* _SHA1_H */

View file

@ -8,6 +8,6 @@
* @param output where to place the results
* @returns 1
*/
int libp2p_crypto_hashing_sha256(const unsigned char* input, size_t input_length, unsigned char output[32]);
int libp2p_crypto_hashing_sha256(const char* input, size_t input_length, unsigned char* output);
#endif

View file

@ -4,8 +4,8 @@
* hash a string using SHA512
* @param input the input string
* @param input_length the length of the input string
* @param output where to place the results
* @returns 1
* @param output where to place the results, should be 64 bytes
* @returns number of bytes written, or 0
*/
int libp2p_crypto_hashing_sha512(const unsigned char* input, size_t input_length, unsigned char output[128]);
int libp2p_crypto_hashing_sha512(const char* input, size_t input_length, unsigned char* output);

View file

@ -27,6 +27,7 @@ struct SecureSession {
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;
};
/***

View file

@ -7,8 +7,10 @@
#include "libp2p/secio/propose.h"
#include "libp2p/secio/exchange.h"
#include "libp2p/net/multistream.h"
#include "libp2p/crypto/sha256.h"
#include "libp2p/crypto/ephemeral.h"
#include "libp2p/crypto/sha1.h"
#include "libp2p/crypto/sha256.h"
#include "libp2p/crypto/sha512.h"
#include "libp2p/utils/string_list.h"
#include "libp2p/utils/vector.h"
@ -58,7 +60,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
unsigned char buffer[in->public_key_size + in->rand_size];
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);
@ -202,30 +204,156 @@ int libp2p_secio_sign(struct PrivateKey* private_key, unsigned char* in, size_t
}
/**
* 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
* Generate 2 keys by stretching the secret key
* @param cipherType the cipher type (i.e. "AES-128")
* @param hashType the hash type (i.e. "SHA256")
* @param secret the secret key
* @param secret_size the length of the secret key
* @param k1 one of the resultant keys
* @param k2 one of the resultant keys
* @returns true(1) on success, otherwise 0 (false)
*/
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) {
int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* secret, size_t secret_size, struct StretchedKey** k1_ptr, struct StretchedKey** k2_ptr) {
int retVal = 0, hash_size = 0, num_filled = 0, num_needed = 0, hmac_size = 20;
struct StretchedKey* k1;
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);
unsigned char* current_hash = NULL;
} else if (strcmp(session->chosen_curve, "P-384") == 0) {
} else if (strcmp(session->chosen_curve, "P-521") == 0) {
k1 = libp2p_crypto_ephemeral_stretched_key_new();
if (k1 == NULL)
goto exit;
k2 = libp2p_crypto_ephemeral_stretched_key_new();
if (k2_ptr == NULL)
goto exit;
// pick the right cipher
if (strcmp(cipherType, "AES-128") == 0) {
k1->iv_size = 16;
k2->iv_size = 16;
k1->cipher_size = 16;
k2->cipher_size = 16;
} else if (strcmp(cipherType, "AES-256") == 0) {
k1->iv_size = 16;
k2->iv_size = 16;
k1->cipher_size = 32;
k2->cipher_size = 32;
} else if (strcmp(cipherType, "Blowfish") == 0) {
k1->iv_size = 8;
k2->iv_size = 8;
k1->cipher_size = 32;
k2->cipher_size = 32;
} else {
goto exit;
}
// generate priv, x, and y
// marshal x and y into a public key
return 0;
// pick the right hash
if (strcmp(hashType, "SHA1") == 0) {
hash_func = libp2p_crypto_hashing_sha1;
hash_size = 40;
} else if (strcmp(hashType, "SHA256") == 0) {
hash_func = libp2p_crypto_hashing_sha256;
hash_size = 32;
} else if (strcmp(hashType, "SHA512") == 0) {
hash_func = libp2p_crypto_hashing_sha512;
hash_size = 64;
} else {
goto exit;
}
int libp2p_secio_stretch_keys(struct SecureSession* local_session, struct SecureSession* remote_session, int order_preference) {
// TODO: Implement this method
return 0;
result_size = 2 * (k1->iv_size + k1->cipher_size * hmac_size);
result = malloc(result_size);
if (result == NULL)
goto exit;
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));
current_hash = malloc(hash_size);
hash_func(second_seed, seed_size, current_hash);
num_needed = hash_size;
// now we have our first hash. Begin to fill the result buffer
while (num_filled < result_size) {
num_needed = result_size - num_filled;
if (num_needed > hash_size)
num_needed = hash_size;
// combine current_hash with first_seed
if (temp != NULL)
free(temp);
seed_size = secret_size + strlen(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));
// make a new hash
hash_func(temp, seed_size, current_hash);
// copy the hash to results
memcpy(&result[num_filled], current_hash, num_needed);
num_filled += num_needed;
// redo the hashes by adding the secret to the current hash
free(temp);
seed_size = secret_size + hash_size;
temp = malloc(seed_size);
memcpy(temp, secret, secret_size);
memcpy(&temp[secret_size], current_hash, hash_size);
hash_func(temp, seed_size, current_hash);
}
// now we have a big result. Cut it up into pieces
if (temp != NULL)
free(temp);
temp = (char*)result;
k1->iv = malloc(k1->iv_size);
memcpy(k1->iv, temp, k1->iv_size);
temp += k1->iv_size;
k1->cipher_key = malloc(k1->cipher_size);
memcpy(k1->cipher_key, temp, k1->cipher_size);
temp += k1->cipher_size;
k1->mac_key = malloc(k1->mac_size);
memcpy(k1->mac_key, temp, k1->mac_size);
temp += k1->mac_size;
k2->iv = malloc(k2->iv_size);
memcpy(k2->iv, temp, k2->iv_size);
temp += k2->iv_size;
k2->cipher_key = malloc(k2->cipher_size);
memcpy(k2->cipher_key, temp, k2->cipher_size);
temp += k2->cipher_size;
k2->mac_key = malloc(k2->mac_size);
memcpy(k2->mac_key, temp, k2->mac_size);
temp += k2->mac_size;
retVal = 1;
// cleanup
exit:
*k1_ptr = k1;
*k2_ptr = k2;
if (retVal != 1) {
if (*k1_ptr != NULL)
libp2p_crypto_ephemeral_stretched_key_free(*k1_ptr);
if (*k2_ptr != NULL)
libp2p_crypto_ephemeral_stretched_key_free(*k2_ptr);
*k1_ptr = NULL;
*k2_ptr = NULL;
}
if (current_hash != NULL)
free(current_hash);
if (temp != NULL)
free(temp);
if (second_seed != NULL)
free(second_seed);
if (result != NULL)
free(result);
return retVal;
}
int libp2p_secio_make_mac_and_cipher(struct SecureSession* session) {
@ -270,6 +398,7 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
size_t exchange_out_protobuf_size;
struct Exchange* exchange_in;
struct Libp2pVector* char_buffer;
struct StretchedKey* k1 = NULL, *k2 = NULL;
const unsigned char* protocol = (unsigned char*)"/secio/1.0.0\n";
@ -346,6 +475,7 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
// generate EphemeralPubKey
struct EphemeralPrivateKey* e_private_key;
libp2p_crypto_ephemeral_keypair_generate(local_session->chosen_curve, &e_private_key);
// build buffer to sign
char_buffer = libp2p_utils_vector_new();
if (char_buffer == NULL)
@ -353,6 +483,7 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
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);
@ -393,8 +524,15 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
// 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);
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;
} else {
local_session->stretched_key = k2;
remote_session.stretched_key = k1;
}
// prepare MAC + cipher
libp2p_secio_make_mac_and_cipher(local_session);
@ -403,6 +541,7 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
// 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)