diff options
Diffstat (limited to 'src/ratchet.cpp')
-rw-r--r-- | src/ratchet.cpp | 139 |
1 files changed, 86 insertions, 53 deletions
diff --git a/src/ratchet.cpp b/src/ratchet.cpp index 5ef1e56..279c4c0 100644 --- a/src/ratchet.cpp +++ b/src/ratchet.cpp @@ -1,4 +1,4 @@ -/* Copyright 2015 OpenMarket Ltd +/* Copyright 2015, 2016 OpenMarket Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,10 +15,9 @@ #include "olm/ratchet.hh" #include "olm/message.hh" #include "olm/memory.hh" -#include "olm/cipher.hh" +#include "olm/cipher.h" #include "olm/pickle.hh" - #include <cstring> namespace { @@ -28,18 +27,30 @@ static const std::uint8_t MESSAGE_KEY_SEED[1] = {0x01}; static const std::uint8_t CHAIN_KEY_SEED[1] = {0x02}; static const std::size_t MAX_MESSAGE_GAP = 2000; + +/** + * Advance the root key, creating a new message chain. + * + * @param root_key previous root key R(n-1) + * @param our_key our new ratchet key T(n) + * @param their_key their most recent ratchet key T(n-1) + * @param info table of constants for the ratchet function + * @param new_root_key[out] returns the new root key R(n) + * @param new_chain_key[out] returns the first chain key in the new chain + * C(n,0) + */ static void create_chain_key( olm::SharedKey const & root_key, - olm::Curve25519KeyPair const & our_key, - olm::Curve25519PublicKey const & their_key, + _olm_curve25519_key_pair const & our_key, + _olm_curve25519_public_key const & their_key, olm::KdfInfo const & info, olm::SharedKey & new_root_key, olm::ChainKey & new_chain_key ) { olm::SharedKey secret; - olm::curve25519_shared_secret(our_key, their_key, secret); - std::uint8_t derived_secrets[2 * olm::KEY_LENGTH]; - olm::hkdf_sha256( + _olm_crypto_curve25519_shared_secret(&our_key, &their_key, secret); + std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH]; + _olm_crypto_hkdf_sha256( secret, sizeof(secret), root_key, sizeof(root_key), info.ratchet_info, info.ratchet_info_length, @@ -58,7 +69,7 @@ static void advance_chain_key( olm::ChainKey const & chain_key, olm::ChainKey & new_chain_key ) { - olm::hmac_sha256( + _olm_crypto_hmac_sha256( chain_key.key, sizeof(chain_key.key), CHAIN_KEY_SEED, sizeof(CHAIN_KEY_SEED), new_chain_key.key @@ -70,9 +81,8 @@ static void advance_chain_key( static void create_message_keys( olm::ChainKey const & chain_key, olm::KdfInfo const & info, - olm::MessageKey & message_key -) { - olm::hmac_sha256( + olm::MessageKey & message_key) { + _olm_crypto_hmac_sha256( chain_key.key, sizeof(chain_key.key), MESSAGE_KEY_SEED, sizeof(MESSAGE_KEY_SEED), message_key.key @@ -82,12 +92,13 @@ static void create_message_keys( static std::size_t verify_mac_and_decrypt( - olm::Cipher const & cipher, + _olm_cipher const *cipher, olm::MessageKey const & message_key, olm::MessageReader const & reader, std::uint8_t * plaintext, std::size_t max_plaintext_length ) { - return cipher.decrypt( + return cipher->ops->decrypt( + cipher, message_key.key, sizeof(message_key.key), reader.input, reader.input_length, reader.ciphertext, reader.ciphertext_length, @@ -155,7 +166,6 @@ static std::size_t verify_mac_and_decrypt_for_new_chain( new_chain.ratchet_key, session.kdf_info, new_root_key, new_chain.chain_key ); - std::size_t result = verify_mac_and_decrypt_for_existing_chain( session, new_chain.chain_key, reader, plaintext, max_plaintext_length @@ -170,19 +180,19 @@ static std::size_t verify_mac_and_decrypt_for_new_chain( olm::Ratchet::Ratchet( olm::KdfInfo const & kdf_info, - Cipher const & ratchet_cipher + _olm_cipher const * ratchet_cipher ) : kdf_info(kdf_info), ratchet_cipher(ratchet_cipher), - last_error(olm::ErrorCode::SUCCESS) { + last_error(OlmErrorCode::OLM_SUCCESS) { } void olm::Ratchet::initialise_as_bob( std::uint8_t const * shared_secret, std::size_t shared_secret_length, - olm::Curve25519PublicKey const & their_ratchet_key + _olm_curve25519_public_key const & their_ratchet_key ) { - std::uint8_t derived_secrets[2 * olm::KEY_LENGTH]; - olm::hkdf_sha256( + std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH]; + _olm_crypto_hkdf_sha256( shared_secret, shared_secret_length, nullptr, 0, kdf_info.root_info, kdf_info.root_info_length, @@ -200,10 +210,10 @@ void olm::Ratchet::initialise_as_bob( void olm::Ratchet::initialise_as_alice( std::uint8_t const * shared_secret, std::size_t shared_secret_length, - olm::Curve25519KeyPair const & our_ratchet_key + _olm_curve25519_key_pair const & our_ratchet_key ) { - std::uint8_t derived_secrets[2 * olm::KEY_LENGTH]; - olm::hkdf_sha256( + std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH]; + _olm_crypto_hkdf_sha256( shared_secret, shared_secret_length, nullptr, 0, kdf_info.root_info, kdf_info.root_info_length, @@ -224,7 +234,7 @@ namespace olm { static std::size_t pickle_length( const olm::SharedKey & value ) { - return olm::KEY_LENGTH; + return olm::OLM_SHARED_KEY_LENGTH; } @@ -232,7 +242,7 @@ static std::uint8_t * pickle( std::uint8_t * pos, const olm::SharedKey & value ) { - return olm::pickle_bytes(pos, value, olm::KEY_LENGTH); + return olm::pickle_bytes(pos, value, olm::OLM_SHARED_KEY_LENGTH); } @@ -240,7 +250,7 @@ static std::uint8_t const * unpickle( std::uint8_t const * pos, std::uint8_t const * end, olm::SharedKey & value ) { - return olm::unpickle_bytes(pos, end, value, olm::KEY_LENGTH); + return olm::unpickle_bytes(pos, end, value, olm::OLM_SHARED_KEY_LENGTH); } @@ -349,7 +359,7 @@ std::size_t olm::pickle_length( olm::Ratchet const & value ) { std::size_t length = 0; - length += olm::KEY_LENGTH; + length += olm::OLM_SHARED_KEY_LENGTH; length += olm::pickle_length(value.sender_chain); length += olm::pickle_length(value.receiver_chains); length += olm::pickle_length(value.skipped_message_keys); @@ -370,12 +380,19 @@ std::uint8_t * olm::pickle( std::uint8_t const * olm::unpickle( std::uint8_t const * pos, std::uint8_t const * end, - olm::Ratchet & value + olm::Ratchet & value, + bool includes_chain_index ) { pos = unpickle(pos, end, value.root_key); pos = unpickle(pos, end, value.sender_chain); pos = unpickle(pos, end, value.receiver_chains); pos = unpickle(pos, end, value.skipped_message_keys); + + // pickle v 0x80000001 includes a chain index; pickle v1 does not. + if (includes_chain_index) { + std::uint32_t dummy; + pos = unpickle(pos, end, dummy); + } return pos; } @@ -387,17 +404,18 @@ std::size_t olm::Ratchet::encrypt_output_length( if (!sender_chain.empty()) { counter = sender_chain[0].chain_key.index; } - std::size_t padded = ratchet_cipher.encrypt_ciphertext_length( + std::size_t padded = ratchet_cipher->ops->encrypt_ciphertext_length( + ratchet_cipher, plaintext_length ); return olm::encode_message_length( - counter, olm::KEY_LENGTH, padded, ratchet_cipher.mac_length() + counter, CURVE25519_KEY_LENGTH, padded, ratchet_cipher->ops->mac_length(ratchet_cipher) ); } std::size_t olm::Ratchet::encrypt_random_length() { - return sender_chain.empty() ? olm::KEY_LENGTH : 0; + return sender_chain.empty() ? CURVE25519_RANDOM_LENGTH : 0; } @@ -409,17 +427,17 @@ std::size_t olm::Ratchet::encrypt( std::size_t output_length = encrypt_output_length(plaintext_length); if (random_length < encrypt_random_length()) { - last_error = olm::ErrorCode::NOT_ENOUGH_RANDOM; + last_error = OlmErrorCode::OLM_NOT_ENOUGH_RANDOM; return std::size_t(-1); } if (max_output_length < output_length) { - last_error = olm::ErrorCode::OUTPUT_BUFFER_TOO_SMALL; + last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL; return std::size_t(-1); } if (sender_chain.empty()) { sender_chain.insert(); - olm::curve25519_generate_key(random, sender_chain[0].ratchet_key); + _olm_crypto_curve25519_generate_key(random, &sender_chain[0].ratchet_key); create_chain_key( root_key, sender_chain[0].ratchet_key, @@ -433,22 +451,26 @@ std::size_t olm::Ratchet::encrypt( create_message_keys(sender_chain[0].chain_key, kdf_info, keys); advance_chain_key(sender_chain[0].chain_key, sender_chain[0].chain_key); - std::size_t ciphertext_length = ratchet_cipher.encrypt_ciphertext_length( + std::size_t ciphertext_length = ratchet_cipher->ops->encrypt_ciphertext_length( + ratchet_cipher, plaintext_length ); std::uint32_t counter = keys.index; - Curve25519PublicKey const & ratchet_key = sender_chain[0].ratchet_key; + _olm_curve25519_public_key const & ratchet_key = + sender_chain[0].ratchet_key.public_key; olm::MessageWriter writer; olm::encode_message( - writer, PROTOCOL_VERSION, counter, olm::KEY_LENGTH, ciphertext_length, + writer, PROTOCOL_VERSION, counter, CURVE25519_KEY_LENGTH, + ciphertext_length, output ); olm::store_array(writer.ratchet_key, ratchet_key.public_key); - ratchet_cipher.encrypt( + ratchet_cipher->ops->encrypt( + ratchet_cipher, keys.key, sizeof(keys.key), plaintext, plaintext_length, writer.ciphertext, ciphertext_length, @@ -465,15 +487,17 @@ std::size_t olm::Ratchet::decrypt_max_plaintext_length( ) { olm::MessageReader reader; olm::decode_message( - reader, input, input_length, ratchet_cipher.mac_length() + reader, input, input_length, + ratchet_cipher->ops->mac_length(ratchet_cipher) ); if (!reader.ciphertext) { - last_error = olm::ErrorCode::BAD_MESSAGE_FORMAT; + last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT; return std::size_t(-1); } - return ratchet_cipher.decrypt_max_plaintext_length(reader.ciphertext_length); + return ratchet_cipher->ops->decrypt_max_plaintext_length( + ratchet_cipher, reader.ciphertext_length); } @@ -483,38 +507,41 @@ std::size_t olm::Ratchet::decrypt( ) { olm::MessageReader reader; olm::decode_message( - reader, input, input_length, ratchet_cipher.mac_length() + reader, input, input_length, + ratchet_cipher->ops->mac_length(ratchet_cipher) ); if (reader.version != PROTOCOL_VERSION) { - last_error = olm::ErrorCode::BAD_MESSAGE_VERSION; + last_error = OlmErrorCode::OLM_BAD_MESSAGE_VERSION; return std::size_t(-1); } if (!reader.has_counter || !reader.ratchet_key || !reader.ciphertext) { - last_error = olm::ErrorCode::BAD_MESSAGE_FORMAT; + last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT; return std::size_t(-1); } - std::size_t max_length = ratchet_cipher.decrypt_max_plaintext_length( + std::size_t max_length = ratchet_cipher->ops->decrypt_max_plaintext_length( + ratchet_cipher, reader.ciphertext_length ); if (max_plaintext_length < max_length) { - last_error = olm::ErrorCode::OUTPUT_BUFFER_TOO_SMALL; + last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL; return std::size_t(-1); } - if (reader.ratchet_key_length != olm::KEY_LENGTH) { - last_error = olm::ErrorCode::BAD_MESSAGE_FORMAT; + if (reader.ratchet_key_length != CURVE25519_KEY_LENGTH) { + last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT; return std::size_t(-1); } ReceiverChain * chain = nullptr; + for (olm::ReceiverChain & receiver_chain : receiver_chains) { if (0 == std::memcmp( receiver_chain.ratchet_key.public_key, reader.ratchet_key, - olm::KEY_LENGTH + CURVE25519_KEY_LENGTH )) { chain = &receiver_chain; break; @@ -534,7 +561,7 @@ std::size_t olm::Ratchet::decrypt( if (reader.counter == skipped.message_key.index && 0 == std::memcmp( skipped.ratchet_key.public_key, reader.ratchet_key, - olm::KEY_LENGTH + CURVE25519_KEY_LENGTH ) ) { /* Found the key for this message. Check the MAC. */ @@ -555,26 +582,32 @@ std::size_t olm::Ratchet::decrypt( } } else { result = verify_mac_and_decrypt_for_existing_chain( - *this, chain->chain_key, reader, plaintext, max_plaintext_length + *this, chain->chain_key, + reader, plaintext, max_plaintext_length ); } if (result == std::size_t(-1)) { - last_error = olm::ErrorCode::BAD_MESSAGE_MAC; + last_error = OlmErrorCode::OLM_BAD_MESSAGE_MAC; return std::size_t(-1); } if (!chain) { - /* They have started using a new empheral ratchet key. + /* They have started using a new ephemeral ratchet key. * We need to derive a new set of chain keys. * We can discard our previous empheral ratchet key. * We will generate a new key when we send the next message. */ + chain = receiver_chains.insert(); olm::load_array(chain->ratchet_key.public_key, reader.ratchet_key); + + // TODO: we've already done this once, in + // verify_mac_and_decrypt_for_new_chain(). we could reuse the result. create_chain_key( root_key, sender_chain[0].ratchet_key, chain->ratchet_key, kdf_info, root_key, chain->chain_key ); + olm::unset(sender_chain[0]); sender_chain.erase(sender_chain.begin()); } |