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;
}
Example #2
0
/*
 * 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;
}