/** * \brief Mixes new input data into the chaining key. * * \param state The SymmetricState object. * \param input Points to the input data to mix in. * \param size The size of the \a input data in bytes. * * \return NOISE_ERROR_NONE on success. * \return NOISE_ERROR_INVALID_PARAM if \a state or \a input is NULL. * \return NOISE_ERROR_INVALID_STATE if the \a state has already been split. * * \sa noise_symmetricstate_mix_hash(), noise_symmetricstate_split() */ int noise_symmetricstate_mix_key (NoiseSymmetricState *state, const uint8_t *input, size_t size) { uint8_t temp_k[NOISE_MAX_HASHLEN]; size_t hash_len; size_t key_len; /* Validate the parameters */ if (!state || !input) return NOISE_ERROR_INVALID_PARAM; /* If the state has been split, then we cannot do this */ if (!state->cipher) return NOISE_ERROR_INVALID_STATE; /* Mix the input data in using HKDF */ hash_len = noise_hashstate_get_hash_length(state->hash); key_len = noise_cipherstate_get_key_length(state->cipher); noise_hashstate_hkdf (state->hash, state->ck, hash_len, input, size, state->ck, hash_len, temp_k, key_len); /* Change the cipher key, or set it for the first time */ noise_cipherstate_init_key(state->cipher, temp_k, key_len); noise_clean(temp_k, sizeof(temp_k)); return NOISE_ERROR_NONE; }
/* Measure the performance of an AEAD primitive */ static void perf_cipher(int id) { static uint8_t const key[32] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20 }; static uint8_t const ad[32] = { 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40 }; NoiseCipherState *cipher; uint8_t data[BLOCK_SIZE + 16]; timestamp_t start, end; int count; double elapsed; NoiseBuffer mbuf; if (noise_cipherstate_new_by_id(&cipher, id) != NOISE_ERROR_NONE) return; memset(data, 0xAA, sizeof(data)); noise_cipherstate_init_key(cipher, key, sizeof(key)); start = current_timestamp(); for (count = 0; count < (MB_COUNT * BLOCKS_PER_MB); ++count) { noise_buffer_set_inout(mbuf, data, sizeof(data) - 16, sizeof(data)); noise_cipherstate_encrypt_with_ad(cipher, ad, sizeof(ad), &mbuf); } end = current_timestamp(); elapsed = elapsed_to_seconds(start, end) / (double)MB_COUNT; printf("%-20s%8.2f %8.2f\n", noise_id_to_name(NOISE_CIPHER_CATEGORY, id), 1.0 / elapsed, units / elapsed); noise_cipherstate_free(cipher); }
/** * \brief Splits the transport encryption CipherState objects out of * this SymmetricState object. * * \param state The SymmetricState object. * \param c1 Points to the variable where to place the pointer to the * first CipherState object. This can be NULL if the application is * using a one-way handshake pattern. * \param c2 Points to the variable where to place the pointer to the * second CipherState object. This can be NULL if the application is * using a one-way handshake pattern. * \param secondary_key Points to an optional "secondary symmetric key" * from a parallel non-DH handshake to mix into the final cipher keys. * This may be NULL if \a secondary_key_len is zero. * \param secondary_key_len Length of \a secondary_key in bytes. * This must be either zero or 32 to comply with the requirements from * the Noise protocol specification. * * \return NOISE_ERROR_NONE on success. * \return NOISE_ERROR_INVALID_PARAM if \a state is NULL. * \return NOISE_ERROR_INVALID_PARAM if both \a c1 and \a c2 are NULL. * \return NOISE_ERROR_INVALID_PARAM if \a secondary_key is NULL and * \a secondary_key_len is not zero. * \return NOISE_ERROR_INVALID_LENGTH if \a secondary_key_len is not zero or 32. * \return NOISE_ERROR_INVALID_STATE if the \a state has already been split. * \return NOISE_ERROR_NO_MEMORY if there is insufficient memory to create * the new CipherState objects. * * Once a SymmetricState has been split, it is effectively finished and * cannot be used for future encryption or hashing operations. * If those operations are invoked, the relevant functions will return * NOISE_ERROR_INVALID_STATE. * * The \a c1 object should be used to protect messages from the initiator to * the responder, and the \a c2 object should be used to protect messages * from the responder to the initiator. * * If the handshake pattern is one-way, then the application should call * noise_cipherstate_free() on the object that is not needed. Alternatively, * the application can pass NULL to noise_symmetricstate_split() as the * \a c1 or \a c2 argument and the second CipherState will not be created * at all. */ int noise_symmetricstate_split (NoiseSymmetricState *state, NoiseCipherState **c1, NoiseCipherState **c2, const uint8_t *secondary_key, size_t secondary_key_len) { uint8_t temp_k1[NOISE_MAX_HASHLEN]; uint8_t temp_k2[NOISE_MAX_HASHLEN]; size_t hash_len; size_t key_len; /* Validate the parameters */ if (!state) return NOISE_ERROR_INVALID_PARAM; if (!c1 && !c2) return NOISE_ERROR_INVALID_PARAM; if (!secondary_key && secondary_key_len) return NOISE_ERROR_INVALID_PARAM; if (secondary_key_len != 0 && secondary_key_len != 32) return NOISE_ERROR_INVALID_LENGTH; if (c1) *c1 = 0; if (c2) *c2 = 0; /* If the state has already been split, then we cannot split again */ if (!state->cipher) return NOISE_ERROR_INVALID_STATE; /* Generate the two encryption keys with HKDF */ hash_len = noise_hashstate_get_hash_length(state->hash); key_len = noise_cipherstate_get_key_length(state->cipher); if (!secondary_key) { noise_hashstate_hkdf (state->hash, state->ck, hash_len, state->ck, 0, temp_k1, key_len, temp_k2, key_len); } else { noise_hashstate_hkdf (state->hash, state->ck, hash_len, secondary_key, secondary_key_len, temp_k1, key_len, temp_k2, key_len); } /* If we only need c2, then re-initialize the key in the internal cipher and copy it to c2 */ if (!c1 && c2) { noise_cipherstate_init_key(state->cipher, temp_k2, key_len); *c2 = state->cipher; state->cipher = 0; noise_clean(temp_k1, sizeof(temp_k1)); noise_clean(temp_k2, sizeof(temp_k2)); return NOISE_ERROR_NONE; } /* Split a copy out of the cipher and give it the second key. We don't need to do this if the second CipherSuite is not required */ if (c2) { *c2 = (*(state->cipher->create))(); if (!(*c2)) { noise_clean(temp_k1, sizeof(temp_k1)); noise_clean(temp_k2, sizeof(temp_k2)); return NOISE_ERROR_NO_MEMORY; } noise_cipherstate_init_key(*c2, temp_k2, key_len); } /* Re-initialize the key in the internal cipher and copy it to c1 */ noise_cipherstate_init_key(state->cipher, temp_k1, key_len); *c1 = state->cipher; state->cipher = 0; noise_clean(temp_k1, sizeof(temp_k1)); noise_clean(temp_k2, sizeof(temp_k2)); return NOISE_ERROR_NONE; }