int main(void) {
	sodium_init();

	//create random chain key
	unsigned char chain_key[crypto_auth_BYTES];
	randombytes_buf(chain_key, crypto_auth_BYTES);

	//print first chain key
	printf("Chain key (%i Bytes):\n", crypto_auth_BYTES);
	print_hex(chain_key, crypto_auth_BYTES, 30);
	putchar('\n');

	int status;


	//derive message key from chain key
	unsigned char message_key[crypto_auth_BYTES];
	status = derive_message_key(message_key, chain_key);
	sodium_memzero(chain_key, crypto_auth_BYTES);
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to derive message key. (%i)\n", status);
		sodium_memzero(message_key, crypto_auth_BYTES);
		return status;
	}

	//print message key
	printf("Message key (%i Bytes):\n", crypto_auth_BYTES);
	print_hex(message_key, crypto_auth_BYTES, 30);
	putchar('\n');

	sodium_memzero(message_key, crypto_auth_BYTES);
	return EXIT_SUCCESS;
}
int main(void) {
	sodium_init();

	int status;
	//create random chain key
	buffer_t *chain_key = buffer_create(crypto_auth_BYTES, crypto_auth_BYTES);
	status = buffer_fill_random(chain_key, chain_key->buffer_length);
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to create chain key. (%i)\n", status);
		buffer_clear(chain_key);
		return status;
	}

	//print first chain key
	printf("Chain key (%zi Bytes):\n", chain_key->content_length);
	print_hex(chain_key);
	putchar('\n');

	//derive message key from chain key
	buffer_t *message_key = buffer_create(crypto_auth_BYTES, crypto_auth_BYTES);
	status = derive_message_key(message_key, chain_key);
	buffer_clear(chain_key);
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to derive message key. (%i)\n", status);
		buffer_clear(message_key);
		return status;
	}

	//print message key
	printf("Message key (%zi Bytes):\n", message_key->content_length);
	print_hex(message_key);
	putchar('\n');

	buffer_clear(message_key);
	return EXIT_SUCCESS;
}
Exemple #3
0
/*
 * This corresponds to "stage_skipped_header_and_message_keys" from the
 * axolotl protocol description.
 *
 * Calculate all the message keys up the the purported message number
 * and save them in the current ratchet state's staging area.
 *
 * TODO: This could easily be used to make clients hang. Because there are
 * currently no header keys in use, an attacker could specify an arbitrarily
 * high purported message number, thereby making this function calculate
 * all of them -> program hangs. Current workaround: Limiting number
 * of message keys that get precalculated.
 */
