Replace hard coded references to the 32-byte key length with a constant, add utilities for copying data to and from fixed sized arrays
This commit is contained in:
parent
a378a40b3a
commit
b318055185
12 changed files with 219 additions and 188 deletions
|
@ -20,28 +20,27 @@
|
||||||
|
|
||||||
namespace olm {
|
namespace olm {
|
||||||
|
|
||||||
|
static const std::size_t KEY_LENGTH = 32;
|
||||||
|
static const std::size_t SIGNATURE_LENGTH = 64;
|
||||||
|
static const std::size_t IV_LENGTH = 16;
|
||||||
|
|
||||||
struct Curve25519PublicKey {
|
struct Curve25519PublicKey {
|
||||||
static const int LENGTH = 32;
|
std::uint8_t public_key[KEY_LENGTH];
|
||||||
std::uint8_t public_key[32];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Curve25519KeyPair : public Curve25519PublicKey {
|
struct Curve25519KeyPair : public Curve25519PublicKey {
|
||||||
static const int LENGTH = 64;
|
std::uint8_t private_key[KEY_LENGTH];
|
||||||
std::uint8_t private_key[32];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Ed25519PublicKey {
|
struct Ed25519PublicKey {
|
||||||
static const int LENGTH = 32;
|
std::uint8_t public_key[KEY_LENGTH];
|
||||||
std::uint8_t public_key[32];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Ed25519KeyPair : public Ed25519PublicKey {
|
struct Ed25519KeyPair : public Ed25519PublicKey {
|
||||||
static const int LENGTH = 64;
|
std::uint8_t private_key[KEY_LENGTH];
|
||||||
std::uint8_t private_key[32];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,9 +51,6 @@ void curve25519_generate_key(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const std::size_t CURVE25519_SHARED_SECRET_LENGTH = 32;
|
|
||||||
|
|
||||||
|
|
||||||
/** Create a shared secret using our private key and their public key.
|
/** Create a shared secret using our private key and their public key.
|
||||||
* The output buffer must be at least 32 bytes long. */
|
* The output buffer must be at least 32 bytes long. */
|
||||||
void curve25519_shared_secret(
|
void curve25519_shared_secret(
|
||||||
|
@ -109,14 +105,12 @@ bool ed25519_verify(
|
||||||
|
|
||||||
|
|
||||||
struct Aes256Key {
|
struct Aes256Key {
|
||||||
static const int LENGTH = 32;
|
std::uint8_t key[KEY_LENGTH];
|
||||||
std::uint8_t key[32];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Aes256Iv {
|
struct Aes256Iv {
|
||||||
static const int LENGTH = 16;
|
std::uint8_t iv[IV_LENGTH];
|
||||||
std::uint8_t iv[16];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,7 +150,7 @@ void sha256(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const std::size_t HMAC_SHA256_OUTPUT_LENGTH = 32;
|
const std::size_t SHA256_OUTPUT_LENGTH = 32;
|
||||||
|
|
||||||
|
|
||||||
/** HMAC: Keyed-Hashing for Message Authentication
|
/** HMAC: Keyed-Hashing for Message Authentication
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
*/
|
*/
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace olm {
|
namespace olm {
|
||||||
|
|
||||||
|
@ -35,4 +37,51 @@ bool is_equal(
|
||||||
std::size_t length
|
std::size_t length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** Check if two fixed size arrays are equals */
|
||||||
|
template<typename T>
|
||||||
|
bool array_equal(
|
||||||
|
T const & array_a,
|
||||||
|
T const & array_b
|
||||||
|
) {
|
||||||
|
static_assert(
|
||||||
|
std::is_array<T>::value
|
||||||
|
&& std::is_convertible<T, std::uint8_t *>::value
|
||||||
|
&& sizeof(T) > 0,
|
||||||
|
"Arguments to array_equal must be std::uint8_t arrays[]."
|
||||||
|
);
|
||||||
|
return is_equal(array_a, array_b, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy into a fixed size array */
|
||||||
|
template<typename T>
|
||||||
|
std::uint8_t const * load_array(
|
||||||
|
T & destination,
|
||||||
|
std::uint8_t const * source
|
||||||
|
) {
|
||||||
|
static_assert(
|
||||||
|
std::is_array<T>::value
|
||||||
|
&& std::is_convertible<T, std::uint8_t *>::value
|
||||||
|
&& sizeof(T) > 0,
|
||||||
|
"The first argument to load_array must be a std::uint8_t array[]."
|
||||||
|
);
|
||||||
|
std::memcpy(destination, source, sizeof(T));
|
||||||
|
return source + sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy from a fixed size array */
|
||||||
|
template<typename T>
|
||||||
|
std::uint8_t * store_array(
|
||||||
|
std::uint8_t * destination,
|
||||||
|
T const & source
|
||||||
|
) {
|
||||||
|
static_assert(
|
||||||
|
std::is_array<T>::value
|
||||||
|
&& std::is_convertible<T, std::uint8_t *>::value
|
||||||
|
&& sizeof(T) > 0,
|
||||||
|
"The second argument to store_array must be a std::uint8_t array[]."
|
||||||
|
);
|
||||||
|
std::memcpy(destination, source, sizeof(T));
|
||||||
|
return destination + sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace olm
|
} // namespace olm
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace olm {
|
||||||
|
|
||||||
class Cipher;
|
class Cipher;
|
||||||
|
|
||||||
typedef std::uint8_t SharedKey[32];
|
typedef std::uint8_t SharedKey[olm::KEY_LENGTH];
|
||||||
|
|
||||||
|
|
||||||
struct ChainKey {
|
struct ChainKey {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "olm/account.hh"
|
#include "olm/account.hh"
|
||||||
#include "olm/base64.hh"
|
#include "olm/base64.hh"
|
||||||
#include "olm/pickle.hh"
|
#include "olm/pickle.hh"
|
||||||
|
#include "olm/memory.hh"
|
||||||
|
|
||||||
olm::Account::Account(
|
olm::Account::Account(
|
||||||
) : next_one_time_key_id(0),
|
) : next_one_time_key_id(0),
|
||||||
|
@ -26,7 +27,7 @@ olm::OneTimeKey const * olm::Account::lookup_key(
|
||||||
olm::Curve25519PublicKey const & public_key
|
olm::Curve25519PublicKey const & public_key
|
||||||
) {
|
) {
|
||||||
for (olm::OneTimeKey const & key : one_time_keys) {
|
for (olm::OneTimeKey const & key : one_time_keys) {
|
||||||
if (0 == memcmp(key.key.public_key, public_key.public_key, 32)) {
|
if (olm::array_equal(key.key.public_key, public_key.public_key)) {
|
||||||
return &key;
|
return &key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +39,7 @@ std::size_t olm::Account::remove_key(
|
||||||
) {
|
) {
|
||||||
OneTimeKey * i;
|
OneTimeKey * i;
|
||||||
for (i = one_time_keys.begin(); i != one_time_keys.end(); ++i) {
|
for (i = one_time_keys.begin(); i != one_time_keys.end(); ++i) {
|
||||||
if (0 == memcmp(i->key.public_key, public_key.public_key, 32)) {
|
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);
|
||||||
return id;
|
return id;
|
||||||
|
@ -48,7 +49,7 @@ std::size_t olm::Account::remove_key(
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t olm::Account::new_account_random_length() {
|
std::size_t olm::Account::new_account_random_length() {
|
||||||
return 2 * 32;
|
return 2 * olm::KEY_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t olm::Account::new_account(
|
std::size_t olm::Account::new_account(
|
||||||
|
@ -60,9 +61,8 @@ std::size_t olm::Account::new_account(
|
||||||
}
|
}
|
||||||
|
|
||||||
olm::ed25519_generate_key(random, identity_keys.ed25519_key);
|
olm::ed25519_generate_key(random, identity_keys.ed25519_key);
|
||||||
random += 32;
|
random += KEY_LENGTH;
|
||||||
olm::curve25519_generate_key(random, identity_keys.curve25519_key);
|
olm::curve25519_generate_key(random, identity_keys.curve25519_key);
|
||||||
random += 32;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,6 @@ std::size_t olm::Account::get_identity_json(
|
||||||
std::uint8_t * identity_json, std::size_t identity_json_length
|
std::uint8_t * identity_json, std::size_t identity_json_length
|
||||||
) {
|
) {
|
||||||
std::uint8_t * pos = identity_json;
|
std::uint8_t * pos = identity_json;
|
||||||
std::uint8_t signature[64];
|
|
||||||
size_t expected_length = get_identity_json_length();
|
size_t expected_length = get_identity_json_length();
|
||||||
|
|
||||||
if (identity_json_length < expected_length) {
|
if (identity_json_length < expected_length) {
|
||||||
|
@ -138,7 +137,7 @@ std::size_t olm::Account::get_identity_json(
|
||||||
|
|
||||||
std::size_t olm::Account::signature_length(
|
std::size_t olm::Account::signature_length(
|
||||||
) {
|
) {
|
||||||
return 64;
|
return olm::SIGNATURE_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -239,7 +238,7 @@ std::size_t olm::Account::max_number_of_one_time_keys(
|
||||||
std::size_t olm::Account::generate_one_time_keys_random_length(
|
std::size_t olm::Account::generate_one_time_keys_random_length(
|
||||||
std::size_t number_of_keys
|
std::size_t number_of_keys
|
||||||
) {
|
) {
|
||||||
return 32 * number_of_keys;
|
return olm::KEY_LENGTH * number_of_keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t olm::Account::generate_one_time_keys(
|
std::size_t olm::Account::generate_one_time_keys(
|
||||||
|
@ -255,7 +254,7 @@ std::size_t olm::Account::generate_one_time_keys(
|
||||||
key.id = ++next_one_time_key_id;
|
key.id = ++next_one_time_key_id;
|
||||||
key.published = false;
|
key.published = false;
|
||||||
olm::curve25519_generate_key(random, key.key);
|
olm::curve25519_generate_key(random, key.key);
|
||||||
random += 32;
|
random += olm::KEY_LENGTH;
|
||||||
}
|
}
|
||||||
return number_of_keys;
|
return number_of_keys;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,9 @@ olm::Cipher::~Cipher() {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static const std::size_t SHA256_LENGTH = 32;
|
|
||||||
|
|
||||||
struct DerivedKeys {
|
struct DerivedKeys {
|
||||||
olm::Aes256Key aes_key;
|
olm::Aes256Key aes_key;
|
||||||
std::uint8_t mac_key[SHA256_LENGTH];
|
std::uint8_t mac_key[olm::KEY_LENGTH];
|
||||||
olm::Aes256Iv aes_iv;
|
olm::Aes256Iv aes_iv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,16 +35,17 @@ static void derive_keys(
|
||||||
std::uint8_t const * key, std::size_t key_length,
|
std::uint8_t const * key, std::size_t key_length,
|
||||||
DerivedKeys & keys
|
DerivedKeys & keys
|
||||||
) {
|
) {
|
||||||
std::uint8_t derived_secrets[80];
|
std::uint8_t derived_secrets[2 * olm::KEY_LENGTH + olm::IV_LENGTH];
|
||||||
olm::hkdf_sha256(
|
olm::hkdf_sha256(
|
||||||
key, key_length,
|
key, key_length,
|
||||||
nullptr, 0,
|
nullptr, 0,
|
||||||
kdf_info, kdf_info_length,
|
kdf_info, kdf_info_length,
|
||||||
derived_secrets, sizeof(derived_secrets)
|
derived_secrets, sizeof(derived_secrets)
|
||||||
);
|
);
|
||||||
std::memcpy(keys.aes_key.key, derived_secrets, 32);
|
std::uint8_t const * pos = derived_secrets;
|
||||||
std::memcpy(keys.mac_key, derived_secrets + 32, 32);
|
pos = olm::load_array(keys.aes_key.key, pos);
|
||||||
std::memcpy(keys.aes_iv.iv, derived_secrets + 64, 16);
|
pos = olm::load_array(keys.mac_key, pos);
|
||||||
|
pos = olm::load_array(keys.aes_iv.iv, pos);
|
||||||
olm::unset(derived_secrets);
|
olm::unset(derived_secrets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +83,7 @@ std::size_t olm::CipherAesSha256::encrypt(
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
struct DerivedKeys keys;
|
struct DerivedKeys keys;
|
||||||
std::uint8_t mac[SHA256_LENGTH];
|
std::uint8_t mac[olm::SHA256_OUTPUT_LENGTH];
|
||||||
|
|
||||||
derive_keys(kdf_info, kdf_info_length, key, key_length, keys);
|
derive_keys(kdf_info, kdf_info_length, key, key_length, keys);
|
||||||
|
|
||||||
|
@ -93,7 +92,7 @@ std::size_t olm::CipherAesSha256::encrypt(
|
||||||
);
|
);
|
||||||
|
|
||||||
olm::hmac_sha256(
|
olm::hmac_sha256(
|
||||||
keys.mac_key, SHA256_LENGTH, output, output_length - MAC_LENGTH, mac
|
keys.mac_key, olm::KEY_LENGTH, output, output_length - MAC_LENGTH, mac
|
||||||
);
|
);
|
||||||
|
|
||||||
std::memcpy(output + output_length - MAC_LENGTH, mac, MAC_LENGTH);
|
std::memcpy(output + output_length - MAC_LENGTH, mac, MAC_LENGTH);
|
||||||
|
@ -116,12 +115,12 @@ std::size_t olm::CipherAesSha256::decrypt(
|
||||||
std::uint8_t * plaintext, std::size_t max_plaintext_length
|
std::uint8_t * plaintext, std::size_t max_plaintext_length
|
||||||
) const {
|
) const {
|
||||||
DerivedKeys keys;
|
DerivedKeys keys;
|
||||||
std::uint8_t mac[SHA256_LENGTH];
|
std::uint8_t mac[olm::SHA256_OUTPUT_LENGTH];
|
||||||
|
|
||||||
derive_keys(kdf_info, kdf_info_length, key, key_length, keys);
|
derive_keys(kdf_info, kdf_info_length, key, key_length, keys);
|
||||||
|
|
||||||
olm::hmac_sha256(
|
olm::hmac_sha256(
|
||||||
keys.mac_key, SHA256_LENGTH, input, input_length - MAC_LENGTH, mac
|
keys.mac_key, olm::KEY_LENGTH, input, input_length - MAC_LENGTH, mac
|
||||||
);
|
);
|
||||||
|
|
||||||
std::uint8_t const * input_mac = input + input_length - MAC_LENGTH;
|
std::uint8_t const * input_mac = input + input_length - MAC_LENGTH;
|
||||||
|
|
|
@ -66,8 +66,9 @@ void ed25519_keypair(
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static const std::uint8_t CURVE25519_BASEPOINT[32] = {9};
|
static const std::uint8_t CURVE25519_BASEPOINT[32] = {9};
|
||||||
|
static const std::size_t AES_KEY_SCHEDULE_LENGTH = 60;
|
||||||
|
static const std::size_t AES_KEY_BITS = 8 * olm::KEY_LENGTH;
|
||||||
static const std::size_t AES_BLOCK_LENGTH = 16;
|
static const std::size_t AES_BLOCK_LENGTH = 16;
|
||||||
static const std::size_t SHA256_HASH_LENGTH = 32;
|
|
||||||
static const std::size_t SHA256_BLOCK_LENGTH = 64;
|
static const std::size_t SHA256_BLOCK_LENGTH = 64;
|
||||||
static const std::uint8_t HKDF_DEFAULT_SALT[32] = {};
|
static const std::uint8_t HKDF_DEFAULT_SALT[32] = {};
|
||||||
|
|
||||||
|
@ -119,7 +120,7 @@ inline static void hmac_sha256_final(
|
||||||
std::uint8_t const * hmac_key,
|
std::uint8_t const * hmac_key,
|
||||||
std::uint8_t * output
|
std::uint8_t * output
|
||||||
) {
|
) {
|
||||||
std::uint8_t o_pad[SHA256_BLOCK_LENGTH + SHA256_HASH_LENGTH];
|
std::uint8_t o_pad[SHA256_BLOCK_LENGTH + olm::SHA256_OUTPUT_LENGTH];
|
||||||
std::memcpy(o_pad, hmac_key, SHA256_BLOCK_LENGTH);
|
std::memcpy(o_pad, hmac_key, SHA256_BLOCK_LENGTH);
|
||||||
for (std::size_t i = 0; i < SHA256_BLOCK_LENGTH; ++i) {
|
for (std::size_t i = 0; i < SHA256_BLOCK_LENGTH; ++i) {
|
||||||
o_pad[i] ^= 0x5C;
|
o_pad[i] ^= 0x5C;
|
||||||
|
@ -140,7 +141,7 @@ void olm::curve25519_generate_key(
|
||||||
std::uint8_t const * random_32_bytes,
|
std::uint8_t const * random_32_bytes,
|
||||||
olm::Curve25519KeyPair & key_pair
|
olm::Curve25519KeyPair & key_pair
|
||||||
) {
|
) {
|
||||||
std::memcpy(key_pair.private_key, random_32_bytes, 32);
|
std::memcpy(key_pair.private_key, random_32_bytes, KEY_LENGTH);
|
||||||
::curve25519_donna(
|
::curve25519_donna(
|
||||||
key_pair.public_key, key_pair.private_key, CURVE25519_BASEPOINT
|
key_pair.public_key, key_pair.private_key, CURVE25519_BASEPOINT
|
||||||
);
|
);
|
||||||
|
@ -161,9 +162,9 @@ void olm::curve25519_sign(
|
||||||
std::uint8_t const * message, std::size_t message_length,
|
std::uint8_t const * message, std::size_t message_length,
|
||||||
std::uint8_t * output
|
std::uint8_t * output
|
||||||
) {
|
) {
|
||||||
std::uint8_t private_key[32];
|
std::uint8_t private_key[KEY_LENGTH];
|
||||||
std::uint8_t public_key[32];
|
std::uint8_t public_key[KEY_LENGTH];
|
||||||
std::memcpy(private_key, our_key.private_key, 32);
|
std::memcpy(private_key, our_key.private_key, KEY_LENGTH);
|
||||||
::ed25519_keypair(private_key, public_key);
|
::ed25519_keypair(private_key, public_key);
|
||||||
::ed25519_sign(
|
::ed25519_sign(
|
||||||
output,
|
output,
|
||||||
|
@ -179,10 +180,10 @@ bool olm::curve25519_verify(
|
||||||
std::uint8_t const * message, std::size_t message_length,
|
std::uint8_t const * message, std::size_t message_length,
|
||||||
std::uint8_t const * signature
|
std::uint8_t const * signature
|
||||||
) {
|
) {
|
||||||
std::uint8_t public_key[32];
|
std::uint8_t public_key[KEY_LENGTH];
|
||||||
std::uint8_t signature_buffer[64];
|
std::uint8_t signature_buffer[SIGNATURE_LENGTH];
|
||||||
std::memcpy(public_key, their_key.public_key, 32);
|
std::memcpy(public_key, their_key.public_key, KEY_LENGTH);
|
||||||
std::memcpy(signature_buffer, signature, 64);
|
std::memcpy(signature_buffer, signature, SIGNATURE_LENGTH);
|
||||||
::convert_curve25519_to_ed25519(public_key, signature_buffer);
|
::convert_curve25519_to_ed25519(public_key, signature_buffer);
|
||||||
return 0 != ::ed25519_verify(
|
return 0 != ::ed25519_verify(
|
||||||
signature,
|
signature,
|
||||||
|
@ -196,7 +197,7 @@ void olm::ed25519_generate_key(
|
||||||
std::uint8_t const * random_32_bytes,
|
std::uint8_t const * random_32_bytes,
|
||||||
olm::Ed25519KeyPair & key_pair
|
olm::Ed25519KeyPair & key_pair
|
||||||
) {
|
) {
|
||||||
std::memcpy(key_pair.private_key, random_32_bytes, 32);
|
std::memcpy(key_pair.private_key, random_32_bytes, KEY_LENGTH);
|
||||||
::ed25519_keypair(key_pair.private_key, key_pair.public_key);
|
::ed25519_keypair(key_pair.private_key, key_pair.public_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,13 +241,13 @@ void olm::aes_encrypt_cbc(
|
||||||
std::uint8_t const * input, std::size_t input_length,
|
std::uint8_t const * input, std::size_t input_length,
|
||||||
std::uint8_t * output
|
std::uint8_t * output
|
||||||
) {
|
) {
|
||||||
std::uint32_t key_schedule[60];
|
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
|
||||||
::aes_key_setup(key.key, key_schedule, 256);
|
::aes_key_setup(key.key, key_schedule, AES_KEY_BITS);
|
||||||
std::uint8_t input_block[AES_BLOCK_LENGTH];
|
std::uint8_t input_block[AES_BLOCK_LENGTH];
|
||||||
std::memcpy(input_block, iv.iv, AES_BLOCK_LENGTH);
|
std::memcpy(input_block, iv.iv, AES_BLOCK_LENGTH);
|
||||||
while (input_length >= AES_BLOCK_LENGTH) {
|
while (input_length >= AES_BLOCK_LENGTH) {
|
||||||
xor_block<AES_BLOCK_LENGTH>(input_block, input);
|
xor_block<AES_BLOCK_LENGTH>(input_block, input);
|
||||||
::aes_encrypt(input_block, output, key_schedule, 256);
|
::aes_encrypt(input_block, output, key_schedule, AES_KEY_BITS);
|
||||||
std::memcpy(input_block, output, AES_BLOCK_LENGTH);
|
std::memcpy(input_block, output, AES_BLOCK_LENGTH);
|
||||||
input += AES_BLOCK_LENGTH;
|
input += AES_BLOCK_LENGTH;
|
||||||
output += AES_BLOCK_LENGTH;
|
output += AES_BLOCK_LENGTH;
|
||||||
|
@ -259,7 +260,7 @@ void olm::aes_encrypt_cbc(
|
||||||
for (; i < AES_BLOCK_LENGTH; ++i) {
|
for (; i < AES_BLOCK_LENGTH; ++i) {
|
||||||
input_block[i] ^= AES_BLOCK_LENGTH - input_length;
|
input_block[i] ^= AES_BLOCK_LENGTH - input_length;
|
||||||
}
|
}
|
||||||
::aes_encrypt(input_block, output, key_schedule, 256);
|
::aes_encrypt(input_block, output, key_schedule, AES_KEY_BITS);
|
||||||
olm::unset(key_schedule);
|
olm::unset(key_schedule);
|
||||||
olm::unset(input_block);
|
olm::unset(input_block);
|
||||||
}
|
}
|
||||||
|
@ -271,14 +272,14 @@ std::size_t olm::aes_decrypt_cbc(
|
||||||
std::uint8_t const * input, std::size_t input_length,
|
std::uint8_t const * input, std::size_t input_length,
|
||||||
std::uint8_t * output
|
std::uint8_t * output
|
||||||
) {
|
) {
|
||||||
std::uint32_t key_schedule[60];
|
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
|
||||||
::aes_key_setup(key.key, key_schedule, 256);
|
::aes_key_setup(key.key, key_schedule, AES_KEY_BITS);
|
||||||
std::uint8_t block1[AES_BLOCK_LENGTH];
|
std::uint8_t block1[AES_BLOCK_LENGTH];
|
||||||
std::uint8_t block2[AES_BLOCK_LENGTH];
|
std::uint8_t block2[AES_BLOCK_LENGTH];
|
||||||
std::memcpy(block1, iv.iv, AES_BLOCK_LENGTH);
|
std::memcpy(block1, iv.iv, AES_BLOCK_LENGTH);
|
||||||
for (std::size_t i = 0; i < input_length; i += AES_BLOCK_LENGTH) {
|
for (std::size_t i = 0; i < input_length; i += AES_BLOCK_LENGTH) {
|
||||||
std::memcpy(block2, &input[i], AES_BLOCK_LENGTH);
|
std::memcpy(block2, &input[i], AES_BLOCK_LENGTH);
|
||||||
::aes_decrypt(&input[i], &output[i], key_schedule, 256);
|
::aes_decrypt(&input[i], &output[i], key_schedule, AES_KEY_BITS);
|
||||||
xor_block<AES_BLOCK_LENGTH>(&output[i], block1);
|
xor_block<AES_BLOCK_LENGTH>(&output[i], block1);
|
||||||
std::memcpy(block1, block2, AES_BLOCK_LENGTH);
|
std::memcpy(block1, block2, AES_BLOCK_LENGTH);
|
||||||
}
|
}
|
||||||
|
@ -301,6 +302,7 @@ void olm::sha256(
|
||||||
olm::unset(context);
|
olm::unset(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void olm::hmac_sha256(
|
void olm::hmac_sha256(
|
||||||
std::uint8_t const * key, std::size_t key_length,
|
std::uint8_t const * key, std::size_t key_length,
|
||||||
std::uint8_t const * input, std::size_t input_length,
|
std::uint8_t const * input, std::size_t input_length,
|
||||||
|
@ -325,7 +327,7 @@ void olm::hkdf_sha256(
|
||||||
) {
|
) {
|
||||||
::SHA256_CTX context;
|
::SHA256_CTX context;
|
||||||
std::uint8_t hmac_key[SHA256_BLOCK_LENGTH];
|
std::uint8_t hmac_key[SHA256_BLOCK_LENGTH];
|
||||||
std::uint8_t step_result[SHA256_HASH_LENGTH];
|
std::uint8_t step_result[olm::SHA256_OUTPUT_LENGTH];
|
||||||
std::size_t bytes_remaining = output_length;
|
std::size_t bytes_remaining = output_length;
|
||||||
std::uint8_t iteration = 1;
|
std::uint8_t iteration = 1;
|
||||||
if (!salt) {
|
if (!salt) {
|
||||||
|
@ -337,20 +339,20 @@ void olm::hkdf_sha256(
|
||||||
hmac_sha256_init(&context, hmac_key);
|
hmac_sha256_init(&context, hmac_key);
|
||||||
::sha256_update(&context, input, input_length);
|
::sha256_update(&context, input, input_length);
|
||||||
hmac_sha256_final(&context, hmac_key, step_result);
|
hmac_sha256_final(&context, hmac_key, step_result);
|
||||||
hmac_sha256_key(step_result, SHA256_HASH_LENGTH, hmac_key);
|
hmac_sha256_key(step_result, olm::SHA256_OUTPUT_LENGTH, hmac_key);
|
||||||
|
|
||||||
/* Extract */
|
/* Extract */
|
||||||
hmac_sha256_init(&context, hmac_key);
|
hmac_sha256_init(&context, hmac_key);
|
||||||
::sha256_update(&context, info, info_length);
|
::sha256_update(&context, info, info_length);
|
||||||
::sha256_update(&context, &iteration, 1);
|
::sha256_update(&context, &iteration, 1);
|
||||||
hmac_sha256_final(&context, hmac_key, step_result);
|
hmac_sha256_final(&context, hmac_key, step_result);
|
||||||
while (bytes_remaining > SHA256_HASH_LENGTH) {
|
while (bytes_remaining > olm::SHA256_OUTPUT_LENGTH) {
|
||||||
std::memcpy(output, step_result, SHA256_HASH_LENGTH);
|
std::memcpy(output, step_result, olm::SHA256_OUTPUT_LENGTH);
|
||||||
output += SHA256_HASH_LENGTH;
|
output += olm::SHA256_OUTPUT_LENGTH;
|
||||||
bytes_remaining -= SHA256_HASH_LENGTH;
|
bytes_remaining -= olm::SHA256_OUTPUT_LENGTH;
|
||||||
iteration ++;
|
iteration ++;
|
||||||
hmac_sha256_init(&context, hmac_key);
|
hmac_sha256_init(&context, hmac_key);
|
||||||
::sha256_update(&context, step_result, SHA256_HASH_LENGTH);
|
::sha256_update(&context, step_result, olm::SHA256_OUTPUT_LENGTH);
|
||||||
::sha256_update(&context, info, info_length);
|
::sha256_update(&context, info, info_length);
|
||||||
::sha256_update(&context, &iteration, 1);
|
::sha256_update(&context, &iteration, 1);
|
||||||
hmac_sha256_final(&context, hmac_key, step_result);
|
hmac_sha256_final(&context, hmac_key, step_result);
|
||||||
|
|
47
src/olm.cpp
47
src/olm.cpp
|
@ -520,8 +520,13 @@ size_t olm_create_outbound_session(
|
||||||
void const * their_one_time_key, size_t their_one_time_key_length,
|
void const * their_one_time_key, size_t their_one_time_key_length,
|
||||||
void * random, size_t random_length
|
void * random, size_t random_length
|
||||||
) {
|
) {
|
||||||
if (olm::decode_base64_length(their_identity_key_length) != 32
|
std::uint8_t const * id_key = from_c(their_identity_key);
|
||||||
|| olm::decode_base64_length(their_one_time_key_length) != 32
|
std::uint8_t const * ot_key = from_c(their_one_time_key);
|
||||||
|
std::size_t id_key_length = their_identity_key_length;
|
||||||
|
std::size_t ot_key_length = their_one_time_key_length;
|
||||||
|
|
||||||
|
if (olm::decode_base64_length(id_key_length) != olm::KEY_LENGTH
|
||||||
|
|| olm::decode_base64_length(ot_key_length) != olm::KEY_LENGTH
|
||||||
) {
|
) {
|
||||||
from_c(session)->last_error = olm::ErrorCode::INVALID_BASE64;
|
from_c(session)->last_error = olm::ErrorCode::INVALID_BASE64;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
|
@ -529,14 +534,8 @@ size_t olm_create_outbound_session(
|
||||||
olm::Curve25519PublicKey identity_key;
|
olm::Curve25519PublicKey identity_key;
|
||||||
olm::Curve25519PublicKey one_time_key;
|
olm::Curve25519PublicKey one_time_key;
|
||||||
|
|
||||||
olm::decode_base64(
|
olm::decode_base64(id_key, id_key_length, identity_key.public_key);
|
||||||
from_c(their_identity_key), their_identity_key_length,
|
olm::decode_base64(ot_key, ot_key_length, one_time_key.public_key);
|
||||||
identity_key.public_key
|
|
||||||
);
|
|
||||||
olm::decode_base64(
|
|
||||||
from_c(their_one_time_key), their_one_time_key_length,
|
|
||||||
one_time_key.public_key
|
|
||||||
);
|
|
||||||
|
|
||||||
size_t result = from_c(session)->new_outbound_session(
|
size_t result = from_c(session)->new_outbound_session(
|
||||||
*from_c(account), identity_key, one_time_key,
|
*from_c(account), identity_key, one_time_key,
|
||||||
|
@ -570,15 +569,15 @@ size_t olm_create_inbound_session_from(
|
||||||
void const * their_identity_key, size_t their_identity_key_length,
|
void const * their_identity_key, size_t their_identity_key_length,
|
||||||
void * one_time_key_message, size_t message_length
|
void * one_time_key_message, size_t message_length
|
||||||
) {
|
) {
|
||||||
if (olm::decode_base64_length(their_identity_key_length) != 32) {
|
std::uint8_t const * id_key = from_c(their_identity_key);
|
||||||
|
std::size_t id_key_length = their_identity_key_length;
|
||||||
|
|
||||||
|
if (olm::decode_base64_length(id_key_length) != olm::KEY_LENGTH) {
|
||||||
from_c(session)->last_error = olm::ErrorCode::INVALID_BASE64;
|
from_c(session)->last_error = olm::ErrorCode::INVALID_BASE64;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
olm::Curve25519PublicKey identity_key;
|
olm::Curve25519PublicKey identity_key;
|
||||||
olm::decode_base64(
|
olm::decode_base64(id_key, id_key_length, identity_key.public_key);
|
||||||
from_c(their_identity_key), their_identity_key_length,
|
|
||||||
identity_key.public_key
|
|
||||||
);
|
|
||||||
|
|
||||||
std::size_t raw_length = b64_input(
|
std::size_t raw_length = b64_input(
|
||||||
from_c(one_time_key_message), message_length, from_c(session)->last_error
|
from_c(one_time_key_message), message_length, from_c(session)->last_error
|
||||||
|
@ -641,15 +640,15 @@ size_t olm_matches_inbound_session_from(
|
||||||
void const * their_identity_key, size_t their_identity_key_length,
|
void const * their_identity_key, size_t their_identity_key_length,
|
||||||
void * one_time_key_message, size_t message_length
|
void * one_time_key_message, size_t message_length
|
||||||
) {
|
) {
|
||||||
if (olm::decode_base64_length(their_identity_key_length) != 32) {
|
std::uint8_t const * id_key = from_c(their_identity_key);
|
||||||
|
std::size_t id_key_length = their_identity_key_length;
|
||||||
|
|
||||||
|
if (olm::decode_base64_length(id_key_length) != olm::KEY_LENGTH) {
|
||||||
from_c(session)->last_error = olm::ErrorCode::INVALID_BASE64;
|
from_c(session)->last_error = olm::ErrorCode::INVALID_BASE64;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
olm::Curve25519PublicKey identity_key;
|
olm::Curve25519PublicKey identity_key;
|
||||||
olm::decode_base64(
|
olm::decode_base64(id_key, id_key_length, identity_key.public_key);
|
||||||
from_c(their_identity_key), their_identity_key_length,
|
|
||||||
identity_key.public_key
|
|
||||||
);
|
|
||||||
|
|
||||||
std::size_t raw_length = b64_input(
|
std::size_t raw_length = b64_input(
|
||||||
from_c(one_time_key_message), message_length, from_c(session)->last_error
|
from_c(one_time_key_message), message_length, from_c(session)->last_error
|
||||||
|
@ -800,15 +799,12 @@ size_t olm_ed25519_verify(
|
||||||
void const * message, size_t message_length,
|
void const * message, size_t message_length,
|
||||||
void * signature, size_t signature_length
|
void * signature, size_t signature_length
|
||||||
) {
|
) {
|
||||||
if (olm::decode_base64_length(key_length) != 32) {
|
if (olm::decode_base64_length(key_length) != olm::KEY_LENGTH) {
|
||||||
from_c(utility)->last_error = olm::ErrorCode::INVALID_BASE64;
|
from_c(utility)->last_error = olm::ErrorCode::INVALID_BASE64;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
olm::Ed25519PublicKey verify_key;
|
olm::Ed25519PublicKey verify_key;
|
||||||
olm::decode_base64(
|
olm::decode_base64(from_c(key), key_length, verify_key.public_key);
|
||||||
from_c(key), key_length,
|
|
||||||
verify_key.public_key
|
|
||||||
);
|
|
||||||
std::size_t raw_signature_length = b64_input(
|
std::size_t raw_signature_length = b64_input(
|
||||||
from_c(signature), signature_length, from_c(utility)->last_error
|
from_c(signature), signature_length, from_c(utility)->last_error
|
||||||
);
|
);
|
||||||
|
@ -822,5 +818,4 @@ size_t olm_ed25519_verify(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,10 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::uint8_t PROTOCOL_VERSION = 3;
|
static const std::uint8_t PROTOCOL_VERSION = 3;
|
||||||
std::size_t KEY_LENGTH = olm::Curve25519PublicKey::LENGTH;
|
static const std::uint8_t MESSAGE_KEY_SEED[1] = {0x01};
|
||||||
std::uint8_t MESSAGE_KEY_SEED[1] = {0x01};
|
static const std::uint8_t CHAIN_KEY_SEED[1] = {0x02};
|
||||||
std::uint8_t CHAIN_KEY_SEED[1] = {0x02};
|
static const std::size_t MAX_MESSAGE_GAP = 2000;
|
||||||
std::size_t MAX_MESSAGE_GAP = 2000;
|
|
||||||
|
|
||||||
static void create_chain_key(
|
static void create_chain_key(
|
||||||
olm::SharedKey const & root_key,
|
olm::SharedKey const & root_key,
|
||||||
|
@ -39,15 +38,16 @@ static void create_chain_key(
|
||||||
) {
|
) {
|
||||||
olm::SharedKey secret;
|
olm::SharedKey secret;
|
||||||
olm::curve25519_shared_secret(our_key, their_key, secret);
|
olm::curve25519_shared_secret(our_key, their_key, secret);
|
||||||
std::uint8_t derived_secrets[64];
|
std::uint8_t derived_secrets[2 * olm::KEY_LENGTH];
|
||||||
olm::hkdf_sha256(
|
olm::hkdf_sha256(
|
||||||
secret, sizeof(secret),
|
secret, sizeof(secret),
|
||||||
root_key, sizeof(root_key),
|
root_key, sizeof(root_key),
|
||||||
info.ratchet_info, info.ratchet_info_length,
|
info.ratchet_info, info.ratchet_info_length,
|
||||||
derived_secrets, sizeof(derived_secrets)
|
derived_secrets, sizeof(derived_secrets)
|
||||||
);
|
);
|
||||||
std::memcpy(new_root_key, derived_secrets, 32);
|
std::uint8_t const * pos = derived_secrets;
|
||||||
std::memcpy(new_chain_key.key, derived_secrets + 32, 32);
|
pos = olm::load_array(new_root_key, pos);
|
||||||
|
pos = olm::load_array(new_chain_key.key, pos);
|
||||||
new_chain_key.index = 0;
|
new_chain_key.index = 0;
|
||||||
olm::unset(derived_secrets);
|
olm::unset(derived_secrets);
|
||||||
olm::unset(secret);
|
olm::unset(secret);
|
||||||
|
@ -148,9 +148,7 @@ static std::size_t verify_mac_and_decrypt_for_new_chain(
|
||||||
if (reader.counter > MAX_MESSAGE_GAP) {
|
if (reader.counter > MAX_MESSAGE_GAP) {
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
std::memcpy(
|
olm::load_array(new_chain.ratchet_key.public_key, reader.ratchet_key);
|
||||||
new_chain.ratchet_key.public_key, reader.ratchet_key, KEY_LENGTH
|
|
||||||
);
|
|
||||||
|
|
||||||
create_chain_key(
|
create_chain_key(
|
||||||
session.root_key, session.sender_chain[0].ratchet_key,
|
session.root_key, session.sender_chain[0].ratchet_key,
|
||||||
|
@ -183,7 +181,7 @@ void olm::Ratchet::initialise_as_bob(
|
||||||
std::uint8_t const * shared_secret, std::size_t shared_secret_length,
|
std::uint8_t const * shared_secret, std::size_t shared_secret_length,
|
||||||
olm::Curve25519PublicKey const & their_ratchet_key
|
olm::Curve25519PublicKey const & their_ratchet_key
|
||||||
) {
|
) {
|
||||||
std::uint8_t derived_secrets[64];
|
std::uint8_t derived_secrets[2 * olm::KEY_LENGTH];
|
||||||
olm::hkdf_sha256(
|
olm::hkdf_sha256(
|
||||||
shared_secret, shared_secret_length,
|
shared_secret, shared_secret_length,
|
||||||
nullptr, 0,
|
nullptr, 0,
|
||||||
|
@ -192,8 +190,9 @@ void olm::Ratchet::initialise_as_bob(
|
||||||
);
|
);
|
||||||
receiver_chains.insert();
|
receiver_chains.insert();
|
||||||
receiver_chains[0].chain_key.index = 0;
|
receiver_chains[0].chain_key.index = 0;
|
||||||
std::memcpy(root_key, derived_secrets, 32);
|
std::uint8_t const * pos = derived_secrets;
|
||||||
std::memcpy(receiver_chains[0].chain_key.key, derived_secrets + 32, 32);
|
pos = olm::load_array(root_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;
|
||||||
olm::unset(derived_secrets);
|
olm::unset(derived_secrets);
|
||||||
}
|
}
|
||||||
|
@ -203,7 +202,7 @@ void olm::Ratchet::initialise_as_alice(
|
||||||
std::uint8_t const * shared_secret, std::size_t shared_secret_length,
|
std::uint8_t const * shared_secret, std::size_t shared_secret_length,
|
||||||
olm::Curve25519KeyPair const & our_ratchet_key
|
olm::Curve25519KeyPair const & our_ratchet_key
|
||||||
) {
|
) {
|
||||||
std::uint8_t derived_secrets[64];
|
std::uint8_t derived_secrets[2 * olm::KEY_LENGTH];
|
||||||
olm::hkdf_sha256(
|
olm::hkdf_sha256(
|
||||||
shared_secret, shared_secret_length,
|
shared_secret, shared_secret_length,
|
||||||
nullptr, 0,
|
nullptr, 0,
|
||||||
|
@ -212,8 +211,9 @@ void olm::Ratchet::initialise_as_alice(
|
||||||
);
|
);
|
||||||
sender_chain.insert();
|
sender_chain.insert();
|
||||||
sender_chain[0].chain_key.index = 0;
|
sender_chain[0].chain_key.index = 0;
|
||||||
std::memcpy(root_key, derived_secrets, 32);
|
std::uint8_t const * pos = derived_secrets;
|
||||||
std::memcpy(sender_chain[0].chain_key.key, derived_secrets + 32, 32);
|
pos = olm::load_array(root_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;
|
||||||
olm::unset(derived_secrets);
|
olm::unset(derived_secrets);
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ namespace olm {
|
||||||
static std::size_t pickle_length(
|
static std::size_t pickle_length(
|
||||||
const olm::SharedKey & value
|
const olm::SharedKey & value
|
||||||
) {
|
) {
|
||||||
return KEY_LENGTH;
|
return olm::KEY_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ static std::uint8_t * pickle(
|
||||||
std::uint8_t * pos,
|
std::uint8_t * pos,
|
||||||
const olm::SharedKey & value
|
const olm::SharedKey & value
|
||||||
) {
|
) {
|
||||||
return olm::pickle_bytes(pos, value, KEY_LENGTH);
|
return olm::pickle_bytes(pos, value, olm::KEY_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ static std::uint8_t const * unpickle(
|
||||||
std::uint8_t const * pos, std::uint8_t const * end,
|
std::uint8_t const * pos, std::uint8_t const * end,
|
||||||
olm::SharedKey & value
|
olm::SharedKey & value
|
||||||
) {
|
) {
|
||||||
return olm::unpickle_bytes(pos, end, value, KEY_LENGTH);
|
return olm::unpickle_bytes(pos, end, value, olm::KEY_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -349,7 +349,7 @@ std::size_t olm::pickle_length(
|
||||||
olm::Ratchet const & value
|
olm::Ratchet const & value
|
||||||
) {
|
) {
|
||||||
std::size_t length = 0;
|
std::size_t length = 0;
|
||||||
length += KEY_LENGTH;
|
length += olm::KEY_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);
|
||||||
|
@ -391,13 +391,13 @@ std::size_t olm::Ratchet::encrypt_output_length(
|
||||||
plaintext_length
|
plaintext_length
|
||||||
);
|
);
|
||||||
return olm::encode_message_length(
|
return olm::encode_message_length(
|
||||||
counter, KEY_LENGTH, padded, ratchet_cipher.mac_length()
|
counter, olm::KEY_LENGTH, padded, ratchet_cipher.mac_length()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::size_t olm::Ratchet::encrypt_random_length() {
|
std::size_t olm::Ratchet::encrypt_random_length() {
|
||||||
return sender_chain.empty() ? KEY_LENGTH : 0;
|
return sender_chain.empty() ? olm::KEY_LENGTH : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -442,10 +442,11 @@ std::size_t olm::Ratchet::encrypt(
|
||||||
olm::MessageWriter writer;
|
olm::MessageWriter writer;
|
||||||
|
|
||||||
olm::encode_message(
|
olm::encode_message(
|
||||||
writer, PROTOCOL_VERSION, counter, KEY_LENGTH, ciphertext_length, output
|
writer, PROTOCOL_VERSION, counter, olm::KEY_LENGTH, ciphertext_length,
|
||||||
|
output
|
||||||
);
|
);
|
||||||
|
|
||||||
std::memcpy(writer.ratchet_key, ratchet_key.public_key, KEY_LENGTH);
|
olm::store_array(writer.ratchet_key, ratchet_key.public_key);
|
||||||
|
|
||||||
ratchet_cipher.encrypt(
|
ratchet_cipher.encrypt(
|
||||||
keys.key, sizeof(keys.key),
|
keys.key, sizeof(keys.key),
|
||||||
|
@ -504,7 +505,7 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reader.ratchet_key_length != KEY_LENGTH) {
|
if (reader.ratchet_key_length != olm::KEY_LENGTH) {
|
||||||
last_error = olm::ErrorCode::BAD_MESSAGE_FORMAT;
|
last_error = olm::ErrorCode::BAD_MESSAGE_FORMAT;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
@ -513,7 +514,7 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
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,
|
||||||
KEY_LENGTH
|
olm::KEY_LENGTH
|
||||||
)) {
|
)) {
|
||||||
chain = &receiver_chain;
|
chain = &receiver_chain;
|
||||||
break;
|
break;
|
||||||
|
@ -533,7 +534,7 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
if (reader.counter == skipped.message_key.index
|
if (reader.counter == skipped.message_key.index
|
||||||
&& 0 == std::memcmp(
|
&& 0 == std::memcmp(
|
||||||
skipped.ratchet_key.public_key, reader.ratchet_key,
|
skipped.ratchet_key.public_key, reader.ratchet_key,
|
||||||
KEY_LENGTH
|
olm::KEY_LENGTH
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
/* Found the key for this message. Check the MAC. */
|
/* Found the key for this message. Check the MAC. */
|
||||||
|
@ -569,9 +570,7 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
* 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();
|
||||||
std::memcpy(
|
olm::load_array(chain->ratchet_key.public_key, reader.ratchet_key);
|
||||||
chain->ratchet_key.public_key, reader.ratchet_key, KEY_LENGTH
|
|
||||||
);
|
|
||||||
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
|
||||||
|
|
123
src/session.cpp
123
src/session.cpp
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static const std::size_t KEY_LENGTH = 32;
|
|
||||||
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";
|
||||||
|
@ -51,7 +50,7 @@ olm::Session::Session(
|
||||||
|
|
||||||
|
|
||||||
std::size_t olm::Session::new_outbound_session_random_length() {
|
std::size_t olm::Session::new_outbound_session_random_length() {
|
||||||
return KEY_LENGTH * 2;
|
return olm::KEY_LENGTH * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,35 +65,35 @@ std::size_t olm::Session::new_outbound_session(
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Curve25519KeyPair base_key;
|
olm::Curve25519KeyPair base_key;
|
||||||
olm::curve25519_generate_key(random, base_key);
|
olm::curve25519_generate_key(random, base_key);
|
||||||
|
|
||||||
Curve25519KeyPair ratchet_key;
|
olm::Curve25519KeyPair ratchet_key;
|
||||||
olm::curve25519_generate_key(random + 32, ratchet_key);
|
olm::curve25519_generate_key(random + olm::KEY_LENGTH, ratchet_key);
|
||||||
|
|
||||||
|
olm::Curve25519KeyPair const & alice_identity_key_pair = (
|
||||||
|
local_account.identity_keys.curve25519_key
|
||||||
|
);
|
||||||
|
|
||||||
received_message = false;
|
received_message = false;
|
||||||
alice_identity_key = local_account.identity_keys.curve25519_key;
|
alice_identity_key = alice_identity_key_pair;
|
||||||
alice_base_key = base_key;
|
alice_base_key = base_key;
|
||||||
bob_one_time_key = one_time_key;
|
bob_one_time_key = one_time_key;
|
||||||
|
|
||||||
std::uint8_t shared_secret[96];
|
std::uint8_t secret[3 * olm::KEY_LENGTH];
|
||||||
|
std::uint8_t * pos = secret;
|
||||||
|
|
||||||
olm::curve25519_shared_secret(
|
olm::curve25519_shared_secret(alice_identity_key_pair, one_time_key, pos);
|
||||||
local_account.identity_keys.curve25519_key,
|
pos += olm::KEY_LENGTH;
|
||||||
one_time_key, shared_secret
|
olm::curve25519_shared_secret(base_key, identity_key, pos);
|
||||||
);
|
pos += olm::KEY_LENGTH;
|
||||||
olm::curve25519_shared_secret(
|
olm::curve25519_shared_secret(base_key, one_time_key, pos);
|
||||||
base_key, identity_key, shared_secret + 32
|
|
||||||
);
|
|
||||||
olm::curve25519_shared_secret(
|
|
||||||
base_key, one_time_key, shared_secret + 64
|
|
||||||
);
|
|
||||||
|
|
||||||
ratchet.initialise_as_alice(shared_secret, 96, ratchet_key);
|
ratchet.initialise_as_alice(secret, sizeof(secret), ratchet_key);
|
||||||
|
|
||||||
olm::unset(base_key);
|
olm::unset(base_key);
|
||||||
olm::unset(ratchet_key);
|
olm::unset(ratchet_key);
|
||||||
olm::unset(shared_secret);
|
olm::unset(secret);
|
||||||
|
|
||||||
return std::size_t(0);
|
return std::size_t(0);
|
||||||
}
|
}
|
||||||
|
@ -107,13 +106,13 @@ static bool check_message_fields(
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
ok = ok && (have_their_identity_key || reader.identity_key);
|
ok = ok && (have_their_identity_key || reader.identity_key);
|
||||||
if (reader.identity_key) {
|
if (reader.identity_key) {
|
||||||
ok = ok && reader.identity_key_length == KEY_LENGTH;
|
ok = ok && reader.identity_key_length == olm::KEY_LENGTH;
|
||||||
}
|
}
|
||||||
ok = ok && reader.message;
|
ok = ok && reader.message;
|
||||||
ok = ok && reader.base_key;
|
ok = ok && reader.base_key;
|
||||||
ok = ok && reader.base_key_length == KEY_LENGTH;
|
ok = ok && reader.base_key_length == olm::KEY_LENGTH;
|
||||||
ok = ok && reader.one_time_key;
|
ok = ok && reader.one_time_key;
|
||||||
ok = ok && reader.one_time_key_length == KEY_LENGTH;
|
ok = ok && reader.one_time_key_length == olm::KEY_LENGTH;
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +134,7 @@ std::size_t olm::Session::new_inbound_session(
|
||||||
|
|
||||||
if (reader.identity_key && their_identity_key) {
|
if (reader.identity_key && their_identity_key) {
|
||||||
bool same = 0 == std::memcmp(
|
bool same = 0 == std::memcmp(
|
||||||
their_identity_key->public_key, reader.identity_key, KEY_LENGTH
|
their_identity_key->public_key, reader.identity_key, olm::KEY_LENGTH
|
||||||
);
|
);
|
||||||
if (!same) {
|
if (!same) {
|
||||||
last_error = olm::ErrorCode::BAD_MESSAGE_KEY_ID;
|
last_error = olm::ErrorCode::BAD_MESSAGE_KEY_ID;
|
||||||
|
@ -150,16 +149,16 @@ std::size_t olm::Session::new_inbound_session(
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!message_reader.ratchet_key
|
if (!message_reader.ratchet_key
|
||||||
|| message_reader.ratchet_key_length != KEY_LENGTH) {
|
|| message_reader.ratchet_key_length != olm::KEY_LENGTH) {
|
||||||
last_error = olm::ErrorCode::BAD_MESSAGE_FORMAT;
|
last_error = olm::ErrorCode::BAD_MESSAGE_FORMAT;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(alice_identity_key.public_key, reader.identity_key, 32);
|
olm::load_array(alice_identity_key.public_key, reader.identity_key);
|
||||||
std::memcpy(alice_base_key.public_key, reader.base_key, 32);
|
olm::load_array(alice_base_key.public_key, reader.base_key);
|
||||||
std::memcpy(bob_one_time_key.public_key, reader.one_time_key, 32);
|
olm::load_array(bob_one_time_key.public_key, reader.one_time_key);
|
||||||
olm::Curve25519PublicKey ratchet_key;
|
olm::Curve25519PublicKey ratchet_key;
|
||||||
std::memcpy(ratchet_key.public_key, message_reader.ratchet_key, 32);
|
olm::load_array(ratchet_key.public_key, message_reader.ratchet_key);
|
||||||
|
|
||||||
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
|
||||||
|
@ -170,27 +169,28 @@ std::size_t olm::Session::new_inbound_session(
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint8_t shared_secret[96];
|
olm::Curve25519KeyPair const & bob_identity_key = (
|
||||||
|
local_account.identity_keys.curve25519_key
|
||||||
olm::curve25519_shared_secret(
|
|
||||||
our_one_time_key->key, alice_identity_key, shared_secret
|
|
||||||
);
|
|
||||||
olm::curve25519_shared_secret(
|
|
||||||
local_account.identity_keys.curve25519_key,
|
|
||||||
alice_base_key, shared_secret + 32
|
|
||||||
);
|
|
||||||
olm::curve25519_shared_secret(
|
|
||||||
our_one_time_key->key, alice_base_key, shared_secret + 64
|
|
||||||
);
|
);
|
||||||
|
olm::Curve25519KeyPair const & bob_one_time_key = our_one_time_key->key;
|
||||||
|
|
||||||
ratchet.initialise_as_bob(shared_secret, 96, ratchet_key);
|
std::uint8_t secret[olm::KEY_LENGTH * 3];
|
||||||
|
std::uint8_t * pos = secret;
|
||||||
|
olm::curve25519_shared_secret(bob_one_time_key, alice_identity_key, pos);
|
||||||
|
pos += olm::KEY_LENGTH;
|
||||||
|
olm::curve25519_shared_secret(bob_identity_key, alice_base_key, pos);
|
||||||
|
pos += olm::KEY_LENGTH;
|
||||||
|
olm::curve25519_shared_secret(bob_one_time_key, alice_base_key, pos);
|
||||||
|
|
||||||
|
ratchet.initialise_as_bob(secret, sizeof(secret), ratchet_key);
|
||||||
|
|
||||||
|
olm::unset(secret);
|
||||||
return std::size_t(0);
|
return std::size_t(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::size_t olm::Session::session_id_length() {
|
std::size_t olm::Session::session_id_length() {
|
||||||
return 32;
|
return olm::SHA256_OUTPUT_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -201,10 +201,11 @@ std::size_t olm::Session::session_id(
|
||||||
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);
|
||||||
}
|
}
|
||||||
std::uint8_t tmp[96];
|
std::uint8_t tmp[olm::KEY_LENGTH * 3];
|
||||||
std::memcpy(tmp, alice_identity_key.public_key, 32);
|
std::uint8_t * pos = tmp;
|
||||||
std::memcpy(tmp + 32, alice_base_key.public_key, 32);
|
pos = olm::store_array(pos, alice_identity_key.public_key);
|
||||||
std::memcpy(tmp + 64, bob_one_time_key.public_key, 32);
|
pos = olm::store_array(pos, alice_base_key.public_key);
|
||||||
|
pos = olm::store_array(pos, bob_one_time_key.public_key);
|
||||||
olm::sha256(tmp, sizeof(tmp), id);
|
olm::sha256(tmp, sizeof(tmp), id);
|
||||||
return session_id_length();
|
return session_id_length();
|
||||||
}
|
}
|
||||||
|
@ -224,20 +225,20 @@ bool olm::Session::matches_inbound_session(
|
||||||
bool same = true;
|
bool same = true;
|
||||||
if (reader.identity_key) {
|
if (reader.identity_key) {
|
||||||
same = same && 0 == std::memcmp(
|
same = same && 0 == std::memcmp(
|
||||||
reader.identity_key, alice_identity_key.public_key, KEY_LENGTH
|
reader.identity_key, alice_identity_key.public_key, olm::KEY_LENGTH
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (their_identity_key) {
|
if (their_identity_key) {
|
||||||
same = same && 0 == std::memcmp(
|
same = same && 0 == std::memcmp(
|
||||||
their_identity_key->public_key, alice_identity_key.public_key,
|
their_identity_key->public_key, alice_identity_key.public_key,
|
||||||
KEY_LENGTH
|
olm::KEY_LENGTH
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
same = same && 0 == std::memcmp(
|
same = same && 0 == std::memcmp(
|
||||||
reader.base_key, alice_base_key.public_key, KEY_LENGTH
|
reader.base_key, alice_base_key.public_key, olm::KEY_LENGTH
|
||||||
);
|
);
|
||||||
same = same && 0 == std::memcmp(
|
same = same && 0 == std::memcmp(
|
||||||
reader.one_time_key, bob_one_time_key.public_key, KEY_LENGTH
|
reader.one_time_key, bob_one_time_key.public_key, olm::KEY_LENGTH
|
||||||
);
|
);
|
||||||
return same;
|
return same;
|
||||||
}
|
}
|
||||||
|
@ -264,9 +265,9 @@ std::size_t olm::Session::encrypt_message_length(
|
||||||
}
|
}
|
||||||
|
|
||||||
return encode_one_time_key_message_length(
|
return encode_one_time_key_message_length(
|
||||||
KEY_LENGTH,
|
olm::KEY_LENGTH,
|
||||||
KEY_LENGTH,
|
olm::KEY_LENGTH,
|
||||||
KEY_LENGTH,
|
olm::KEY_LENGTH,
|
||||||
message_length
|
message_length
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -298,21 +299,15 @@ std::size_t olm::Session::encrypt(
|
||||||
encode_one_time_key_message(
|
encode_one_time_key_message(
|
||||||
writer,
|
writer,
|
||||||
PROTOCOL_VERSION,
|
PROTOCOL_VERSION,
|
||||||
KEY_LENGTH,
|
olm::KEY_LENGTH,
|
||||||
KEY_LENGTH,
|
olm::KEY_LENGTH,
|
||||||
KEY_LENGTH,
|
olm::KEY_LENGTH,
|
||||||
message_body_length,
|
message_body_length,
|
||||||
message
|
message
|
||||||
);
|
);
|
||||||
std::memcpy(
|
olm::store_array(writer.one_time_key, bob_one_time_key.public_key);
|
||||||
writer.one_time_key, bob_one_time_key.public_key, KEY_LENGTH
|
olm::store_array(writer.identity_key, alice_identity_key.public_key);
|
||||||
);
|
olm::store_array(writer.base_key, alice_base_key.public_key);
|
||||||
std::memcpy(
|
|
||||||
writer.identity_key, alice_identity_key.public_key, KEY_LENGTH
|
|
||||||
);
|
|
||||||
std::memcpy(
|
|
||||||
writer.base_key, alice_base_key.public_key, KEY_LENGTH
|
|
||||||
);
|
|
||||||
message_body = writer.message;
|
message_body = writer.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ olm::Utility::Utility(
|
||||||
|
|
||||||
|
|
||||||
size_t olm::Utility::sha256_length() {
|
size_t olm::Utility::sha256_length() {
|
||||||
return olm::HMAC_SHA256_OUTPUT_LENGTH;
|
return olm::SHA256_OUTPUT_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ size_t olm::Utility::sha256(
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
olm::sha256(input, input_length, output);
|
olm::sha256(input, input_length, output);
|
||||||
return 32;
|
return olm::SHA256_OUTPUT_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ size_t olm::Utility::ed25519_verify(
|
||||||
std::uint8_t const * message, std::size_t message_length,
|
std::uint8_t const * message, std::size_t message_length,
|
||||||
std::uint8_t const * signature, std::size_t signature_length
|
std::uint8_t const * signature, std::size_t signature_length
|
||||||
) {
|
) {
|
||||||
if (signature_length < 64) {
|
if (signature_length < olm::SIGNATURE_LENGTH) {
|
||||||
last_error = olm::ErrorCode::BAD_MESSAGE_MAC;
|
last_error = olm::ErrorCode::BAD_MESSAGE_MAC;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,5 +33,4 @@ olm::decode_base64(input, input_length, output);
|
||||||
assert_equals(expected_output, output, output_length);
|
assert_equals(expected_output, output, output_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ olm::curve25519_generate_key(bob_private, bob_pair);
|
||||||
assert_equals(bob_private, bob_pair.private_key, 32);
|
assert_equals(bob_private, bob_pair.private_key, 32);
|
||||||
assert_equals(bob_public, bob_pair.public_key, 32);
|
assert_equals(bob_public, bob_pair.public_key, 32);
|
||||||
|
|
||||||
std::uint8_t actual_agreement[olm::CURVE25519_SHARED_SECRET_LENGTH] = {};
|
std::uint8_t actual_agreement[olm::KEY_LENGTH] = {};
|
||||||
|
|
||||||
olm::curve25519_shared_secret(alice_pair, bob_pair, actual_agreement);
|
olm::curve25519_shared_secret(alice_pair, bob_pair, actual_agreement);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue