From 39212987bdef8e16794e756e3c78b531be25b70a Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 2 Sep 2016 15:11:14 +0100 Subject: [PATCH] Create new constants for key lengths, etc We were using olm::KEY_LENGTH for everything under the sun which happened to be 32 bytes long, and making a bunch of assumptions in the process. Create a bunch of new constants (as C #defines rather than C++ consts so that I can use them in another forthcoming refactor). --- include/olm/crypto.h | 31 ++++++++++++++++++++++++- include/olm/crypto.hh | 15 +++++-------- include/olm/ratchet.hh | 7 +++++- src/account.cpp | 10 ++++----- src/cipher.cpp | 12 ++++++---- src/crypto.cpp | 4 ++-- src/olm.cpp | 10 ++++----- src/ratchet.cpp | 27 +++++++++++----------- src/session.cpp | 51 +++++++++++++++++++++--------------------- src/utility.cpp | 2 +- tests/test_crypto.cpp | 2 +- 11 files changed, 103 insertions(+), 68 deletions(-) diff --git a/include/olm/crypto.h b/include/olm/crypto.h index 31b9b60..325080e 100644 --- a/include/olm/crypto.h +++ b/include/olm/crypto.h @@ -27,7 +27,36 @@ extern "C" { #endif -const size_t SHA256_OUTPUT_LENGTH = 32; +/** length of a sha256 hash */ +#define SHA256_OUTPUT_LENGTH 32 + +/** length of a public or private Curve25519 key */ +#define CURVE25519_KEY_LENGTH 32 + +/** length of the shared secret created by a Curve25519 ECDH operation */ +#define CURVE25519_SHARED_SECRET_LENGTH 32 + +/** amount of random data required to create a Curve25519 keypair */ +#define CURVE25519_RANDOM_LENGTH CURVE25519_KEY_LENGTH + +/** length of a public Ed25519 key */ +#define ED25519_PUBLIC_KEY_LENGTH 32 + +/** length of a private Ed25519 key */ +#define ED25519_PRIVATE_KEY_LENGTH 64 + +/** amount of random data required to create a Ed25519 keypair */ +#define ED25519_RANDOM_LENGTH 32 + +/** length of an Ed25519 signature */ +#define ED25519_SIGNATURE_LENGTH 64 + +/** length of an aes256 key */ +#define AES256_KEY_LENGTH 32 + +/** length of an aes256 initialisation vector */ +#define AES256_IV_LENGTH 16 + /** Computes SHA-256 of the input. The output buffer must be a least 32 * bytes long. */ diff --git a/include/olm/crypto.hh b/include/olm/crypto.hh index 484dc83..13fd7e9 100644 --- a/include/olm/crypto.hh +++ b/include/olm/crypto.hh @@ -25,23 +25,18 @@ namespace olm { -static const std::size_t ED25519_PRIVATE_KEY_LENGTH = 64; -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 { - std::uint8_t public_key[KEY_LENGTH]; + std::uint8_t public_key[CURVE25519_KEY_LENGTH]; }; struct Curve25519KeyPair : public Curve25519PublicKey { - std::uint8_t private_key[KEY_LENGTH]; + std::uint8_t private_key[CURVE25519_KEY_LENGTH]; }; struct Ed25519PublicKey { - std::uint8_t public_key[KEY_LENGTH]; + std::uint8_t public_key[ED25519_PUBLIC_KEY_LENGTH]; }; @@ -93,12 +88,12 @@ bool ed25519_verify( struct Aes256Key { - std::uint8_t key[KEY_LENGTH]; + std::uint8_t key[AES256_KEY_LENGTH]; }; struct Aes256Iv { - std::uint8_t iv[IV_LENGTH]; + std::uint8_t iv[AES256_IV_LENGTH]; }; diff --git a/include/olm/ratchet.hh b/include/olm/ratchet.hh index 13f7097..e91d634 100644 --- a/include/olm/ratchet.hh +++ b/include/olm/ratchet.hh @@ -21,8 +21,13 @@ struct _olm_cipher; namespace olm { -typedef std::uint8_t SharedKey[olm::KEY_LENGTH]; +/** length of a shared key: the root key R(i), chain key C(i,j), and message key + * M(i,j)). They are all only used to stuff into HMACs, so could be any length + * for that. The chain key and message key are both derived from SHA256 + * operations, so their length is determined by that. */ +const std::size_t OLM_SHARED_KEY_LENGTH = SHA256_OUTPUT_LENGTH; +typedef std::uint8_t SharedKey[OLM_SHARED_KEY_LENGTH]; struct ChainKey { std::uint32_t index; diff --git a/src/account.cpp b/src/account.cpp index ec763f8..9512068 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -49,7 +49,7 @@ std::size_t olm::Account::remove_key( } std::size_t olm::Account::new_account_random_length() { - return 2 * olm::KEY_LENGTH; + return ED25519_RANDOM_LENGTH + CURVE25519_RANDOM_LENGTH; } std::size_t olm::Account::new_account( @@ -61,7 +61,7 @@ std::size_t olm::Account::new_account( } olm::ed25519_generate_key(random, identity_keys.ed25519_key); - random += KEY_LENGTH; + random += ED25519_RANDOM_LENGTH; olm::curve25519_generate_key(random, identity_keys.curve25519_key); return 0; @@ -137,7 +137,7 @@ std::size_t olm::Account::get_identity_json( std::size_t olm::Account::signature_length( ) { - return olm::SIGNATURE_LENGTH; + return ED25519_SIGNATURE_LENGTH; } @@ -238,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 number_of_keys ) { - return olm::KEY_LENGTH * number_of_keys; + return CURVE25519_RANDOM_LENGTH * number_of_keys; } std::size_t olm::Account::generate_one_time_keys( @@ -254,7 +254,7 @@ std::size_t olm::Account::generate_one_time_keys( key.id = ++next_one_time_key_id; key.published = false; olm::curve25519_generate_key(random, key.key); - random += olm::KEY_LENGTH; + random += CURVE25519_RANDOM_LENGTH; } return number_of_keys; } diff --git a/src/cipher.cpp b/src/cipher.cpp index 8c3de92..8e3d7a5 100644 --- a/src/cipher.cpp +++ b/src/cipher.cpp @@ -17,11 +17,13 @@ #include "olm/memory.hh" #include +const std::size_t HMAC_KEY_LENGTH = 32; + namespace { struct DerivedKeys { olm::Aes256Key aes_key; - std::uint8_t mac_key[olm::KEY_LENGTH]; + std::uint8_t mac_key[HMAC_KEY_LENGTH]; olm::Aes256Iv aes_iv; }; @@ -31,7 +33,9 @@ static void derive_keys( std::uint8_t const * key, std::size_t key_length, DerivedKeys & keys ) { - std::uint8_t derived_secrets[2 * olm::KEY_LENGTH + olm::IV_LENGTH]; + std::uint8_t derived_secrets[ + AES256_KEY_LENGTH + HMAC_KEY_LENGTH + AES256_IV_LENGTH + ]; _olm_crypto_hkdf_sha256( key, key_length, nullptr, 0, @@ -81,7 +85,7 @@ size_t aes_sha_256_cipher_encrypt( ); _olm_crypto_hmac_sha256( - keys.mac_key, olm::KEY_LENGTH, output, output_length - MAC_LENGTH, mac + keys.mac_key, HMAC_KEY_LENGTH, output, output_length - MAC_LENGTH, mac ); std::memcpy(output + output_length - MAC_LENGTH, mac, MAC_LENGTH); @@ -113,7 +117,7 @@ size_t aes_sha_256_cipher_decrypt( derive_keys(c->kdf_info, c->kdf_info_length, key, key_length, keys); _olm_crypto_hmac_sha256( - keys.mac_key, olm::KEY_LENGTH, input, input_length - MAC_LENGTH, mac + keys.mac_key, HMAC_KEY_LENGTH, input, input_length - MAC_LENGTH, mac ); std::uint8_t const * input_mac = input + input_length - MAC_LENGTH; diff --git a/src/crypto.cpp b/src/crypto.cpp index 83493be..0b08c54 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -31,7 +31,7 @@ namespace { 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_KEY_BITS = 8 * AES256_KEY_LENGTH; static const std::size_t AES_BLOCK_LENGTH = 16; static const std::size_t SHA256_BLOCK_LENGTH = 64; static const std::uint8_t HKDF_DEFAULT_SALT[32] = {}; @@ -104,7 +104,7 @@ void olm::curve25519_generate_key( std::uint8_t const * random_32_bytes, olm::Curve25519KeyPair & key_pair ) { - std::memcpy(key_pair.private_key, random_32_bytes, KEY_LENGTH); + std::memcpy(key_pair.private_key, random_32_bytes, CURVE25519_KEY_LENGTH); ::curve25519_donna( key_pair.public_key, key_pair.private_key, CURVE25519_BASEPOINT ); diff --git a/src/olm.cpp b/src/olm.cpp index 682a84c..10e00fa 100644 --- a/src/olm.cpp +++ b/src/olm.cpp @@ -436,8 +436,8 @@ size_t olm_create_outbound_session( 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 + if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH + || olm::decode_base64_length(ot_key_length) != CURVE25519_KEY_LENGTH ) { from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64; return std::size_t(-1); @@ -483,7 +483,7 @@ size_t olm_create_inbound_session_from( 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) { + if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH) { from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64; return std::size_t(-1); } @@ -554,7 +554,7 @@ size_t olm_matches_inbound_session_from( 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) { + if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH) { from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64; return std::size_t(-1); } @@ -710,7 +710,7 @@ size_t olm_ed25519_verify( void const * message, size_t message_length, void * signature, size_t signature_length ) { - if (olm::decode_base64_length(key_length) != olm::KEY_LENGTH) { + if (olm::decode_base64_length(key_length) != CURVE25519_KEY_LENGTH) { from_c(utility)->last_error = OlmErrorCode::OLM_INVALID_BASE64; return std::size_t(-1); } diff --git a/src/ratchet.cpp b/src/ratchet.cpp index aab5fbb..57cb385 100644 --- a/src/ratchet.cpp +++ b/src/ratchet.cpp @@ -49,7 +49,7 @@ static void create_chain_key( ) { olm::SharedKey secret; olm::curve25519_shared_secret(our_key, their_key, secret); - std::uint8_t derived_secrets[2 * olm::KEY_LENGTH]; + std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH]; _olm_crypto_hkdf_sha256( secret, sizeof(secret), root_key, sizeof(root_key), @@ -191,7 +191,7 @@ void olm::Ratchet::initialise_as_bob( std::uint8_t const * shared_secret, std::size_t shared_secret_length, olm::Curve25519PublicKey const & their_ratchet_key ) { - std::uint8_t derived_secrets[2 * olm::KEY_LENGTH]; + std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH]; _olm_crypto_hkdf_sha256( shared_secret, shared_secret_length, nullptr, 0, @@ -212,7 +212,7 @@ void olm::Ratchet::initialise_as_alice( std::uint8_t const * shared_secret, std::size_t shared_secret_length, olm::Curve25519KeyPair const & our_ratchet_key ) { - std::uint8_t derived_secrets[2 * olm::KEY_LENGTH]; + std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH]; _olm_crypto_hkdf_sha256( shared_secret, shared_secret_length, nullptr, 0, @@ -234,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; } @@ -242,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); } @@ -250,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); } @@ -359,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); @@ -409,13 +409,13 @@ std::size_t olm::Ratchet::encrypt_output_length( plaintext_length ); return olm::encode_message_length( - counter, olm::KEY_LENGTH, padded, ratchet_cipher->ops->mac_length(ratchet_cipher) + 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; } @@ -461,7 +461,8 @@ std::size_t olm::Ratchet::encrypt( 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 ); @@ -529,7 +530,7 @@ std::size_t olm::Ratchet::decrypt( return std::size_t(-1); } - if (reader.ratchet_key_length != olm::KEY_LENGTH) { + if (reader.ratchet_key_length != CURVE25519_KEY_LENGTH) { last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT; return std::size_t(-1); } @@ -539,7 +540,7 @@ std::size_t olm::Ratchet::decrypt( 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; @@ -559,7 +560,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. */ diff --git a/src/session.cpp b/src/session.cpp index 6ca7f36..7bde5d1 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -49,7 +49,7 @@ olm::Session::Session( std::size_t olm::Session::new_outbound_session_random_length() { - return olm::KEY_LENGTH * 2; + return CURVE25519_RANDOM_LENGTH * 2; } @@ -68,7 +68,7 @@ std::size_t olm::Session::new_outbound_session( olm::curve25519_generate_key(random, base_key); olm::Curve25519KeyPair ratchet_key; - olm::curve25519_generate_key(random + olm::KEY_LENGTH, ratchet_key); + olm::curve25519_generate_key(random + CURVE25519_RANDOM_LENGTH, ratchet_key); olm::Curve25519KeyPair const & alice_identity_key_pair = ( local_account.identity_keys.curve25519_key @@ -79,13 +79,13 @@ std::size_t olm::Session::new_outbound_session( alice_base_key = base_key; bob_one_time_key = one_time_key; - std::uint8_t secret[3 * olm::KEY_LENGTH]; + // Calculate the shared secret S via triple DH + std::uint8_t secret[3 * CURVE25519_SHARED_SECRET_LENGTH]; std::uint8_t * pos = secret; - olm::curve25519_shared_secret(alice_identity_key_pair, one_time_key, pos); - pos += olm::KEY_LENGTH; + pos += CURVE25519_SHARED_SECRET_LENGTH; olm::curve25519_shared_secret(base_key, identity_key, pos); - pos += olm::KEY_LENGTH; + pos += CURVE25519_SHARED_SECRET_LENGTH; olm::curve25519_shared_secret(base_key, one_time_key, pos); ratchet.initialise_as_alice(secret, sizeof(secret), ratchet_key); @@ -105,13 +105,13 @@ static bool check_message_fields( bool ok = true; ok = ok && (have_their_identity_key || reader.identity_key); if (reader.identity_key) { - ok = ok && reader.identity_key_length == olm::KEY_LENGTH; + ok = ok && reader.identity_key_length == CURVE25519_KEY_LENGTH; } ok = ok && reader.message; ok = ok && reader.base_key; - ok = ok && reader.base_key_length == olm::KEY_LENGTH; + ok = ok && reader.base_key_length == CURVE25519_KEY_LENGTH; ok = ok && reader.one_time_key; - ok = ok && reader.one_time_key_length == olm::KEY_LENGTH; + ok = ok && reader.one_time_key_length == CURVE25519_KEY_LENGTH; return ok; } @@ -133,7 +133,7 @@ std::size_t olm::Session::new_inbound_session( if (reader.identity_key && their_identity_key) { bool same = 0 == std::memcmp( - their_identity_key->public_key, reader.identity_key, olm::KEY_LENGTH + their_identity_key->public_key, reader.identity_key, CURVE25519_KEY_LENGTH ); if (!same) { last_error = OlmErrorCode::OLM_BAD_MESSAGE_KEY_ID; @@ -152,7 +152,7 @@ std::size_t olm::Session::new_inbound_session( ); if (!message_reader.ratchet_key - || message_reader.ratchet_key_length != olm::KEY_LENGTH) { + || message_reader.ratchet_key_length != CURVE25519_KEY_LENGTH) { last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT; return std::size_t(-1); } @@ -174,12 +174,13 @@ std::size_t olm::Session::new_inbound_session( ); olm::Curve25519KeyPair const & bob_one_time_key = our_one_time_key->key; - std::uint8_t secret[olm::KEY_LENGTH * 3]; + // Calculate the shared secret S via triple DH + std::uint8_t secret[CURVE25519_SHARED_SECRET_LENGTH * 3]; std::uint8_t * pos = secret; olm::curve25519_shared_secret(bob_one_time_key, alice_identity_key, pos); - pos += olm::KEY_LENGTH; + pos += CURVE25519_SHARED_SECRET_LENGTH; olm::curve25519_shared_secret(bob_identity_key, alice_base_key, pos); - pos += olm::KEY_LENGTH; + pos += CURVE25519_SHARED_SECRET_LENGTH; olm::curve25519_shared_secret(bob_one_time_key, alice_base_key, pos); ratchet.initialise_as_bob(secret, sizeof(secret), ratchet_key); @@ -202,7 +203,7 @@ std::size_t olm::Session::session_id( last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL; return std::size_t(-1); } - std::uint8_t tmp[olm::KEY_LENGTH * 3]; + std::uint8_t tmp[CURVE25519_KEY_LENGTH * 3]; std::uint8_t * pos = tmp; pos = olm::store_array(pos, alice_identity_key.public_key); pos = olm::store_array(pos, alice_base_key.public_key); @@ -226,20 +227,20 @@ bool olm::Session::matches_inbound_session( bool same = true; if (reader.identity_key) { same = same && 0 == std::memcmp( - reader.identity_key, alice_identity_key.public_key, olm::KEY_LENGTH + reader.identity_key, alice_identity_key.public_key, CURVE25519_KEY_LENGTH ); } if (their_identity_key) { same = same && 0 == std::memcmp( their_identity_key->public_key, alice_identity_key.public_key, - olm::KEY_LENGTH + CURVE25519_KEY_LENGTH ); } same = same && 0 == std::memcmp( - reader.base_key, alice_base_key.public_key, olm::KEY_LENGTH + reader.base_key, alice_base_key.public_key, CURVE25519_KEY_LENGTH ); same = same && 0 == std::memcmp( - reader.one_time_key, bob_one_time_key.public_key, olm::KEY_LENGTH + reader.one_time_key, bob_one_time_key.public_key, CURVE25519_KEY_LENGTH ); return same; } @@ -266,9 +267,9 @@ std::size_t olm::Session::encrypt_message_length( } return encode_one_time_key_message_length( - olm::KEY_LENGTH, - olm::KEY_LENGTH, - olm::KEY_LENGTH, + CURVE25519_KEY_LENGTH, + CURVE25519_KEY_LENGTH, + CURVE25519_KEY_LENGTH, message_length ); } @@ -300,9 +301,9 @@ std::size_t olm::Session::encrypt( encode_one_time_key_message( writer, PROTOCOL_VERSION, - olm::KEY_LENGTH, - olm::KEY_LENGTH, - olm::KEY_LENGTH, + CURVE25519_KEY_LENGTH, + CURVE25519_KEY_LENGTH, + CURVE25519_KEY_LENGTH, message_body_length, message ); diff --git a/src/utility.cpp b/src/utility.cpp index 67029c9..e33351c 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -45,7 +45,7 @@ size_t olm::Utility::ed25519_verify( std::uint8_t const * message, std::size_t message_length, std::uint8_t const * signature, std::size_t signature_length ) { - if (signature_length < olm::SIGNATURE_LENGTH) { + if (signature_length < ED25519_SIGNATURE_LENGTH) { last_error = OlmErrorCode::OLM_BAD_MESSAGE_MAC; return std::size_t(-1); } diff --git a/tests/test_crypto.cpp b/tests/test_crypto.cpp index 175f66f..56abdcd 100644 --- a/tests/test_crypto.cpp +++ b/tests/test_crypto.cpp @@ -70,7 +70,7 @@ olm::curve25519_generate_key(bob_private, bob_pair); assert_equals(bob_private, bob_pair.private_key, 32); assert_equals(bob_public, bob_pair.public_key, 32); -std::uint8_t actual_agreement[olm::KEY_LENGTH] = {}; +std::uint8_t actual_agreement[CURVE25519_SHARED_SECRET_LENGTH] = {}; olm::curve25519_shared_secret(alice_pair, bob_pair, actual_agreement);