int stage_skipped_header_and_message_keys(
		unsigned char * const purported_chain_key, //CKp
		unsigned char * const message_key, //MK
		const unsigned int purported_message_number,
		const unsigned char * const receive_chain_key,
		ratchet_state *state) {

	//if chain key is <none>, don't do anything
	if (is_none(receive_chain_key, crypto_secretbox_KEYBYTES)) {
		sodium_memzero(message_key, crypto_secretbox_KEYBYTES);
		sodium_memzero(purported_chain_key, crypto_secretbox_KEYBYTES);
		return 0;
	}

	//limit number of message keys to calculate
	static const unsigned int LIMIT = 100;
	if ((purported_message_number - state->receive_message_number) > LIMIT) {
		return -10;
	}

	//copy current chain key to purported chain key
	unsigned char purported_current_chain_key[crypto_secretbox_KEYBYTES];
	unsigned char purported_next_chain_key[crypto_secretbox_KEYBYTES];
	memcpy(purported_current_chain_key, receive_chain_key, sizeof(purported_current_chain_key));

	//message key buffer
	unsigned char message_key_buffer[crypto_secretbox_KEYBYTES];

	//create all message keys
	int status;
	unsigned int pos;
	for (pos = state->receive_message_number; pos <= purported_message_number; pos++) {
		status = derive_message_key(message_key_buffer, purported_current_chain_key);
		if (status != 0) {
			sodium_memzero(purported_current_chain_key, sizeof(purported_current_chain_key));
			sodium_memzero(purported_next_chain_key, sizeof(purported_next_chain_key));
			sodium_memzero(message_key_buffer, sizeof(message_key_buffer));
			return status;
		}

		//add message key to list of purported message keys
		if (pos < purported_message_number) { //only stage previous message keys
			status = header_and_message_keystore_add(
					&(state->purported_header_and_message_keys),
					message_key_buffer,
					state->receive_header_key);
			if (status != 0) {
				sodium_memzero(purported_current_chain_key, sizeof(purported_current_chain_key));
				sodium_memzero(purported_next_chain_key, sizeof(purported_next_chain_key));
				return status;
			}
		} else { //current message key is not staged, but copied to return it's value
			memcpy(message_key, message_key_buffer, sizeof(message_key_buffer));
		}
		sodium_memzero(message_key_buffer, sizeof(message_key_buffer));

		status = derive_chain_key(purported_next_chain_key, purported_current_chain_key);
		if (status != 0) {
			sodium_memzero(purported_current_chain_key, sizeof(purported_current_chain_key));
			sodium_memzero(purported_next_chain_key, sizeof(purported_next_chain_key));
			return status;
		}

		//shift chain keys
		memcpy(purported_current_chain_key, purported_next_chain_key, sizeof(purported_current_chain_key));
	}

	//copy chain key to purported_receive_chain_key (this will be used in commit_skipped_header_and_message_keys)
	memcpy(purported_chain_key, purported_next_chain_key, sizeof(purported_next_chain_key));

	sodium_memzero(purported_current_chain_key, sizeof(purported_current_chain_key));
	sodium_memzero(purported_next_chain_key, sizeof(purported_next_chain_key));

	return 0;
}
Exemple #4
0
/*
 * Create message and header keys to encrypt the next sent message with.
 */
int ratchet_next_send_keys(
		unsigned char * const next_message_key,
		unsigned char * const next_header_key,
		ratchet_state *state) {
	int status;
	if (state->ratchet_flag) {
		//generate new ephemeral key
		status = crypto_box_keypair(state->our_public_ephemeral, state->our_private_ephemeral);
		if (status != 0) {
			return status;
		}

		//HKs = NHKs (shift header keys)
		memcpy(state->send_header_key, state->next_send_header_key, sizeof(state->send_header_key));

		//derive next root key and send chain key
		//RK, CKs, NHKs = HKDF(DH(DHs, DHr))
		unsigned char previous_root_key[crypto_secretbox_KEYBYTES];
		memcpy(previous_root_key, state->root_key, sizeof(previous_root_key));
		status = derive_root_chain_and_header_keys(
				state->root_key,
				state->send_chain_key,
				state->next_send_header_key,
				state->our_private_ephemeral,
				state->our_public_ephemeral,
				state->their_public_ephemeral,
				previous_root_key,
				state->am_i_alice);
		sodium_memzero(previous_root_key, sizeof(previous_root_key));
		if (status != 0) {
			return status;
		}

		state->previous_message_number = state->send_message_number;
		state->send_message_number = 0;
		state->ratchet_flag = false;
	}

	//MK = HMAC-HASH(CKs, 0x00)
	status = derive_message_key(
			next_message_key,
			state->send_chain_key);
	if (status != 0) {
		return status;
	}

	//copy the header key
	memcpy(next_header_key, state->send_header_key, sizeof(state->send_header_key));

	state->send_message_number++;

	//derive next chain key
	//CKs = HMAC-HASH(CKs, 0x01)
	unsigned char old_chain_key[crypto_secretbox_KEYBYTES];
	memcpy(old_chain_key, state->send_chain_key, sizeof(old_chain_key));
	status = derive_chain_key(
			state->send_chain_key,
			old_chain_key);
	sodium_memzero(old_chain_key, sizeof(old_chain_key));

	return status;
}