int main(void) { if (sodium_init() == -1) { return -1; } return_status status = return_status_init(); //create buffers //alice keys buffer_t * const alice_public_identity = buffer_create_on_heap(crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES); buffer_t * const alice_private_identity = buffer_create_on_heap(crypto_box_SECRETKEYBYTES, crypto_box_SECRETKEYBYTES); buffer_t * const alice_public_ephemeral = buffer_create_on_heap(crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES); buffer_t * const alice_private_ephemeral = buffer_create_on_heap(crypto_box_SECRETKEYBYTES, crypto_box_SECRETKEYBYTES); buffer_t * const alice_shared_secret = buffer_create_on_heap(crypto_generichash_BYTES, crypto_generichash_BYTES); //bobs keys buffer_t * const bob_public_identity = buffer_create_on_heap(crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES); buffer_t * const bob_private_identity = buffer_create_on_heap(crypto_box_SECRETKEYBYTES, crypto_box_SECRETKEYBYTES); buffer_t * const bob_public_ephemeral = buffer_create_on_heap(crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES); buffer_t * const bob_private_ephemeral = buffer_create_on_heap(crypto_box_SECRETKEYBYTES, crypto_box_SECRETKEYBYTES); buffer_t * const bob_shared_secret = buffer_create_on_heap(crypto_generichash_BYTES, crypto_generichash_BYTES); printf("Generate Alice's keys -------------------------------------------------------\n\n"); int status_int = 0; //create Alice's identity keypair buffer_create_from_string(alice_string, "Alice"); buffer_create_from_string(identity_string, "identity"); status = generate_and_print_keypair( alice_public_identity, alice_private_identity, alice_string, identity_string); throw_on_error(KEYGENERATION_FAILED, "Failed to generate and print Alice' identity keypair."); //create Alice's ephemeral keypair buffer_create_from_string(ephemeral_string, "ephemeral"); status = generate_and_print_keypair( alice_public_ephemeral, alice_private_ephemeral, alice_string, ephemeral_string); throw_on_error(KEYGENERATION_FAILED, "Failed to generate and print Alice' ephemeral keypair."); printf("Generate Bob's keys ---------------------------------------------------------\n\n"); //create Bob's identity keypair buffer_create_from_string(bob_string, "Bob"); status = generate_and_print_keypair( bob_public_identity, bob_private_identity, bob_string, identity_string); throw_on_error(KEYGENERATION_FAILED, "Failed to generate and print Bob's identity keypair."); //create Bob's ephemeral keypair status = generate_and_print_keypair( bob_public_ephemeral, bob_private_ephemeral, bob_string, ephemeral_string); throw_on_error(KEYGENERATION_FAILED, "Failed to generate and print Bob's ephemeral keypair."); printf("Calculate shared secret via Triple Diffie Hellman ---------------------------\n\n"); //Triple Diffie Hellman on Alice's side status = triple_diffie_hellman( alice_shared_secret, alice_private_identity, alice_public_identity, alice_private_ephemeral, alice_public_ephemeral, bob_public_identity, bob_public_ephemeral, true); buffer_clear(alice_private_identity); buffer_clear(alice_private_ephemeral); throw_on_error(KEYGENERATION_FAILED, "Triple Diffie Hellman for Alice failed."); //print Alice's shared secret printf("Alice's shared secret H(DH(A_priv,B0_pub)||DH(A0_priv,B_pub)||DH(A0_priv,B0_pub)):\n"); print_hex(alice_shared_secret); putchar('\n'); //Triple Diffie Hellman on Bob's side status = triple_diffie_hellman( bob_shared_secret, bob_private_identity, bob_public_identity, bob_private_ephemeral, bob_public_ephemeral, alice_public_identity, alice_public_ephemeral, false); buffer_clear(bob_private_identity); buffer_clear(bob_private_ephemeral); throw_on_error(KEYGENERATION_FAILED, "Triple Diffie Hellnan for Bob failed."); //print Bob's shared secret printf("Bob's shared secret H(DH(B0_priv, A_pub)||DH(B_priv, A0_pub)||DH(B0_priv, A0_pub)):\n"); print_hex(bob_shared_secret); putchar('\n'); //compare both shared secrets status_int = buffer_compare(alice_shared_secret, bob_shared_secret); buffer_clear(alice_shared_secret); buffer_clear(bob_shared_secret); if (status_int != 0) { throw(INCORRECT_DATA, "Triple Diffie Hellman didn't produce the same shared secret."); } printf("Both shared secrets match!\n"); cleanup: //alice keys buffer_destroy_from_heap(alice_public_identity); buffer_destroy_from_heap(alice_private_identity); buffer_destroy_from_heap(alice_public_ephemeral); buffer_destroy_from_heap(alice_private_ephemeral); buffer_destroy_from_heap(alice_shared_secret); //bobs keys buffer_destroy_from_heap(bob_public_identity); buffer_destroy_from_heap(bob_private_identity); buffer_destroy_from_heap(bob_public_ephemeral); buffer_destroy_from_heap(bob_private_ephemeral); buffer_destroy_from_heap(bob_shared_secret); on_error { print_errors(&status); } return_status_destroy_errors(&status); return status.status; }
/* * Derive initial root, chain and header keys. * * RK, CKs/r, HKs/r, NHKs/r = HKDF(HASH(DH(A,B0) || DH(A0,B) || DH(A0,B0))) */ int derive_initial_root_chain_and_header_keys( buffer_t * const root_key, //crypto_secretbox_KEYBYTES buffer_t * const send_chain_key, //crypto_secretbox_KEYBYTES buffer_t * const receive_chain_key, //crypto_secretbox_KEYBYTES buffer_t * const send_header_key, //crypto_aead_chacha20poly1305_KEYBYTES buffer_t * const receive_header_key, //crypto_aead_chacha20poly1305_KEYBYTES buffer_t * const next_send_header_key, //crypto_aead_chacha20poly1305_KEYBYTES buffer_t * const next_receive_header_key, //crypto_aead_chacha20poly1305_KEYBYTES const buffer_t * const our_private_identity, const buffer_t * const our_public_identity, const buffer_t * const their_public_identity, const buffer_t * const our_private_ephemeral, const buffer_t * const our_public_ephemeral, const buffer_t * const their_public_ephemeral, bool am_i_alice) { //check buffer sizes if ((root_key->buffer_length < crypto_secretbox_KEYBYTES) || (send_chain_key->buffer_length < crypto_secretbox_KEYBYTES) || (receive_chain_key->buffer_length < crypto_secretbox_KEYBYTES) || (send_header_key->buffer_length < crypto_aead_chacha20poly1305_KEYBYTES) || (receive_header_key->buffer_length < crypto_aead_chacha20poly1305_KEYBYTES) || (next_send_header_key->buffer_length < crypto_aead_chacha20poly1305_KEYBYTES) || (next_receive_header_key->buffer_length < crypto_aead_chacha20poly1305_KEYBYTES) || (our_private_identity->content_length != crypto_box_SECRETKEYBYTES) || (our_public_identity->content_length != crypto_box_PUBLICKEYBYTES) || (their_public_identity->content_length != crypto_box_PUBLICKEYBYTES) || (our_private_ephemeral->content_length != crypto_box_SECRETKEYBYTES) || (our_public_ephemeral->content_length != crypto_box_PUBLICKEYBYTES) || (their_public_ephemeral->content_length != crypto_box_PUBLICKEYBYTES)) { return -6; } int status; //derive pre_root_key to later derive the initial root key, //header keys and chain keys from //pre_root_key = HASH( DH(A,B0) || DH(A0,B) || DH(A0,B0) ) assert(crypto_secretbox_KEYBYTES == crypto_auth_BYTES); buffer_t *pre_root_key = buffer_create(crypto_secretbox_KEYBYTES, crypto_secretbox_KEYBYTES); status = triple_diffie_hellman( pre_root_key, our_private_identity, our_public_identity, our_private_ephemeral, our_public_ephemeral, their_public_identity, their_public_ephemeral, am_i_alice); if (status != 0) { buffer_clear(pre_root_key); return status; } //derive chain, root and header keys from pre_root_key via HKDF //RK, CK, HK, NHK1, NHK2 = HKDF(salt, pre_root_key) buffer_t *hkdf_buffer = buffer_create(2 * crypto_secretbox_KEYBYTES + 3 * crypto_aead_chacha20poly1305_KEYBYTES, 2 * crypto_secretbox_KEYBYTES + 3 * crypto_aead_chacha20poly1305_KEYBYTES); buffer_t *salt = buffer_create_from_string("molch--libsodium-crypto-library"); assert(salt->content_length == crypto_auth_KEYBYTES); buffer_t *info = buffer_create_from_string(INFO); status = hkdf( hkdf_buffer, hkdf_buffer->content_length, salt, pre_root_key, info); buffer_clear(pre_root_key); if (status != 0) { buffer_clear(hkdf_buffer); return status; } //now copy the keys //root key: status = buffer_copy(root_key, 0, hkdf_buffer, 0, crypto_secretbox_KEYBYTES); if (status != 0) { buffer_clear(hkdf_buffer); buffer_clear(root_key); return status; } //chain keys and header keys if (am_i_alice) { //Alice: CKs=<none>, CKr=HKDF //TODO <none> will be an empty buffer in the future send_chain_key->content_length = crypto_secretbox_KEYBYTES; memset(send_chain_key->content, 0, send_chain_key->content_length); status = buffer_copy(receive_chain_key, 0, hkdf_buffer, crypto_secretbox_KEYBYTES, crypto_secretbox_KEYBYTES); if (status != 0) { buffer_clear(hkdf_buffer); buffer_clear(root_key); buffer_clear(receive_chain_key); return status; } //HKs=<none>, HKr=HKDF //TODO <none> will be an empty buffer in the future send_header_key->content_length = crypto_aead_chacha20poly1305_KEYBYTES; memset(send_header_key->content, 0, send_header_key->content_length); status = buffer_copy(receive_header_key, 0, hkdf_buffer, 2 * crypto_secretbox_KEYBYTES, crypto_aead_chacha20poly1305_KEYBYTES); if (status != 0) { buffer_clear(hkdf_buffer); buffer_clear(root_key); buffer_clear(receive_chain_key); buffer_clear(receive_header_key); return status; } //NHKs, NHKr status = buffer_copy(next_send_header_key, 0, hkdf_buffer, 2 * crypto_secretbox_KEYBYTES + crypto_aead_chacha20poly1305_KEYBYTES, crypto_aead_chacha20poly1305_KEYBYTES); if (status != 0) { buffer_clear(hkdf_buffer); buffer_clear(root_key); buffer_clear(receive_chain_key); buffer_clear(receive_header_key); buffer_clear(next_send_header_key); return status; } status = buffer_copy(next_receive_header_key, 0, hkdf_buffer, 2 * crypto_secretbox_KEYBYTES + 2 * crypto_aead_chacha20poly1305_KEYBYTES, crypto_aead_chacha20poly1305_KEYBYTES); if (status != 0) { buffer_clear(hkdf_buffer); buffer_clear(root_key); buffer_clear(receive_chain_key); buffer_clear(receive_header_key); buffer_clear(next_send_header_key); buffer_clear(next_receive_header_key); return status; } } else { //Bob: CKs=HKDF, CKr=<none> receive_chain_key->content_length = crypto_secretbox_KEYBYTES; memset(receive_chain_key->content, 0, receive_chain_key->content_length); status = buffer_copy(send_chain_key, 0, hkdf_buffer, crypto_secretbox_KEYBYTES, crypto_secretbox_KEYBYTES); if (status != 0) { buffer_clear(hkdf_buffer); buffer_clear(root_key); buffer_clear(send_chain_key); return status; } //HKs=HKDF, HKr=<none> receive_header_key->content_length = crypto_aead_chacha20poly1305_KEYBYTES; memset(receive_header_key->content, 0, receive_header_key->content_length); status = buffer_copy(send_header_key, 0, hkdf_buffer, 2 * crypto_secretbox_KEYBYTES, crypto_aead_chacha20poly1305_KEYBYTES); if (status != 0) { buffer_clear(hkdf_buffer); buffer_clear(root_key); buffer_clear(send_chain_key); buffer_clear(send_header_key); return status; } //NHKr, NHKs status = buffer_copy(next_receive_header_key, 0, hkdf_buffer, 2 * crypto_secretbox_KEYBYTES + crypto_aead_chacha20poly1305_KEYBYTES, crypto_aead_chacha20poly1305_KEYBYTES); if (status != 0) { buffer_clear(hkdf_buffer); buffer_clear(root_key); buffer_clear(send_chain_key); buffer_clear(send_header_key); buffer_clear(next_receive_header_key); return status; } status = buffer_copy(next_send_header_key, 0, hkdf_buffer, 2 * crypto_secretbox_KEYBYTES + 2 * crypto_aead_chacha20poly1305_KEYBYTES, crypto_aead_chacha20poly1305_KEYBYTES); if (status != 0) { buffer_clear(hkdf_buffer); buffer_clear(root_key); buffer_clear(send_chain_key); buffer_clear(send_header_key); buffer_clear(next_receive_header_key); buffer_clear(next_send_header_key); return status; } } buffer_clear(hkdf_buffer); return 0; }