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; }
/* * 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; }
/* * 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; }