Add some logging to help understand what's going on
This commit is contained in:
parent
e7a2af1ede
commit
9848f84452
10 changed files with 220 additions and 27 deletions
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace olm {
|
namespace olm {
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ static const std::size_t IV_LENGTH = 16;
|
||||||
|
|
||||||
struct Curve25519PublicKey {
|
struct Curve25519PublicKey {
|
||||||
std::uint8_t public_key[KEY_LENGTH];
|
std::uint8_t public_key[KEY_LENGTH];
|
||||||
|
std::string to_string() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ const unsigned int LOG_ERROR = 2;
|
||||||
const unsigned int LOG_WARNING = 3;
|
const unsigned int LOG_WARNING = 3;
|
||||||
const unsigned int LOG_INFO = 4;
|
const unsigned int LOG_INFO = 4;
|
||||||
const unsigned int LOG_DEBUG = 5;
|
const unsigned int LOG_DEBUG = 5;
|
||||||
|
const unsigned int LOG_TRACE = 6;
|
||||||
|
|
||||||
void set_log_level(unsigned int log_level);
|
void set_log_level(unsigned int log_level);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2015 OpenMarket Ltd
|
/* Copyright 2015, 2016 OpenMarket Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -15,6 +15,9 @@
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace olm {
|
namespace olm {
|
||||||
|
@ -84,4 +87,23 @@ std::uint8_t * store_array(
|
||||||
return destination + sizeof(T);
|
return destination + sizeof(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** convert an array of bytes to a string representation */
|
||||||
|
template<typename T>
|
||||||
|
std::string bytes_to_string(T start, T end) {
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << std::hex << std::setfill('0');
|
||||||
|
while (start != end) {
|
||||||
|
ss << std::setw(2) << static_cast<int>(*start++);
|
||||||
|
if (start != end) {
|
||||||
|
ss << ":";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::string bytes_to_string(T start, size_t len) {
|
||||||
|
return bytes_to_string(start, start+len);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace olm
|
} // namespace olm
|
||||||
|
|
|
@ -29,7 +29,6 @@ struct ChainKey {
|
||||||
SharedKey key;
|
SharedKey key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct MessageKey {
|
struct MessageKey {
|
||||||
std::uint32_t index;
|
std::uint32_t index;
|
||||||
SharedKey key;
|
SharedKey key;
|
||||||
|
@ -82,8 +81,18 @@ struct Ratchet {
|
||||||
/** The last error that happened encrypting or decrypting a message. */
|
/** The last error that happened encrypting or decrypting a message. */
|
||||||
ErrorCode last_error;
|
ErrorCode last_error;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A count of the number of times the root key has been advanced; this is
|
||||||
|
* maintained purely for diagnostics.
|
||||||
|
*
|
||||||
|
* If sender_chain is empty, this will be the index of the current receiver
|
||||||
|
* chain (odd for Alice, even for Bob); otherwise, the index of the current
|
||||||
|
* sender chain (even for Alice, odd for Bob).
|
||||||
|
*/
|
||||||
|
std::uint32_t chain_index;
|
||||||
|
|
||||||
/** The root key is used to generate chain keys from the ephemeral keys.
|
/** The root key is used to generate chain keys from the ephemeral keys.
|
||||||
* A new root_key derived each time a chain key is derived. */
|
* A new root_key derived each time a new chain is started. */
|
||||||
SharedKey root_key;
|
SharedKey root_key;
|
||||||
|
|
||||||
/** The sender chain is used to send messages. Each time a new ephemeral
|
/** The sender chain is used to send messages. Each time a new ephemeral
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<script src="../build/olm.js"></script>
|
<script src="olm.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function (event) {
|
document.addEventListener("DOMContentLoaded", function (event) {
|
||||||
function progress(who, message) {
|
function progress(who, message) {
|
||||||
var message_element = document.createElement("pre");
|
var message_element = document.createElement("pre");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2015 OpenMarket Ltd
|
/* Copyright 2015, 2016 OpenMarket Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -14,9 +14,12 @@
|
||||||
*/
|
*/
|
||||||
#include "olm/account.hh"
|
#include "olm/account.hh"
|
||||||
#include "olm/base64.hh"
|
#include "olm/base64.hh"
|
||||||
|
#include "olm/logging.hh"
|
||||||
#include "olm/pickle.hh"
|
#include "olm/pickle.hh"
|
||||||
#include "olm/memory.hh"
|
#include "olm/memory.hh"
|
||||||
|
|
||||||
|
static const char *LOG_CATEGORY = "olm::Account";
|
||||||
|
|
||||||
olm::Account::Account(
|
olm::Account::Account(
|
||||||
) : next_one_time_key_id(0),
|
) : next_one_time_key_id(0),
|
||||||
last_error(olm::ErrorCode::SUCCESS) {
|
last_error(olm::ErrorCode::SUCCESS) {
|
||||||
|
@ -42,9 +45,11 @@ std::size_t olm::Account::remove_key(
|
||||||
if (olm::array_equal(i->key.public_key, public_key.public_key)) {
|
if (olm::array_equal(i->key.public_key, public_key.public_key)) {
|
||||||
std::uint32_t id = i->id;
|
std::uint32_t id = i->id;
|
||||||
one_time_keys.erase(i);
|
one_time_keys.erase(i);
|
||||||
|
olm::logf(olm::LOG_INFO, LOG_CATEGORY, "removed key id %i", id);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
olm::logf(olm::LOG_WARNING, LOG_CATEGORY, "Couldn't find key to remove");
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +69,8 @@ std::size_t olm::Account::new_account(
|
||||||
random += KEY_LENGTH;
|
random += KEY_LENGTH;
|
||||||
olm::curve25519_generate_key(random, identity_keys.curve25519_key);
|
olm::curve25519_generate_key(random, identity_keys.curve25519_key);
|
||||||
|
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Created new account");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,10 @@ inline static void hmac_sha256_final(
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
std::string olm::Curve25519PublicKey::to_string() const {
|
||||||
|
return olm::bytes_to_string(std::begin(public_key),
|
||||||
|
std::end(public_key));
|
||||||
|
};
|
||||||
|
|
||||||
void olm::curve25519_generate_key(
|
void olm::curve25519_generate_key(
|
||||||
std::uint8_t const * random_32_bytes,
|
std::uint8_t const * random_32_bytes,
|
||||||
|
|
|
@ -14,8 +14,13 @@
|
||||||
*/
|
*/
|
||||||
#include "olm/message.hh"
|
#include "olm/message.hh"
|
||||||
|
|
||||||
|
#include "olm/logging.hh"
|
||||||
|
#include "olm/memory.hh"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
static const char *LOG_CATEGORY = "olm::Message";
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static std::size_t varint_length(
|
static std::size_t varint_length(
|
||||||
T value
|
T value
|
||||||
|
@ -234,6 +239,13 @@ void olm::decode_message(
|
||||||
}
|
}
|
||||||
unknown = pos;
|
unknown = pos;
|
||||||
}
|
}
|
||||||
|
olm::logf(olm::LOG_TRACE, LOG_CATEGORY,
|
||||||
|
"Decoded message ver=%i ratchet_key=%s chain_idx=%i ciphertext=%s",
|
||||||
|
reader.version,
|
||||||
|
olm::bytes_to_string(reader.ratchet_key, reader.ratchet_key_length).c_str(),
|
||||||
|
reader.has_counter ? reader.counter : -1,
|
||||||
|
olm::bytes_to_string(reader.ciphertext, reader.ciphertext_length).c_str()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -322,4 +334,14 @@ void olm::decode_one_time_key_message(
|
||||||
}
|
}
|
||||||
unknown = pos;
|
unknown = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
olm::logf(olm::LOG_TRACE, LOG_CATEGORY,
|
||||||
|
"Decoded pre-key message ver=%i one_time_key[Eb]=%s "
|
||||||
|
"base_key[Ea]=%s identity_key[Ia]=%s message=%s",
|
||||||
|
reader.version,
|
||||||
|
olm::bytes_to_string(reader.one_time_key, reader.one_time_key_length).c_str(),
|
||||||
|
olm::bytes_to_string(reader.base_key, reader.base_key_length).c_str(),
|
||||||
|
olm::bytes_to_string(reader.identity_key, reader.identity_key_length).c_str(),
|
||||||
|
olm::bytes_to_string(reader.message, reader.message_length).c_str()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2015 OpenMarket Ltd
|
/* Copyright 2015, 2016 OpenMarket Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,17 +17,31 @@
|
||||||
#include "olm/memory.hh"
|
#include "olm/memory.hh"
|
||||||
#include "olm/cipher.hh"
|
#include "olm/cipher.hh"
|
||||||
#include "olm/pickle.hh"
|
#include "olm/pickle.hh"
|
||||||
|
#include "olm/logging.hh"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
static const char *LOG_CATEGORY = "olm::Ratchet";
|
||||||
|
|
||||||
static const std::uint8_t PROTOCOL_VERSION = 3;
|
static const std::uint8_t PROTOCOL_VERSION = 3;
|
||||||
static const std::uint8_t MESSAGE_KEY_SEED[1] = {0x01};
|
static const std::uint8_t MESSAGE_KEY_SEED[1] = {0x01};
|
||||||
static const std::uint8_t CHAIN_KEY_SEED[1] = {0x02};
|
static const std::uint8_t CHAIN_KEY_SEED[1] = {0x02};
|
||||||
static const std::size_t MAX_MESSAGE_GAP = 2000;
|
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(
|
static void create_chain_key(
|
||||||
olm::SharedKey const & root_key,
|
olm::SharedKey const & root_key,
|
||||||
olm::Curve25519KeyPair const & our_key,
|
olm::Curve25519KeyPair const & our_key,
|
||||||
|
@ -55,6 +69,7 @@ static void create_chain_key(
|
||||||
|
|
||||||
|
|
||||||
static void advance_chain_key(
|
static void advance_chain_key(
|
||||||
|
std::uint32_t chain_index,
|
||||||
olm::ChainKey const & chain_key,
|
olm::ChainKey const & chain_key,
|
||||||
olm::ChainKey & new_chain_key
|
olm::ChainKey & new_chain_key
|
||||||
) {
|
) {
|
||||||
|
@ -64,20 +79,24 @@ static void advance_chain_key(
|
||||||
new_chain_key.key
|
new_chain_key.key
|
||||||
);
|
);
|
||||||
new_chain_key.index = chain_key.index + 1;
|
new_chain_key.index = chain_key.index + 1;
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Derived chain key C(%i,%i)",
|
||||||
|
chain_index, new_chain_key.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void create_message_keys(
|
static void create_message_keys(
|
||||||
|
std::uint32_t chain_index,
|
||||||
olm::ChainKey const & chain_key,
|
olm::ChainKey const & chain_key,
|
||||||
olm::KdfInfo const & info,
|
olm::KdfInfo const & info,
|
||||||
olm::MessageKey & message_key
|
olm::MessageKey & message_key) {
|
||||||
) {
|
|
||||||
olm::hmac_sha256(
|
olm::hmac_sha256(
|
||||||
chain_key.key, sizeof(chain_key.key),
|
chain_key.key, sizeof(chain_key.key),
|
||||||
MESSAGE_KEY_SEED, sizeof(MESSAGE_KEY_SEED),
|
MESSAGE_KEY_SEED, sizeof(MESSAGE_KEY_SEED),
|
||||||
message_key.key
|
message_key.key
|
||||||
);
|
);
|
||||||
message_key.index = chain_key.index;
|
message_key.index = chain_key.index;
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Created message key with chain key C(%i,%i)",
|
||||||
|
chain_index, message_key.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,6 +117,7 @@ static std::size_t verify_mac_and_decrypt(
|
||||||
|
|
||||||
static std::size_t verify_mac_and_decrypt_for_existing_chain(
|
static std::size_t verify_mac_and_decrypt_for_existing_chain(
|
||||||
olm::Ratchet const & session,
|
olm::Ratchet const & session,
|
||||||
|
std::uint32_t chain_index,
|
||||||
olm::ChainKey const & chain,
|
olm::ChainKey const & chain,
|
||||||
olm::MessageReader const & reader,
|
olm::MessageReader const & reader,
|
||||||
std::uint8_t * plaintext, std::size_t max_plaintext_length
|
std::uint8_t * plaintext, std::size_t max_plaintext_length
|
||||||
|
@ -114,11 +134,11 @@ static std::size_t verify_mac_and_decrypt_for_existing_chain(
|
||||||
olm::ChainKey new_chain = chain;
|
olm::ChainKey new_chain = chain;
|
||||||
|
|
||||||
while (new_chain.index < reader.counter) {
|
while (new_chain.index < reader.counter) {
|
||||||
advance_chain_key(new_chain, new_chain);
|
advance_chain_key(chain_index, new_chain, new_chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
olm::MessageKey message_key;
|
olm::MessageKey message_key;
|
||||||
create_message_keys(new_chain, session.kdf_info, message_key);
|
create_message_keys(chain_index, new_chain, session.kdf_info, message_key);
|
||||||
|
|
||||||
std::size_t result = verify_mac_and_decrypt(
|
std::size_t result = verify_mac_and_decrypt(
|
||||||
session.ratchet_cipher, message_key, reader,
|
session.ratchet_cipher, message_key, reader,
|
||||||
|
@ -150,14 +170,17 @@ static std::size_t verify_mac_and_decrypt_for_new_chain(
|
||||||
}
|
}
|
||||||
olm::load_array(new_chain.ratchet_key.public_key, reader.ratchet_key);
|
olm::load_array(new_chain.ratchet_key.public_key, reader.ratchet_key);
|
||||||
|
|
||||||
|
std::uint32_t chain_index = session.chain_index + 1;
|
||||||
create_chain_key(
|
create_chain_key(
|
||||||
session.root_key, session.sender_chain[0].ratchet_key,
|
session.root_key, session.sender_chain[0].ratchet_key,
|
||||||
new_chain.ratchet_key, session.kdf_info,
|
new_chain.ratchet_key, session.kdf_info,
|
||||||
new_root_key, new_chain.chain_key
|
new_root_key, new_chain.chain_key
|
||||||
);
|
);
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Calculated new receiver chain R(%i)",
|
||||||
|
chain_index);
|
||||||
|
|
||||||
std::size_t result = verify_mac_and_decrypt_for_existing_chain(
|
std::size_t result = verify_mac_and_decrypt_for_existing_chain(
|
||||||
session, new_chain.chain_key, reader,
|
session, chain_index, new_chain.chain_key, reader,
|
||||||
plaintext, max_plaintext_length
|
plaintext, max_plaintext_length
|
||||||
);
|
);
|
||||||
olm::unset(new_root_key);
|
olm::unset(new_root_key);
|
||||||
|
@ -194,7 +217,9 @@ void olm::Ratchet::initialise_as_bob(
|
||||||
pos = olm::load_array(root_key, pos);
|
pos = olm::load_array(root_key, pos);
|
||||||
pos = olm::load_array(receiver_chains[0].chain_key.key, pos);
|
pos = olm::load_array(receiver_chains[0].chain_key.key, pos);
|
||||||
receiver_chains[0].ratchet_key = their_ratchet_key;
|
receiver_chains[0].ratchet_key = their_ratchet_key;
|
||||||
|
chain_index = 0;
|
||||||
olm::unset(derived_secrets);
|
olm::unset(derived_secrets);
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Initialised receiver chain R(0)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -215,7 +240,9 @@ void olm::Ratchet::initialise_as_alice(
|
||||||
pos = olm::load_array(root_key, pos);
|
pos = olm::load_array(root_key, pos);
|
||||||
pos = olm::load_array(sender_chain[0].chain_key.key, pos);
|
pos = olm::load_array(sender_chain[0].chain_key.key, pos);
|
||||||
sender_chain[0].ratchet_key = our_ratchet_key;
|
sender_chain[0].ratchet_key = our_ratchet_key;
|
||||||
|
chain_index = 0;
|
||||||
olm::unset(derived_secrets);
|
olm::unset(derived_secrets);
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Initialised sender chain R(0)");
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace olm {
|
namespace olm {
|
||||||
|
@ -353,6 +380,7 @@ std::size_t olm::pickle_length(
|
||||||
length += olm::pickle_length(value.sender_chain);
|
length += olm::pickle_length(value.sender_chain);
|
||||||
length += olm::pickle_length(value.receiver_chains);
|
length += olm::pickle_length(value.receiver_chains);
|
||||||
length += olm::pickle_length(value.skipped_message_keys);
|
length += olm::pickle_length(value.skipped_message_keys);
|
||||||
|
length += olm::pickle_length(value.chain_index);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,6 +392,7 @@ std::uint8_t * olm::pickle(
|
||||||
pos = pickle(pos, value.sender_chain);
|
pos = pickle(pos, value.sender_chain);
|
||||||
pos = pickle(pos, value.receiver_chains);
|
pos = pickle(pos, value.receiver_chains);
|
||||||
pos = pickle(pos, value.skipped_message_keys);
|
pos = pickle(pos, value.skipped_message_keys);
|
||||||
|
pos = pickle(pos, value.chain_index);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,6 +405,7 @@ std::uint8_t const * olm::unpickle(
|
||||||
pos = unpickle(pos, end, value.sender_chain);
|
pos = unpickle(pos, end, value.sender_chain);
|
||||||
pos = unpickle(pos, end, value.receiver_chains);
|
pos = unpickle(pos, end, value.receiver_chains);
|
||||||
pos = unpickle(pos, end, value.skipped_message_keys);
|
pos = unpickle(pos, end, value.skipped_message_keys);
|
||||||
|
pos = unpickle(pos, end, value.chain_index);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,6 +450,9 @@ std::size_t olm::Ratchet::encrypt(
|
||||||
if (sender_chain.empty()) {
|
if (sender_chain.empty()) {
|
||||||
sender_chain.insert();
|
sender_chain.insert();
|
||||||
olm::curve25519_generate_key(random, sender_chain[0].ratchet_key);
|
olm::curve25519_generate_key(random, sender_chain[0].ratchet_key);
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Created new ratchet key T(%i) %s",
|
||||||
|
chain_index + 1,
|
||||||
|
sender_chain[0].ratchet_key.to_string().c_str());
|
||||||
create_chain_key(
|
create_chain_key(
|
||||||
root_key,
|
root_key,
|
||||||
sender_chain[0].ratchet_key,
|
sender_chain[0].ratchet_key,
|
||||||
|
@ -427,11 +460,14 @@ std::size_t olm::Ratchet::encrypt(
|
||||||
kdf_info,
|
kdf_info,
|
||||||
root_key, sender_chain[0].chain_key
|
root_key, sender_chain[0].chain_key
|
||||||
);
|
);
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Initialised new sender chain R(%i)",
|
||||||
|
chain_index + 1);
|
||||||
|
chain_index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageKey keys;
|
MessageKey keys;
|
||||||
create_message_keys(sender_chain[0].chain_key, kdf_info, keys);
|
create_message_keys(chain_index, sender_chain[0].chain_key, kdf_info, keys);
|
||||||
advance_chain_key(sender_chain[0].chain_key, sender_chain[0].chain_key);
|
advance_chain_key(chain_index, 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.encrypt_ciphertext_length(
|
||||||
plaintext_length
|
plaintext_length
|
||||||
|
@ -455,6 +491,14 @@ std::size_t olm::Ratchet::encrypt(
|
||||||
output, output_length
|
output, output_length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
olm::logf(olm::LOG_TRACE, LOG_CATEGORY,
|
||||||
|
"Encoded message ver=%i ratchet_key=%s chain_idx=%i ciphertext=%s",
|
||||||
|
PROTOCOL_VERSION,
|
||||||
|
olm::bytes_to_string(writer.ratchet_key, olm::KEY_LENGTH).c_str(),
|
||||||
|
counter,
|
||||||
|
olm::bytes_to_string(writer.ciphertext, ciphertext_length).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
olm::unset(keys);
|
olm::unset(keys);
|
||||||
return output_length;
|
return output_length;
|
||||||
}
|
}
|
||||||
|
@ -481,6 +525,10 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
std::uint8_t const * input, std::size_t input_length,
|
std::uint8_t const * input, std::size_t input_length,
|
||||||
std::uint8_t * plaintext, std::size_t max_plaintext_length
|
std::uint8_t * plaintext, std::size_t max_plaintext_length
|
||||||
) {
|
) {
|
||||||
|
olm::logf(olm::LOG_TRACE, LOG_CATEGORY,
|
||||||
|
"Decrypting message %s",
|
||||||
|
olm::bytes_to_string(input, input_length).c_str());
|
||||||
|
|
||||||
olm::MessageReader reader;
|
olm::MessageReader reader;
|
||||||
olm::decode_message(
|
olm::decode_message(
|
||||||
reader, input, input_length, ratchet_cipher.mac_length()
|
reader, input, input_length, ratchet_cipher.mac_length()
|
||||||
|
@ -511,6 +559,13 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
}
|
}
|
||||||
|
|
||||||
ReceiverChain * chain = nullptr;
|
ReceiverChain * chain = nullptr;
|
||||||
|
auto receiver_chain_index = chain_index;
|
||||||
|
if (!sender_chain.empty()) {
|
||||||
|
// we've already advanced to the next (sender) chain; decrement to
|
||||||
|
// get back to the receiver chains
|
||||||
|
receiver_chain_index --;
|
||||||
|
}
|
||||||
|
|
||||||
for (olm::ReceiverChain & receiver_chain : receiver_chains) {
|
for (olm::ReceiverChain & receiver_chain : receiver_chains) {
|
||||||
if (0 == std::memcmp(
|
if (0 == std::memcmp(
|
||||||
receiver_chain.ratchet_key.public_key, reader.ratchet_key,
|
receiver_chain.ratchet_key.public_key, reader.ratchet_key,
|
||||||
|
@ -519,11 +574,14 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
chain = &receiver_chain;
|
chain = &receiver_chain;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
receiver_chain_index -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t result = std::size_t(-1);
|
std::size_t result = std::size_t(-1);
|
||||||
|
|
||||||
if (!chain) {
|
if (!chain) {
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY,
|
||||||
|
"Sender ratchet key does not match known chain; starting new one");
|
||||||
result = verify_mac_and_decrypt_for_new_chain(
|
result = verify_mac_and_decrypt_for_new_chain(
|
||||||
*this, reader, plaintext, max_plaintext_length
|
*this, reader, plaintext, max_plaintext_length
|
||||||
);
|
);
|
||||||
|
@ -555,7 +613,8 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = verify_mac_and_decrypt_for_existing_chain(
|
result = verify_mac_and_decrypt_for_existing_chain(
|
||||||
*this, chain->chain_key, reader, plaintext, max_plaintext_length
|
*this, receiver_chain_index, chain->chain_key,
|
||||||
|
reader, plaintext, max_plaintext_length
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,28 +624,36 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!chain) {
|
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 need to derive a new set of chain keys.
|
||||||
* We can discard our previous empheral ratchet key.
|
* We can discard our previous empheral ratchet key.
|
||||||
* We will generate a new key when we send the next message. */
|
* We will generate a new key when we send the next message. */
|
||||||
|
|
||||||
chain = receiver_chains.insert();
|
chain = receiver_chains.insert();
|
||||||
olm::load_array(chain->ratchet_key.public_key, reader.ratchet_key);
|
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(
|
create_chain_key(
|
||||||
root_key, sender_chain[0].ratchet_key, chain->ratchet_key,
|
root_key, sender_chain[0].ratchet_key, chain->ratchet_key,
|
||||||
kdf_info, root_key, chain->chain_key
|
kdf_info, root_key, chain->chain_key
|
||||||
);
|
);
|
||||||
|
|
||||||
olm::unset(sender_chain[0]);
|
olm::unset(sender_chain[0]);
|
||||||
sender_chain.erase(sender_chain.begin());
|
sender_chain.erase(sender_chain.begin());
|
||||||
|
receiver_chain_index = ++chain_index;
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Initialised new receiver chain R(%i)",
|
||||||
|
chain_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (chain->chain_key.index < reader.counter) {
|
while (chain->chain_key.index < reader.counter) {
|
||||||
olm::SkippedMessageKey & key = *skipped_message_keys.insert();
|
olm::SkippedMessageKey & key = *skipped_message_keys.insert();
|
||||||
create_message_keys(chain->chain_key, kdf_info, key.message_key);
|
create_message_keys(receiver_chain_index, chain->chain_key, kdf_info, key.message_key);
|
||||||
key.ratchet_key = chain->ratchet_key;
|
key.ratchet_key = chain->ratchet_key;
|
||||||
advance_chain_key(chain->chain_key, chain->chain_key);
|
advance_chain_key(receiver_chain_index, chain->chain_key, chain->chain_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
advance_chain_key(chain->chain_key, chain->chain_key);
|
advance_chain_key(receiver_chain_index, chain->chain_key, chain->chain_key);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2015 OpenMarket Ltd
|
/* Copyright 2015, 2016 OpenMarket Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
#include "olm/cipher.hh"
|
#include "olm/cipher.hh"
|
||||||
#include "olm/crypto.hh"
|
#include "olm/crypto.hh"
|
||||||
#include "olm/account.hh"
|
#include "olm/account.hh"
|
||||||
|
#include "olm/logging.hh"
|
||||||
#include "olm/memory.hh"
|
#include "olm/memory.hh"
|
||||||
#include "olm/message.hh"
|
#include "olm/message.hh"
|
||||||
#include "olm/pickle.hh"
|
#include "olm/pickle.hh"
|
||||||
|
@ -24,6 +25,8 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
static const char *LOG_CATEGORY = "olm::Session";
|
||||||
|
|
||||||
static const std::uint8_t PROTOCOL_VERSION = 0x3;
|
static const std::uint8_t PROTOCOL_VERSION = 0x3;
|
||||||
|
|
||||||
static const std::uint8_t ROOT_KDF_INFO[] = "OLM_ROOT";
|
static const std::uint8_t ROOT_KDF_INFO[] = "OLM_ROOT";
|
||||||
|
@ -65,11 +68,21 @@ std::size_t olm::Session::new_outbound_session(
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY,
|
||||||
|
"Creating new outbound session to receiver identity IB %s, "
|
||||||
|
"receiver ephemeral EB %s", identity_key.to_string().c_str(),
|
||||||
|
one_time_key.to_string().c_str()
|
||||||
|
);
|
||||||
|
|
||||||
olm::Curve25519KeyPair base_key;
|
olm::Curve25519KeyPair base_key;
|
||||||
olm::curve25519_generate_key(random, base_key);
|
olm::curve25519_generate_key(random, base_key);
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Created new ephemeral key EA %s",
|
||||||
|
base_key.to_string().c_str());
|
||||||
|
|
||||||
olm::Curve25519KeyPair ratchet_key;
|
olm::Curve25519KeyPair ratchet_key;
|
||||||
olm::curve25519_generate_key(random + olm::KEY_LENGTH, ratchet_key);
|
olm::curve25519_generate_key(random + olm::KEY_LENGTH, ratchet_key);
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Created new ratchet key T(0) %s",
|
||||||
|
ratchet_key.to_string().c_str());
|
||||||
|
|
||||||
olm::Curve25519KeyPair const & alice_identity_key_pair = (
|
olm::Curve25519KeyPair const & alice_identity_key_pair = (
|
||||||
local_account.identity_keys.curve25519_key
|
local_account.identity_keys.curve25519_key
|
||||||
|
@ -95,6 +108,7 @@ std::size_t olm::Session::new_outbound_session(
|
||||||
olm::unset(ratchet_key);
|
olm::unset(ratchet_key);
|
||||||
olm::unset(secret);
|
olm::unset(secret);
|
||||||
|
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Initialised outbound session");
|
||||||
return std::size_t(0);
|
return std::size_t(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,11 +151,29 @@ std::size_t olm::Session::new_inbound_session(
|
||||||
their_identity_key->public_key, reader.identity_key, olm::KEY_LENGTH
|
their_identity_key->public_key, reader.identity_key, olm::KEY_LENGTH
|
||||||
);
|
);
|
||||||
if (!same) {
|
if (!same) {
|
||||||
|
olm::logf(olm::LOG_INFO, LOG_CATEGORY,
|
||||||
|
"Identity key on received message is incorrect "
|
||||||
|
"(expected %s, got %s)",
|
||||||
|
their_identity_key->to_string().c_str(),
|
||||||
|
olm::bytes_to_string(reader.identity_key,
|
||||||
|
reader.identity_key + olm::KEY_LENGTH)
|
||||||
|
.c_str());
|
||||||
last_error = olm::ErrorCode::BAD_MESSAGE_KEY_ID;
|
last_error = olm::ErrorCode::BAD_MESSAGE_KEY_ID;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
olm::load_array(alice_identity_key.public_key, reader.identity_key);
|
||||||
|
olm::load_array(alice_base_key.public_key, reader.base_key);
|
||||||
|
olm::load_array(bob_one_time_key.public_key, reader.one_time_key);
|
||||||
|
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY,
|
||||||
|
"Creating new inbound session from sender identity IA %s, "
|
||||||
|
"sender ephemeral EA %s, our ephemeral EB %s",
|
||||||
|
alice_identity_key.to_string().c_str(),
|
||||||
|
alice_base_key.to_string().c_str(),
|
||||||
|
bob_one_time_key.to_string().c_str());
|
||||||
|
|
||||||
olm::MessageReader message_reader;
|
olm::MessageReader message_reader;
|
||||||
decode_message(
|
decode_message(
|
||||||
message_reader, reader.message, reader.message_length,
|
message_reader, reader.message, reader.message_length,
|
||||||
|
@ -154,17 +186,20 @@ std::size_t olm::Session::new_inbound_session(
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
olm::load_array(alice_identity_key.public_key, reader.identity_key);
|
|
||||||
olm::load_array(alice_base_key.public_key, reader.base_key);
|
|
||||||
olm::load_array(bob_one_time_key.public_key, reader.one_time_key);
|
|
||||||
olm::Curve25519PublicKey ratchet_key;
|
olm::Curve25519PublicKey ratchet_key;
|
||||||
olm::load_array(ratchet_key.public_key, message_reader.ratchet_key);
|
olm::load_array(ratchet_key.public_key, message_reader.ratchet_key);
|
||||||
|
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY,
|
||||||
|
"Received ratchet key T(0) %s", ratchet_key.to_string().c_str());
|
||||||
|
|
||||||
olm::OneTimeKey const * our_one_time_key = local_account.lookup_key(
|
olm::OneTimeKey const * our_one_time_key = local_account.lookup_key(
|
||||||
bob_one_time_key
|
bob_one_time_key
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!our_one_time_key) {
|
if (!our_one_time_key) {
|
||||||
|
olm::logf(olm::LOG_INFO, LOG_CATEGORY,
|
||||||
|
"Session uses unknown ephemeral key %s",
|
||||||
|
bob_one_time_key.to_string().c_str());
|
||||||
last_error = olm::ErrorCode::BAD_MESSAGE_KEY_ID;
|
last_error = olm::ErrorCode::BAD_MESSAGE_KEY_ID;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
@ -185,6 +220,8 @@ std::size_t olm::Session::new_inbound_session(
|
||||||
ratchet.initialise_as_bob(secret, sizeof(secret), ratchet_key);
|
ratchet.initialise_as_bob(secret, sizeof(secret), ratchet_key);
|
||||||
|
|
||||||
olm::unset(secret);
|
olm::unset(secret);
|
||||||
|
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Initialised inbound session");
|
||||||
return std::size_t(0);
|
return std::size_t(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,6 +320,9 @@ std::size_t olm::Session::encrypt(
|
||||||
std::uint8_t const * random, std::size_t random_length,
|
std::uint8_t const * random, std::size_t random_length,
|
||||||
std::uint8_t * message, std::size_t message_length
|
std::uint8_t * message, std::size_t message_length
|
||||||
) {
|
) {
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Encrypting '%.*s'",
|
||||||
|
(int)plaintext_length, plaintext);
|
||||||
|
|
||||||
if (message_length < encrypt_message_length(plaintext_length)) {
|
if (message_length < encrypt_message_length(plaintext_length)) {
|
||||||
last_error = olm::ErrorCode::OUTPUT_BUFFER_TOO_SMALL;
|
last_error = olm::ErrorCode::OUTPUT_BUFFER_TOO_SMALL;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
|
@ -309,6 +349,16 @@ std::size_t olm::Session::encrypt(
|
||||||
olm::store_array(writer.identity_key, alice_identity_key.public_key);
|
olm::store_array(writer.identity_key, alice_identity_key.public_key);
|
||||||
olm::store_array(writer.base_key, alice_base_key.public_key);
|
olm::store_array(writer.base_key, alice_base_key.public_key);
|
||||||
message_body = writer.message;
|
message_body = writer.message;
|
||||||
|
|
||||||
|
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY,
|
||||||
|
"Encoded pre-key message ver=%i one_time_key[Eb]=%s "
|
||||||
|
"base_key[Ea]=%s identity_key[Ia]=%s",
|
||||||
|
PROTOCOL_VERSION,
|
||||||
|
olm::bytes_to_string(writer.one_time_key, olm::KEY_LENGTH).c_str(),
|
||||||
|
olm::bytes_to_string(writer.base_key, olm::KEY_LENGTH).c_str(),
|
||||||
|
olm::bytes_to_string(writer.identity_key, olm::KEY_LENGTH).c_str()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t result = ratchet.encrypt(
|
std::size_t result = ratchet.encrypt(
|
||||||
|
@ -320,7 +370,12 @@ std::size_t olm::Session::encrypt(
|
||||||
if (result == std::size_t(-1)) {
|
if (result == std::size_t(-1)) {
|
||||||
last_error = ratchet.last_error;
|
last_error = ratchet.last_error;
|
||||||
ratchet.last_error = olm::ErrorCode::SUCCESS;
|
ratchet.last_error = olm::ErrorCode::SUCCESS;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
olm::logf(olm::LOG_TRACE, LOG_CATEGORY, "Encrypted message %s",
|
||||||
|
olm::bytes_to_string(message_body, result).c_str());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,6 +417,9 @@ std::size_t olm::Session::decrypt(
|
||||||
std::uint8_t const * message, std::size_t message_length,
|
std::uint8_t const * message, std::size_t message_length,
|
||||||
std::uint8_t * plaintext, std::size_t max_plaintext_length
|
std::uint8_t * plaintext, std::size_t max_plaintext_length
|
||||||
) {
|
) {
|
||||||
|
olm::logf(olm::LOG_TRACE, LOG_CATEGORY, "Decrypting %smessage",
|
||||||
|
message_type == olm::MessageType::MESSAGE ? "" : "pre-key ");
|
||||||
|
|
||||||
std::uint8_t const * message_body;
|
std::uint8_t const * message_body;
|
||||||
std::size_t message_body_length;
|
std::size_t message_body_length;
|
||||||
if (message_type == olm::MessageType::MESSAGE) {
|
if (message_type == olm::MessageType::MESSAGE) {
|
||||||
|
@ -385,9 +443,12 @@ std::size_t olm::Session::decrypt(
|
||||||
if (result == std::size_t(-1)) {
|
if (result == std::size_t(-1)) {
|
||||||
last_error = ratchet.last_error;
|
last_error = ratchet.last_error;
|
||||||
ratchet.last_error = olm::ErrorCode::SUCCESS;
|
ratchet.last_error = olm::ErrorCode::SUCCESS;
|
||||||
} else {
|
return result;
|
||||||
received_message = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
received_message = true;
|
||||||
|
olm::logf(olm::LOG_DEBUG, LOG_CATEGORY, "Decrypted '%.*s'",
|
||||||
|
(int)result, plaintext);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,4 +501,3 @@ std::uint8_t const * olm::unpickle(
|
||||||
pos = olm::unpickle(pos, end, value.ratchet);
|
pos = olm::unpickle(pos, end, value.ratchet);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue