From 09d4125ff164f5ca686d12ccb0790c35ce721a6b Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 27 Jun 2015 01:15:23 +0200 Subject: Rename axolotlpp as olm to avoid confusion with Axolotl-the-spec and Axolotl-the-OWS-libraries at moxie's request --- include/axolotl/account.hh | 84 ------------- include/axolotl/axolotl.hh | 295 --------------------------------------------- include/axolotl/base64.hh | 49 -------- include/axolotl/cipher.hh | 128 -------------------- include/axolotl/crypto.hh | 148 ----------------------- include/axolotl/error.hh | 34 ------ include/axolotl/list.hh | 119 ------------------ include/axolotl/memory.hh | 38 ------ include/axolotl/message.hh | 126 ------------------- include/axolotl/pickle.hh | 178 --------------------------- include/axolotl/ratchet.hh | 177 --------------------------- include/axolotl/session.hh | 114 ------------------ include/olm/account.hh | 84 +++++++++++++ include/olm/base64.hh | 49 ++++++++ include/olm/cipher.hh | 128 ++++++++++++++++++++ include/olm/crypto.hh | 148 +++++++++++++++++++++++ include/olm/error.hh | 34 ++++++ include/olm/list.hh | 119 ++++++++++++++++++ include/olm/memory.hh | 38 ++++++ include/olm/message.hh | 126 +++++++++++++++++++ include/olm/olm.hh | 295 +++++++++++++++++++++++++++++++++++++++++++++ include/olm/pickle.hh | 178 +++++++++++++++++++++++++++ include/olm/ratchet.hh | 177 +++++++++++++++++++++++++++ include/olm/session.hh | 114 ++++++++++++++++++ 24 files changed, 1490 insertions(+), 1490 deletions(-) delete mode 100644 include/axolotl/account.hh delete mode 100644 include/axolotl/axolotl.hh delete mode 100644 include/axolotl/base64.hh delete mode 100644 include/axolotl/cipher.hh delete mode 100644 include/axolotl/crypto.hh delete mode 100644 include/axolotl/error.hh delete mode 100644 include/axolotl/list.hh delete mode 100644 include/axolotl/memory.hh delete mode 100644 include/axolotl/message.hh delete mode 100644 include/axolotl/pickle.hh delete mode 100644 include/axolotl/ratchet.hh delete mode 100644 include/axolotl/session.hh create mode 100644 include/olm/account.hh create mode 100644 include/olm/base64.hh create mode 100644 include/olm/cipher.hh create mode 100644 include/olm/crypto.hh create mode 100644 include/olm/error.hh create mode 100644 include/olm/list.hh create mode 100644 include/olm/memory.hh create mode 100644 include/olm/message.hh create mode 100644 include/olm/olm.hh create mode 100644 include/olm/pickle.hh create mode 100644 include/olm/ratchet.hh create mode 100644 include/olm/session.hh (limited to 'include') diff --git a/include/axolotl/account.hh b/include/axolotl/account.hh deleted file mode 100644 index 54621fd..0000000 --- a/include/axolotl/account.hh +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef AXOLOTL_ACCOUNT_HH_ -#define AXOLOTL_ACCOUNT_HH_ - -#include "axolotl/list.hh" -#include "axolotl/crypto.hh" -#include "axolotl/error.hh" - -#include - -namespace axolotl { - - -struct LocalKey { - std::uint32_t id; - Curve25519KeyPair key; -}; - - -struct SignedKey : LocalKey { - std::uint8_t signature[64]; -}; - - -static std::size_t const MAX_ONE_TIME_KEYS = 100; - -struct Account { - LocalKey identity_key; - LocalKey last_resort_one_time_key; - List one_time_keys; - ErrorCode last_error; - - /** Number of random bytes needed to create a new account */ - std::size_t new_account_random_length(); - - /** Create a new account. Returns NOT_ENOUGH_RANDOM if the number of random - * bytes is too small. */ - std::size_t new_account( - uint8_t const * random, std::size_t random_length - ); - - LocalKey const * lookup_key( - std::uint32_t id - ); - - std::size_t remove_key( - std::uint32_t id - ); -}; - - -std::size_t pickle_length( - Account const & value -); - - -std::uint8_t * pickle( - std::uint8_t * pos, - Account const & value -); - - -std::uint8_t const * unpickle( - std::uint8_t const * pos, std::uint8_t const * end, - Account & value -); - - -} // namespace axolotl - -#endif /* AXOLOTL_ACCOUNT_HH_ */ diff --git a/include/axolotl/axolotl.hh b/include/axolotl/axolotl.hh deleted file mode 100644 index 90065a7..0000000 --- a/include/axolotl/axolotl.hh +++ /dev/null @@ -1,295 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef AXOLOTL_HH_ -#define AXOLOTL_HH_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -static const size_t AXOLOTL_MESSAGE_TYPE_PRE_KEY = 0; -static const size_t AXOLOTL_MESSAGE_TYPE_MESSAGE = 1; - -struct AxolotlAccount; -struct AxolotlSession; - -/** The size of an account object in bytes */ -size_t axolotl_account_size(); - -/** The size of a session object in bytes */ -size_t axolotl_session_size(); - -/** Initialise an account object using the supplied memory - * The supplied memory must be at least axolotl_account_size() bytes */ -AxolotlAccount * axolotl_account( - void * memory -); - -/** Initialise a session object using the supplied memory - * The supplied memory must be at least axolotl_session_size() bytes */ -AxolotlSession * axolotl_session( - void * memory -); - -/** The value that axolotl will return from a function if there was an error */ -size_t axolotl_error(); - -/** A null terminated string describing the most recent error to happen to an - * account */ -const char * axolotl_account_last_error( - AxolotlSession * account -); - -/** A null terminated string describing the most recent error to happen to a - * session */ -const char * axolotl_session_last_error( - AxolotlSession * session -); - -/** Returns the number of bytes needed to store an account */ -size_t axolotl_pickle_account_length( - AxolotlAccount * account -); - -/** Returns the number of bytes needed to store a session */ -size_t axolotl_pickle_session_length( - AxolotlSession * session -); - -/** Stores an account as a base64 string. Encrypts the account using the - * supplied key. Returns the length of the pickled account on success. - * Returns axolotl_error() on failure. If the pickle output buffer - * is smaller than axolotl_pickle_account_length() then - * axolotl_account_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" */ -size_t axolotl_pickle_account( - AxolotlAccount * account, - void const * key, size_t key_length, - void * pickled, size_t pickled_length -); - -/** Stores a session as a base64 string. Encrypts the session using the - * supplied key. Returns the length of the pickled session on success. - * Returns axolotl_error() on failure. If the pickle output buffer - * is smaller than axolotl_pickle_session_length() then - * axolotl_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" */ -size_t axolotl_pickle_session( - AxolotlSession * session, - void const * key, size_t key_length, - void * pickled, size_t pickled_length -); - -/** Loads an account from a pickled base64 string. Decrypts the account using - * the supplied key. Returns axolotl_error() on failure. If the key doesn't - * match the one used to encrypt the account then axolotl_account_last_error() - * will be "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then - * axolotl_account_last_error() will be "INVALID_BASE64". The input pickled - * buffer is destroyed */ -size_t axolotl_unpickle_account( - AxolotlAccount * account, - void const * key, size_t key_length, - void * pickled, size_t pickled_length -); - -/** Loads a session from a pickled base64 string. Decrypts the session using - * the supplied key. Returns axolotl_error() on failure. If the key doesn't - * match the one used to encrypt the account then axolotl_session_last_error() - * will be "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then - * axolotl_session_last_error() will be "INVALID_BASE64". The input pickled - * buffer is destroyed */ -size_t axolotl_unpickle_session( - AxolotlSession * session, - void const * key, size_t key_length, - void * pickled, size_t pickled_length -); - -/** The number of random bytes needed to create an account.*/ -size_t axolotl_create_account_random_length( - AxolotlAccount * account -); - -/** Creates a new account. Returns axolotl_error() on failure. If weren't - * enough random bytes then axolotl_account_last_error() will be - * "NOT_ENOUGH_RANDOM" */ -size_t axolotl_create_account( - AxolotlAccount * account, - void const * random, size_t random_length -); - -/** The size of the output buffer needed to hold the identity keys */ -size_t axolotl_account_identity_keys_length( - AxolotlAccount * account -); - -/** Writes the public parts of the identity keys for the account into the - * identity_keys output buffer. The output is formatted as though it was - * created with sprintf(output, "[[%10d,\"%43s\"]\n]", key_id, key_base64). - * The output can either be parsed as fixed width using the above format or by - * a JSON parser. Returns axolotl_error() on failure. If the identity_keys - * buffer was too small then axolotl_account_last_error() will be - * "OUTPUT_BUFFER_TOO_SMALL". */ -size_t axolotl_account_identity_keys( - AxolotlAccount * account, - void * identity_keys, size_t identity_key_length -); - -/** The size of the output buffer needed to hold the one time keys */ -size_t axolotl_account_one_time_keys_length( - AxolotlAccount * account -); - -/** Writes the public parts of the one time keys for the account into the - * one_time_keys output buffer. The first key will be formatted as though it was - * created with sprintf(output, "[[%10d,\"%43s\"]\n", key_id, key_base64). - * subsequent keys are formatted with ",[%10d,\"%43s\"]\n". The final byte of - * output will be "]". The output can either be parsed as fixed width using - * the above format or by a JSON parser. Returns axolotl_error() on failure. - * If the one_time_keys buffer was too small then axolotl_account_last_error() - * will be "OUTPUT_BUFFER_TOO_SMALL". */ -size_t axolotl_account_one_time_keys( - AxolotlAccount * account, - void * one_time_keys, size_t one_time_keys_length -); - -/* TODO: Add methods for marking keys as used, generating new keys, and - * tracking which keys have been uploaded to the central servers */ - -/** The number of random bytes needed to create an outbound session */ -size_t axolotl_create_outbound_session_random_length( - AxolotlSession * session -); - -/** Creates a new out-bound session for sending messages to a given identity_key - * and one_time_key. Returns axolotl_error() on failure. If the keys couldn't be - * decoded as base64 then axolotl_session_last_error() will be "INVALID_BASE64" - * If there weren't enough random bytes then axolotl_session_last_error() will - * be "NOT_ENOUGH_RANDOM". */ -size_t axolotl_create_outbound_session( - AxolotlSession * session, - AxolotlAccount * account, - void const * their_identity_key, size_t their_identity_key_length, - unsigned their_one_time_key_id, - void const * their_one_time_key, size_t their_one_time_key_length, - void const * random, size_t random_length -); - -/** Create a new in-bound session for sending/receiving messages from an - * incoming PRE_KEY message. Returns axolotl_error() on failure. If the base64 - * couldn't be decoded then axolotl_session_last_error will be "INVALID_BASE64". - * If the message was for an unsupported protocol version then - * axolotl_session_last_error() will be "BAD_MESSAGE_VERSION". If the message - * couldn't be decoded then then axolotl_session_last_error() will be - * "BAD_MESSAGE_FORMAT". If the message refers to an unknown one time - * key then axolotl_session_last_error() will be "BAD_MESSAGE_KEY_ID". */ -size_t axolotl_create_inbound_session( - AxolotlSession * session, - AxolotlAccount * account, - void * one_time_key_message, size_t message_length -); - -/** Checks if the PRE_KEY message is for this in-bound session. This can happen - * if multiple messages are sent to this account before this account sends a - * message in reply. Returns axolotl_error() on failure. If the base64 - * couldn't be decoded then axolotl_session_last_error will be "INVALID_BASE64". - * If the message was for an unsupported protocol version then - * axolotl_session_last_error() will be "BAD_MESSAGE_VERSION". If the message - * couldn't be decoded then then axolotl_session_last_error() will be - * "BAD_MESSAGE_FORMAT". */ -size_t axolotl_matches_inbound_session( - AxolotlSession * session, - void * one_time_key_message, size_t message_length -); - -/** Removes the one time keys that the session used from the account. Returns - * axolotl_error() on failure. If the account doesn't have any matching one time - * keys then axolotl_account_last_error() will be "BAD_MESSAGE_KEY_ID". */ -size_t axolotl_remove_one_time_keys( - AxolotlAccount * account, - AxolotlSession * session -); - -/** The type of the next message that axolotl_encrypt() will return. Returns - * AXOLOTL_MESSAGE_TYPE_PRE_KEY if the message will be a PRE_KEY message. - * Returns AXOLOTL_MESSAGE_TYPE_MESSAGE if the message will be a normal message. - * Returns axolotl_error on failure. */ -size_t axolotl_encrypt_message_type( - AxolotlSession * session -); - -/** The number of random bytes needed to encrypt the next message. */ -size_t axolotl_encrypt_random_length( - AxolotlSession * session -); - -/** The size of the next message in bytes for the given number of plain-text - * bytes. */ -size_t axolotl_encrypt_message_length( - AxolotlSession * session, - size_t plaintext_length -); - -/** Encrypts a message using the session. Returns the length of the message in - * bytes on success. Writes the message as base64 into the message buffer. - * Returns axolotl_error() on failure. If the message buffer is too small then - * axolotl_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". If there - * weren't enough random bytes then axolotl_session_last_error() will be - * "NOT_ENOUGH_RANDOM". */ -size_t axolotl_encrypt( - AxolotlSession * session, - void const * plaintext, size_t plaintext_length, - void const * random, size_t random_length, - void * message, size_t message_length -); - -/** The maximum number of bytes of plain-text a given message could decode to. - * The actual size could be different due to padding. The input message buffer - * is destroyed. Returns axolotl_error() on failure. If the message base64 - * couldn't be decoded then axolotl_session_last_error() will be - * "INVALID_BASE64". If the message is for an unsupported version of the - * protocol then axolotl_session_last_error() will be "BAD_MESSAGE_VERSION". - * If the message couldn't be decoded then axolotl_session_last_error() will be - * "BAD_MESSAGE_FORMAT". */ -size_t axolotl_decrypt_max_plaintext_length( - AxolotlSession * session, - size_t message_type, - void * message, size_t message_length -); - -/** Decrypts a message using the session. The input message buffer is destroyed. - * Returns the length of the plain-text on success. Returns axolotl_error() on - * failure. If the plain-text buffer is smaller than - * axolotl_decrypt_max_plaintext_length() then axolotl_session_last_error() - * will be "OUTPUT_BUFFER_TOO_SMALL". If the base64 couldn't be decoded then - * axolotl_session_last_error() will be "INVALID_BASE64". If the message is for - * an unsupported version of the protocol then axolotl_session_last_error() will - * be "BAD_MESSAGE_VERSION". If the message couldn't be decoded then - * axolotl_session_last_error() will be BAD_MESSAGE_FORMAT". - * If the MAC on the message was invalid then axolotl_session_last_error() will - * be "BAD_MESSAGE_MAC". */ -size_t axolotl_decrypt( - AxolotlSession * session, - size_t message_type, - void * message, size_t message_length, - void * plaintext, size_t max_plaintext_length -); - - - -#ifdef __cplusplus -} -#endif - -#endif /* AXOLOTL_HH_ */ diff --git a/include/axolotl/base64.hh b/include/axolotl/base64.hh deleted file mode 100644 index 361a558..0000000 --- a/include/axolotl/base64.hh +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef AXOLOLT_BASE64_HH_ -#define AXOLOLT_BASE64_HH_ - -#include -#include - -namespace axolotl { - - -std::size_t encode_base64_length( - std::size_t input_length -); - - -void encode_base64( - std::uint8_t const * input, std::size_t input_length, - std::uint8_t * output -); - - -std::size_t decode_base64_length( - std::size_t input_length -); - - -void decode_base64( - std::uint8_t const * input, std::size_t input_length, - std::uint8_t * output -); - - -} // namespace axolotl - - -#endif /* AXOLOLT_BASE64_HH_ */ diff --git a/include/axolotl/cipher.hh b/include/axolotl/cipher.hh deleted file mode 100644 index 5a077aa..0000000 --- a/include/axolotl/cipher.hh +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AXOLOTL_CIPHER_HH_ -#define AXOLOTL_CIPHER_HH_ - -#include -#include - -namespace axolotl { - -class Cipher { -public: - virtual ~Cipher(); - - /** - * Returns the length of the message authentication code that will be - * appended to the output. - */ - virtual std::size_t mac_length() const = 0; - - /** - * Returns the length of cipher-text for a given length of plain-text. - */ - virtual std::size_t encrypt_ciphertext_length( - std::size_t plaintext_length - ) const = 0; - - /* - * Encrypts the plain-text into the output buffer and authenticates the - * contents of the output buffer covering both cipher-text and any other - * associated data in the output buffer. - * - * |---------------------------------------output_length-->| - * output |--ciphertext_length-->| |---mac_length-->| - * ciphertext - * - * Returns std::size_t(-1) if the length of the cipher-text or the output - * buffer is too small. Otherwise returns the length of the output buffer. - */ - virtual std::size_t encrypt( - std::uint8_t const * key, std::size_t key_length, - std::uint8_t const * plaintext, std::size_t plaintext_length, - std::uint8_t * ciphertext, std::size_t ciphertext_length, - std::uint8_t * output, std::size_t output_length - ) const = 0; - - /** - * Returns the maximum length of plain-text that a given length of - * cipher-text can contain. - */ - virtual std::size_t decrypt_max_plaintext_length( - std::size_t ciphertext_length - ) const = 0; - - /** - * Authenticates the input and decrypts the cipher-text into the plain-text - * buffer. - * - * |----------------------------------------input_length-->| - * input |--ciphertext_length-->| |---mac_length-->| - * ciphertext - * - * Returns std::size_t(-1) if the length of the plain-text buffer is too - * small or if the authentication check fails. Otherwise returns the length - * of the plain text. - */ - virtual std::size_t decrypt( - std::uint8_t const * key, std::size_t key_length, - std::uint8_t const * input, std::size_t input_length, - std::uint8_t const * ciphertext, std::size_t ciphertext_length, - std::uint8_t * plaintext, std::size_t max_plaintext_length - ) const = 0; -}; - - -class CipherAesSha256 : public Cipher { -public: - CipherAesSha256( - std::uint8_t const * kdf_info, std::size_t kdf_info_length - ); - - virtual std::size_t mac_length() const; - - virtual std::size_t encrypt_ciphertext_length( - std::size_t plaintext_length - ) const; - - virtual std::size_t encrypt( - std::uint8_t const * key, std::size_t key_length, - std::uint8_t const * plaintext, std::size_t plaintext_length, - std::uint8_t * ciphertext, std::size_t ciphertext_length, - std::uint8_t * output, std::size_t output_length - ) const; - - virtual std::size_t decrypt_max_plaintext_length( - std::size_t ciphertext_length - ) const; - - virtual std::size_t decrypt( - std::uint8_t const * key, std::size_t key_length, - std::uint8_t const * input, std::size_t input_length, - std::uint8_t const * ciphertext, std::size_t ciphertext_length, - std::uint8_t * plaintext, std::size_t max_plaintext_length - ) const; - -private: - std::uint8_t const * kdf_info; - std::size_t kdf_info_length; -}; - - -} // namespace - - -#endif /* AXOLOTL_CIPHER_HH_ */ diff --git a/include/axolotl/crypto.hh b/include/axolotl/crypto.hh deleted file mode 100644 index 7564e8f..0000000 --- a/include/axolotl/crypto.hh +++ /dev/null @@ -1,148 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef AXOLOTL_CRYPTO_HH_ -#define AXOLOTL_CRYPTO_HH_ - -#include -#include - -namespace axolotl { - - -struct Curve25519PublicKey { - static const int LENGTH = 32; - std::uint8_t public_key[32]; -}; - - -struct Curve25519KeyPair : public Curve25519PublicKey { - static const int LENGTH = 64; - std::uint8_t private_key[32]; -}; - - -/** Generate a curve25519 key pair from 32 random bytes. */ -void generate_key( - std::uint8_t const * random_32_bytes, - Curve25519KeyPair & key_pair -); - - -const std::size_t CURVE25519_SHARED_SECRET_LENGTH = 32; - - -/** Create a shared secret using our private key and their public key. - * The output buffer must be at least 32 bytes long. */ -void curve25519_shared_secret( - Curve25519KeyPair const & our_key, - Curve25519PublicKey const & their_key, - std::uint8_t * output -); - - -/** Signs the message using our private key. - * The output buffer must be at least 64 bytes long. */ -void curve25519_sign( - Curve25519KeyPair const & our_key, - std::uint8_t const * message, std::size_t message_length, - std::uint8_t * output -); - - -/** Verify thei message using their public key. - * The signature input buffer must be 64 bytes long. - * Returns true if the signature is valid. */ -bool curve25519_verify( - Curve25519PublicKey const & their_key, - std::uint8_t const * message, std::size_t message_length, - std::uint8_t const * signature -); - - -struct Aes256Key { - static const int LENGTH = 32; - std::uint8_t key[32]; -}; - - -struct Aes256Iv { - static const int LENGTH = 16; - std::uint8_t iv[16]; -}; - - -/** The length of output the aes_encrypt_cbc function will write */ -std::size_t aes_encrypt_cbc_length( - std::size_t input_length -); - - -/** Encrypts the input using AES256 in CBC mode with PKCS#7 padding. - * The output buffer must be big enough to hold the output including padding */ -void aes_encrypt_cbc( - Aes256Key const & key, - Aes256Iv const & iv, - std::uint8_t const * input, std::size_t input_length, - std::uint8_t * output -); - - -/** Decrypts the input using AES256 in CBC mode. The output buffer must be at - * least the same size as the input buffer. Returns the length of the plaintext - * without padding on success or std::size_t(-1) if the padding is invalid. - */ -std::size_t aes_decrypt_cbc( - Aes256Key const & key, - Aes256Iv const & iv, - std::uint8_t const * input, std::size_t input_length, - std::uint8_t * output -); - - -/** Computes SHA-256 of the input. The output buffer must be a least 32 - * bytes long. */ -void sha256( - std::uint8_t const * input, std::size_t input_length, - std::uint8_t * output -); - - -const std::size_t HMAC_SHA256_OUTPUT_LENGTH = 32; - - -/** HMAC: Keyed-Hashing for Message Authentication - * http://tools.ietf.org/html/rfc2104 - * Computes HMAC-SHA-256 of the input for the key. The output buffer must - * be at least 32 bytes long. */ -void hmac_sha256( - std::uint8_t const * key, std::size_t key_length, - std::uint8_t const * input, std::size_t input_length, - std::uint8_t * output -); - - -/** HMAC-based Key Derivation Function (HKDF) - * https://tools.ietf.org/html/rfc5869 - * Derives key material from the input bytes. */ -void hkdf_sha256( - std::uint8_t const * input, std::size_t input_length, - std::uint8_t const * info, std::size_t info_length, - std::uint8_t const * salt, std::size_t salt_length, - std::uint8_t * output, std::size_t output_length -); - -} // namespace axolotl - -#endif /* AXOLOTL_CRYPTO_HH_ */ diff --git a/include/axolotl/error.hh b/include/axolotl/error.hh deleted file mode 100644 index 781705e..0000000 --- a/include/axolotl/error.hh +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef ERROR_HH_ -#define ERROR_HH_ - -namespace axolotl { - -enum struct ErrorCode { - SUCCESS = 0, /*!< There wasn't an error */ - NOT_ENOUGH_RANDOM = 1, /*!< Not enough entropy was supplied */ - OUTPUT_BUFFER_TOO_SMALL = 2, /*!< Supplied output buffer is too small */ - BAD_MESSAGE_VERSION = 3, /*!< The message version is unsupported */ - BAD_MESSAGE_FORMAT = 4, /*!< The message couldn't be decoded */ - BAD_MESSAGE_MAC = 5, /*!< The message couldn't be decrypted */ - BAD_MESSAGE_KEY_ID = 6, /*!< The message references an unknown key id */ - INVALID_BASE64 = 7, /*!< The input base64 was invalid */ - BAD_ACCOUNT_KEY = 8, /*!< The supplied account key is invalid */ -}; - -} // namespace axolotl - -#endif /* ERROR_HH_ */ diff --git a/include/axolotl/list.hh b/include/axolotl/list.hh deleted file mode 100644 index 604f00f..0000000 --- a/include/axolotl/list.hh +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef AXOLOTL_LIST_HH_ -#define AXOLOTL_LIST_HH_ - -#include - -namespace axolotl { - -template -class List { -public: - List() : _end(_data) {} - - typedef T * iterator; - typedef T const * const_iterator; - - T * begin() { return _data; } - T * end() { return _end; } - T const * begin() const { return _data; } - T const * end() const { return _end; } - - /** - * Is the list empty? - */ - bool empty() const { return _end == _data; } - - /** - * The number of items in the list. - */ - std::size_t size() const { return _end - _data; } - - T & operator[](std::size_t index) { return _data[index]; } - - T const & operator[](std::size_t index) const { return _data[index]; } - - /** - * Erase the item from the list at the given position. - */ - void erase(T * pos) { - --_end; - while (pos != _end) { - *pos = *(pos + 1); - ++pos; - } - } - - /** - * Make space for an item in the list at a given position. - * If inserting the item makes the list longer than max_size then - * the end of the list is discarded. - * Returns the where the item is inserted. - */ - T * insert(T * pos) { - if (_end != _data + max_size) { - ++_end; - } else if (pos == _end) { - --pos; - } - T * tmp = pos; - while (tmp != _end - 1) { - *(tmp + 1) = *tmp; - ++tmp; - } - return pos; - } - - /** - * Make space for an item in the list at the start of the list - */ - T * insert() { return insert(begin()); } - - /** - * Insert an item into the list at a given position. - * If inserting the item makes the list longer than max_size then - * the end of the list is discarded. - * Returns the where the item is inserted. - */ - T * insert(T * pos, T const & value) { - pos = insert(pos); - *pos = value; - return pos; - } - - List & operator=(List const & other) { - if (this == &other) { - return *this; - } - T * this_pos = _data; - T * const other_pos = other._data; - while (other_pos != other._end) { - *this_pos = *other; - ++this_pos; - ++other_pos; - } - _end = this_pos; - return *this; - } - -private: - T * _end; - T _data[max_size]; -}; - -} // namespace axolotl - -#endif /* AXOLOTL_LIST_HH_ */ diff --git a/include/axolotl/memory.hh b/include/axolotl/memory.hh deleted file mode 100644 index 68b577d..0000000 --- a/include/axolotl/memory.hh +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include - -namespace axolotl { - -/** Clear the memory held in the buffer */ -void unset( - void volatile * buffer, std::size_t buffer_length -); - -/** Clear the memory backing an object */ -template -void unset(T & value) { - unset(reinterpret_cast(&value), sizeof(T)); -} - -/** Check if two buffers are equal in constant time. */ -bool is_equal( - std::uint8_t const * buffer_a, - std::uint8_t const * buffer_b, - std::size_t length -); - -} // namespace axolotl diff --git a/include/axolotl/message.hh b/include/axolotl/message.hh deleted file mode 100644 index 4d7a1c7..0000000 --- a/include/axolotl/message.hh +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include - - -namespace axolotl { - -/** - * The length of the buffer needed to hold a message. - */ -std::size_t encode_message_length( - std::uint32_t counter, - std::size_t ratchet_key_length, - std::size_t ciphertext_length, - std::size_t mac_length -); - - -struct MessageWriter { - std::uint8_t * ratchet_key; - std::uint8_t * ciphertext; -}; - - -struct MessageReader { - std::uint8_t version; - bool has_counter; - std::uint32_t counter; - std::uint8_t const * input; std::size_t input_length; - std::uint8_t const * ratchet_key; std::size_t ratchet_key_length; - std::uint8_t const * ciphertext; std::size_t ciphertext_length; -}; - - -/** - * Writes the message headers into the output buffer. - * Populates the writer struct with pointers into the output buffer. - */ -void encode_message( - MessageWriter & writer, - std::uint8_t version, - std::uint32_t counter, - std::size_t ratchet_key_length, - std::size_t ciphertext_length, - std::uint8_t * output -); - - -/** - * Reads the message headers from the input buffer. - * Populates the reader struct with pointers into the input buffer. - */ -void decode_message( - MessageReader & reader, - std::uint8_t const * input, std::size_t input_length, - std::size_t mac_length -); - - -struct PreKeyMessageWriter { - std::uint8_t * identity_key; - std::uint8_t * base_key; - std::uint8_t * message; -}; - - -struct PreKeyMessageReader { - std::uint8_t version; - bool has_one_time_key_id; - std::uint32_t one_time_key_id; - std::uint8_t const * identity_key; std::size_t identity_key_length; - std::uint8_t const * base_key; std::size_t base_key_length; - std::uint8_t const * message; std::size_t message_length; -}; - - -/** - * The length of the buffer needed to hold a message. - */ -std::size_t encode_one_time_key_message_length( - std::uint32_t one_time_key_id, - std::size_t identity_key_length, - std::size_t base_key_length, - std::size_t message_length -); - - -/** - * Writes the message headers into the output buffer. - * Populates the writer struct with pointers into the output buffer. - */ -void encode_one_time_key_message( - PreKeyMessageWriter & writer, - std::uint8_t version, - std::uint32_t one_time_key_id, - std::size_t identity_key_length, - std::size_t base_key_length, - std::size_t message_length, - std::uint8_t * output -); - - -/** - * Reads the message headers from the input buffer. - * Populates the reader struct with pointers into the input buffer. - */ -void decode_one_time_key_message( - PreKeyMessageReader & reader, - std::uint8_t const * input, std::size_t input_length -); - - -} // namespace axolotl diff --git a/include/axolotl/pickle.hh b/include/axolotl/pickle.hh deleted file mode 100644 index 8134971..0000000 --- a/include/axolotl/pickle.hh +++ /dev/null @@ -1,178 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef AXOLOTL_PICKLE_HH_ -#define AXOLOTL_PICKLE_HH_ - -#include "axolotl/list.hh" -#include "axolotl/crypto.hh" - -#include -#include - -namespace axolotl { - -static std::size_t pickle_length( - const std::uint32_t & value -) { - return 4; -} - - -static std::uint8_t * pickle( - std::uint8_t * pos, - std::uint32_t value -) { - pos += 4; - for (unsigned i = 4; i--;) { *(--pos) = value; value >>= 8; } - return pos + 4; -} - - -static std::uint8_t const * unpickle( - std::uint8_t const * pos, std::uint8_t const * end, - std::uint32_t & value -) { - value = 0; - if (end - pos < 4) return end; - for (unsigned i = 4; i--;) { value <<= 8; value |= *(pos++); } - return pos; -} - -static std::size_t pickle_length( - const bool & value -) { - return 1; -} - - -static std::uint8_t * pickle( - std::uint8_t * pos, - bool value -) { - *(pos++) = value ? 1 : 0; - return pos; -} - - -static std::uint8_t const * unpickle( - std::uint8_t const * pos, std::uint8_t const * end, - bool & value -) { - if (pos == end) return end; - value = *(pos++); - return pos; -} - - - -template -std::size_t pickle_length( - axolotl::List const & list -) { - std::size_t length = pickle_length(std::uint32_t(list.size())); - for (auto const & value : list) { - length += pickle_length(value); - } - return length; -} - - -template -std::uint8_t * pickle( - std::uint8_t * pos, - axolotl::List const & list -) { - pos = pickle(pos, std::uint32_t(list.size())); - for (auto const & value : list) { - pos = pickle(pos, value); - } - return pos; -} - - -template -std::uint8_t const * unpickle( - std::uint8_t const * pos, std::uint8_t const * end, - axolotl::List & list -) { - std::uint32_t size; - pos = unpickle(pos, end, size); - while (size--) { - T * value = list.insert(list.end()); - pos = unpickle(pos, end, *value); - } - return pos; -} - - -static std::uint8_t * pickle_bytes( - std::uint8_t * pos, - std::uint8_t const * bytes, std::size_t bytes_length -) { - std::memcpy(pos, bytes, bytes_length); - return pos + bytes_length; -} - - -static std::uint8_t const * unpickle_bytes( - std::uint8_t const * pos, std::uint8_t const * end, - std::uint8_t * bytes, std::size_t bytes_length -) { - if (end - pos < bytes_length) return end; - std::memcpy(bytes, pos, bytes_length); - return pos + bytes_length; -} - - -std::size_t pickle_length( - const Curve25519PublicKey & value -); - - -std::uint8_t * pickle( - std::uint8_t * pos, - const Curve25519PublicKey & value -); - - -std::uint8_t const * unpickle( - std::uint8_t const * pos, std::uint8_t const * end, - Curve25519PublicKey & value -); - - -std::size_t pickle_length( - const Curve25519KeyPair & value -); - - -std::uint8_t * pickle( - std::uint8_t * pos, - const Curve25519KeyPair & value -); - - -std::uint8_t const * unpickle( - std::uint8_t const * pos, std::uint8_t const * end, - Curve25519KeyPair & value -); - - -} // namespace axolotl - - - - -#endif /* AXOLOTL_PICKLE_HH */ diff --git a/include/axolotl/ratchet.hh b/include/axolotl/ratchet.hh deleted file mode 100644 index 0874cf0..0000000 --- a/include/axolotl/ratchet.hh +++ /dev/null @@ -1,177 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "axolotl/crypto.hh" -#include "axolotl/list.hh" -#include "axolotl/error.hh" - -namespace axolotl { - -class Cipher; - -typedef std::uint8_t SharedKey[32]; - - -struct ChainKey { - std::uint32_t index; - SharedKey key; -}; - - -struct MessageKey { - std::uint32_t index; - SharedKey key; -}; - - -struct SenderChain { - Curve25519KeyPair ratchet_key; - ChainKey chain_key; -}; - - -struct ReceiverChain { - Curve25519PublicKey ratchet_key; - ChainKey chain_key; -}; - - -struct SkippedMessageKey { - Curve25519PublicKey ratchet_key; - MessageKey message_key; -}; - - -static std::size_t const MAX_RECEIVER_CHAINS = 5; -static std::size_t const MAX_SKIPPED_MESSAGE_KEYS = 40; - - -struct KdfInfo { - std::uint8_t const * root_info; - std::size_t root_info_length; - std::uint8_t const * ratchet_info; - std::size_t ratchet_info_length; -}; - - -struct Ratchet { - - Ratchet( - KdfInfo const & kdf_info, - Cipher const & ratchet_cipher - ); - - /** A some strings identifying the application to feed into the KDF. */ - KdfInfo const & kdf_info; - - /** The AEAD cipher to use for encrypting messages. */ - Cipher const & ratchet_cipher; - - /** The last error that happened encrypting or decrypting a message. */ - ErrorCode last_error; - - /** 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. */ - SharedKey root_key; - - /** The sender chain is used to send messages. Each time a new ephemeral - * key is received from the remote server we generate a new sender chain - * with a new empheral key when we next send a message. */ - List sender_chain; - - /** The receiver chain is used to decrypt received messages. We store the - * last few chains so we can decrypt any out of order messages we haven't - * received yet. */ - List receiver_chains; - - /** List of message keys we've skipped over when advancing the receiver - * chain. */ - List skipped_message_keys; - - /** Initialise the session using a shared secret and the public part of the - * remote's first ratchet key */ - void initialise_as_bob( - std::uint8_t const * shared_secret, std::size_t shared_secret_length, - Curve25519PublicKey const & their_ratchet_key - ); - - /** Initialise the session using a shared secret and the public/private key - * pair for the first ratchet key */ - void initialise_as_alice( - std::uint8_t const * shared_secret, std::size_t shared_secret_length, - Curve25519KeyPair const & our_ratchet_key - ); - - /** The number of bytes of output the encrypt method will write for - * a given message length. */ - std::size_t encrypt_output_length( - std::size_t plaintext_length - ); - - /** The number of bytes of random data the encrypt method will need to - * encrypt a message. This will be 32 bytes if the session needs to - * generate a new ephemeral key, or will be 0 bytes otherwise.*/ - std::size_t encrypt_random_length(); - - /** Encrypt some plain-text. Returns the length of the encrypted message - * or std::size_t(-1) on failure. On failure last_error will be set with - * an error code. The last_error will be NOT_ENOUGH_RANDOM if the number - * of random bytes is too small. The last_error will be - * OUTPUT_BUFFER_TOO_SMALL if the output buffer is too small. */ - std::size_t encrypt( - std::uint8_t const * plaintext, std::size_t plaintext_length, - std::uint8_t const * random, std::size_t random_length, - std::uint8_t * output, std::size_t max_output_length - ); - - /** An upper bound on the number of bytes of plain-text the decrypt method - * will write for a given input message length. */ - std::size_t decrypt_max_plaintext_length( - std::uint8_t const * input, std::size_t input_length - ); - - /** Decrypt a message. Returns the length of the decrypted plain-text or - * std::size_t(-1) on failure. On failure last_error will be set with an - * error code. The last_error will be OUTPUT_BUFFER_TOO_SMALL if the - * plain-text buffer is too small. The last_error will be - * BAD_MESSAGE_VERSION if the message was encrypted with an unsupported - * version of the protocol. The last_error will be BAD_MESSAGE_FORMAT if - * the message headers could not be decoded. The last_error will be - * BAD_MESSAGE_MAC if the message could not be verified */ - std::size_t decrypt( - std::uint8_t const * input, std::size_t input_length, - std::uint8_t * plaintext, std::size_t max_plaintext_length - ); -}; - - -std::size_t pickle_length( - Ratchet const & value -); - - -std::uint8_t * pickle( - std::uint8_t * pos, - Ratchet const & value -); - - -std::uint8_t const * unpickle( - std::uint8_t const * pos, std::uint8_t const * end, - Ratchet & value -); - - -} // namespace axolotl diff --git a/include/axolotl/session.hh b/include/axolotl/session.hh deleted file mode 100644 index 17f1653..0000000 --- a/include/axolotl/session.hh +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright 2015 OpenMarket Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef AXOLOTL_SESSION_HH_ -#define AXOLOTL_SESSION_HH_ - -#include "axolotl/ratchet.hh" - -namespace axolotl { - -class Account; - -struct RemoteKey { - std::uint32_t id; - Curve25519PublicKey key; -}; - - -enum struct MessageType { - PRE_KEY = 0, - MESSAGE = 1, -}; - - -struct Session { - - Session(); - - Ratchet ratchet; - ErrorCode last_error; - - bool received_message; - - RemoteKey alice_identity_key; - Curve25519PublicKey alice_base_key; - std::uint32_t bob_one_time_key_id; - - - std::size_t new_outbound_session_random_length(); - - std::size_t new_outbound_session( - Account const & local_account, - Curve25519PublicKey const & identity_key, - RemoteKey const & one_time_key, - std::uint8_t const * random, std::size_t random_length - ); - - std::size_t new_inbound_session( - Account & local_account, - std::uint8_t const * one_time_key_message, std::size_t message_length - ); - - bool matches_inbound_session( - std::uint8_t const * one_time_key_message, std::size_t message_length - ); - - MessageType encrypt_message_type(); - - std::size_t encrypt_message_length( - std::size_t plaintext_length - ); - - std::size_t encrypt_random_length(); - - std::size_t encrypt( - std::uint8_t const * plaintext, std::size_t plaintext_length, - std::uint8_t const * random, std::size_t random_length, - std::uint8_t * message, std::size_t message_length - ); - - std::size_t decrypt_max_plaintext_length( - MessageType message_type, - std::uint8_t const * message, std::size_t message_length - ); - - std::size_t decrypt( - MessageType message_type, - std::uint8_t const * message, std::size_t message_length, - std::uint8_t * plaintext, std::size_t max_plaintext_length - ); -}; - - -std::size_t pickle_length( - Session const & value -); - - -std::uint8_t * pickle( - std::uint8_t * pos, - Session const & value -); - - -std::uint8_t const * unpickle( - std::uint8_t const * pos, std::uint8_t const * end, - Session & value -); - - -} // namespace axolotl - -#endif /* AXOLOTL_SESSION_HH_ */ diff --git a/include/olm/account.hh b/include/olm/account.hh new file mode 100644 index 0000000..8094a25 --- /dev/null +++ b/include/olm/account.hh @@ -0,0 +1,84 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OLM_ACCOUNT_HH_ +#define OLM_ACCOUNT_HH_ + +#include "olm/list.hh" +#include "olm/crypto.hh" +#include "olm/error.hh" + +#include + +namespace olm { + + +struct LocalKey { + std::uint32_t id; + Curve25519KeyPair key; +}; + + +struct SignedKey : LocalKey { + std::uint8_t signature[64]; +}; + + +static std::size_t const MAX_ONE_TIME_KEYS = 100; + +struct Account { + LocalKey identity_key; + LocalKey last_resort_one_time_key; + List one_time_keys; + ErrorCode last_error; + + /** Number of random bytes needed to create a new account */ + std::size_t new_account_random_length(); + + /** Create a new account. Returns NOT_ENOUGH_RANDOM if the number of random + * bytes is too small. */ + std::size_t new_account( + uint8_t const * random, std::size_t random_length + ); + + LocalKey const * lookup_key( + std::uint32_t id + ); + + std::size_t remove_key( + std::uint32_t id + ); +}; + + +std::size_t pickle_length( + Account const & value +); + + +std::uint8_t * pickle( + std::uint8_t * pos, + Account const & value +); + + +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + Account & value +); + + +} // namespace olm + +#endif /* OLM_ACCOUNT_HH_ */ diff --git a/include/olm/base64.hh b/include/olm/base64.hh new file mode 100644 index 0000000..0a7435b --- /dev/null +++ b/include/olm/base64.hh @@ -0,0 +1,49 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef AXOLOLT_BASE64_HH_ +#define AXOLOLT_BASE64_HH_ + +#include +#include + +namespace olm { + + +std::size_t encode_base64_length( + std::size_t input_length +); + + +void encode_base64( + std::uint8_t const * input, std::size_t input_length, + std::uint8_t * output +); + + +std::size_t decode_base64_length( + std::size_t input_length +); + + +void decode_base64( + std::uint8_t const * input, std::size_t input_length, + std::uint8_t * output +); + + +} // namespace olm + + +#endif /* AXOLOLT_BASE64_HH_ */ diff --git a/include/olm/cipher.hh b/include/olm/cipher.hh new file mode 100644 index 0000000..f71b3af --- /dev/null +++ b/include/olm/cipher.hh @@ -0,0 +1,128 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OLM_CIPHER_HH_ +#define OLM_CIPHER_HH_ + +#include +#include + +namespace olm { + +class Cipher { +public: + virtual ~Cipher(); + + /** + * Returns the length of the message authentication code that will be + * appended to the output. + */ + virtual std::size_t mac_length() const = 0; + + /** + * Returns the length of cipher-text for a given length of plain-text. + */ + virtual std::size_t encrypt_ciphertext_length( + std::size_t plaintext_length + ) const = 0; + + /* + * Encrypts the plain-text into the output buffer and authenticates the + * contents of the output buffer covering both cipher-text and any other + * associated data in the output buffer. + * + * |---------------------------------------output_length-->| + * output |--ciphertext_length-->| |---mac_length-->| + * ciphertext + * + * Returns std::size_t(-1) if the length of the cipher-text or the output + * buffer is too small. Otherwise returns the length of the output buffer. + */ + virtual std::size_t encrypt( + std::uint8_t const * key, std::size_t key_length, + std::uint8_t const * plaintext, std::size_t plaintext_length, + std::uint8_t * ciphertext, std::size_t ciphertext_length, + std::uint8_t * output, std::size_t output_length + ) const = 0; + + /** + * Returns the maximum length of plain-text that a given length of + * cipher-text can contain. + */ + virtual std::size_t decrypt_max_plaintext_length( + std::size_t ciphertext_length + ) const = 0; + + /** + * Authenticates the input and decrypts the cipher-text into the plain-text + * buffer. + * + * |----------------------------------------input_length-->| + * input |--ciphertext_length-->| |---mac_length-->| + * ciphertext + * + * Returns std::size_t(-1) if the length of the plain-text buffer is too + * small or if the authentication check fails. Otherwise returns the length + * of the plain text. + */ + virtual std::size_t decrypt( + std::uint8_t const * key, std::size_t key_length, + std::uint8_t const * input, std::size_t input_length, + std::uint8_t const * ciphertext, std::size_t ciphertext_length, + std::uint8_t * plaintext, std::size_t max_plaintext_length + ) const = 0; +}; + + +class CipherAesSha256 : public Cipher { +public: + CipherAesSha256( + std::uint8_t const * kdf_info, std::size_t kdf_info_length + ); + + virtual std::size_t mac_length() const; + + virtual std::size_t encrypt_ciphertext_length( + std::size_t plaintext_length + ) const; + + virtual std::size_t encrypt( + std::uint8_t const * key, std::size_t key_length, + std::uint8_t const * plaintext, std::size_t plaintext_length, + std::uint8_t * ciphertext, std::size_t ciphertext_length, + std::uint8_t * output, std::size_t output_length + ) const; + + virtual std::size_t decrypt_max_plaintext_length( + std::size_t ciphertext_length + ) const; + + virtual std::size_t decrypt( + std::uint8_t const * key, std::size_t key_length, + std::uint8_t const * input, std::size_t input_length, + std::uint8_t const * ciphertext, std::size_t ciphertext_length, + std::uint8_t * plaintext, std::size_t max_plaintext_length + ) const; + +private: + std::uint8_t const * kdf_info; + std::size_t kdf_info_length; +}; + + +} // namespace + + +#endif /* OLM_CIPHER_HH_ */ diff --git a/include/olm/crypto.hh b/include/olm/crypto.hh new file mode 100644 index 0000000..b299e12 --- /dev/null +++ b/include/olm/crypto.hh @@ -0,0 +1,148 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OLM_CRYPTO_HH_ +#define OLM_CRYPTO_HH_ + +#include +#include + +namespace olm { + + +struct Curve25519PublicKey { + static const int LENGTH = 32; + std::uint8_t public_key[32]; +}; + + +struct Curve25519KeyPair : public Curve25519PublicKey { + static const int LENGTH = 64; + std::uint8_t private_key[32]; +}; + + +/** Generate a curve25519 key pair from 32 random bytes. */ +void generate_key( + std::uint8_t const * random_32_bytes, + Curve25519KeyPair & key_pair +); + + +const std::size_t CURVE25519_SHARED_SECRET_LENGTH = 32; + + +/** Create a shared secret using our private key and their public key. + * The output buffer must be at least 32 bytes long. */ +void curve25519_shared_secret( + Curve25519KeyPair const & our_key, + Curve25519PublicKey const & their_key, + std::uint8_t * output +); + + +/** Signs the message using our private key. + * The output buffer must be at least 64 bytes long. */ +void curve25519_sign( + Curve25519KeyPair const & our_key, + std::uint8_t const * message, std::size_t message_length, + std::uint8_t * output +); + + +/** Verify thei message using their public key. + * The signature input buffer must be 64 bytes long. + * Returns true if the signature is valid. */ +bool curve25519_verify( + Curve25519PublicKey const & their_key, + std::uint8_t const * message, std::size_t message_length, + std::uint8_t const * signature +); + + +struct Aes256Key { + static const int LENGTH = 32; + std::uint8_t key[32]; +}; + + +struct Aes256Iv { + static const int LENGTH = 16; + std::uint8_t iv[16]; +}; + + +/** The length of output the aes_encrypt_cbc function will write */ +std::size_t aes_encrypt_cbc_length( + std::size_t input_length +); + + +/** Encrypts the input using AES256 in CBC mode with PKCS#7 padding. + * The output buffer must be big enough to hold the output including padding */ +void aes_encrypt_cbc( + Aes256Key const & key, + Aes256Iv const & iv, + std::uint8_t const * input, std::size_t input_length, + std::uint8_t * output +); + + +/** Decrypts the input using AES256 in CBC mode. The output buffer must be at + * least the same size as the input buffer. Returns the length of the plaintext + * without padding on success or std::size_t(-1) if the padding is invalid. + */ +std::size_t aes_decrypt_cbc( + Aes256Key const & key, + Aes256Iv const & iv, + std::uint8_t const * input, std::size_t input_length, + std::uint8_t * output +); + + +/** Computes SHA-256 of the input. The output buffer must be a least 32 + * bytes long. */ +void sha256( + std::uint8_t const * input, std::size_t input_length, + std::uint8_t * output +); + + +const std::size_t HMAC_SHA256_OUTPUT_LENGTH = 32; + + +/** HMAC: Keyed-Hashing for Message Authentication + * http://tools.ietf.org/html/rfc2104 + * Computes HMAC-SHA-256 of the input for the key. The output buffer must + * be at least 32 bytes long. */ +void hmac_sha256( + std::uint8_t const * key, std::size_t key_length, + std::uint8_t const * input, std::size_t input_length, + std::uint8_t * output +); + + +/** HMAC-based Key Derivation Function (HKDF) + * https://tools.ietf.org/html/rfc5869 + * Derives key material from the input bytes. */ +void hkdf_sha256( + std::uint8_t const * input, std::size_t input_length, + std::uint8_t const * info, std::size_t info_length, + std::uint8_t const * salt, std::size_t salt_length, + std::uint8_t * output, std::size_t output_length +); + +} // namespace olm + +#endif /* OLM_CRYPTO_HH_ */ diff --git a/include/olm/error.hh b/include/olm/error.hh new file mode 100644 index 0000000..960de72 --- /dev/null +++ b/include/olm/error.hh @@ -0,0 +1,34 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ERROR_HH_ +#define ERROR_HH_ + +namespace olm { + +enum struct ErrorCode { + SUCCESS = 0, /*!< There wasn't an error */ + NOT_ENOUGH_RANDOM = 1, /*!< Not enough entropy was supplied */ + OUTPUT_BUFFER_TOO_SMALL = 2, /*!< Supplied output buffer is too small */ + BAD_MESSAGE_VERSION = 3, /*!< The message version is unsupported */ + BAD_MESSAGE_FORMAT = 4, /*!< The message couldn't be decoded */ + BAD_MESSAGE_MAC = 5, /*!< The message couldn't be decrypted */ + BAD_MESSAGE_KEY_ID = 6, /*!< The message references an unknown key id */ + INVALID_BASE64 = 7, /*!< The input base64 was invalid */ + BAD_ACCOUNT_KEY = 8, /*!< The supplied account key is invalid */ +}; + +} // namespace olm + +#endif /* ERROR_HH_ */ diff --git a/include/olm/list.hh b/include/olm/list.hh new file mode 100644 index 0000000..e4bf951 --- /dev/null +++ b/include/olm/list.hh @@ -0,0 +1,119 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OLM_LIST_HH_ +#define OLM_LIST_HH_ + +#include + +namespace olm { + +template +class List { +public: + List() : _end(_data) {} + + typedef T * iterator; + typedef T const * const_iterator; + + T * begin() { return _data; } + T * end() { return _end; } + T const * begin() const { return _data; } + T const * end() const { return _end; } + + /** + * Is the list empty? + */ + bool empty() const { return _end == _data; } + + /** + * The number of items in the list. + */ + std::size_t size() const { return _end - _data; } + + T & operator[](std::size_t index) { return _data[index]; } + + T const & operator[](std::size_t index) const { return _data[index]; } + + /** + * Erase the item from the list at the given position. + */ + void erase(T * pos) { + --_end; + while (pos != _end) { + *pos = *(pos + 1); + ++pos; + } + } + + /** + * Make space for an item in the list at a given position. + * If inserting the item makes the list longer than max_size then + * the end of the list is discarded. + * Returns the where the item is inserted. + */ + T * insert(T * pos) { + if (_end != _data + max_size) { + ++_end; + } else if (pos == _end) { + --pos; + } + T * tmp = pos; + while (tmp != _end - 1) { + *(tmp + 1) = *tmp; + ++tmp; + } + return pos; + } + + /** + * Make space for an item in the list at the start of the list + */ + T * insert() { return insert(begin()); } + + /** + * Insert an item into the list at a given position. + * If inserting the item makes the list longer than max_size then + * the end of the list is discarded. + * Returns the where the item is inserted. + */ + T * insert(T * pos, T const & value) { + pos = insert(pos); + *pos = value; + return pos; + } + + List & operator=(List const & other) { + if (this == &other) { + return *this; + } + T * this_pos = _data; + T * const other_pos = other._data; + while (other_pos != other._end) { + *this_pos = *other; + ++this_pos; + ++other_pos; + } + _end = this_pos; + return *this; + } + +private: + T * _end; + T _data[max_size]; +}; + +} // namespace olm + +#endif /* OLM_LIST_HH_ */ diff --git a/include/olm/memory.hh b/include/olm/memory.hh new file mode 100644 index 0000000..b19c74b --- /dev/null +++ b/include/olm/memory.hh @@ -0,0 +1,38 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +namespace olm { + +/** Clear the memory held in the buffer */ +void unset( + void volatile * buffer, std::size_t buffer_length +); + +/** Clear the memory backing an object */ +template +void unset(T & value) { + unset(reinterpret_cast(&value), sizeof(T)); +} + +/** Check if two buffers are equal in constant time. */ +bool is_equal( + std::uint8_t const * buffer_a, + std::uint8_t const * buffer_b, + std::size_t length +); + +} // namespace olm diff --git a/include/olm/message.hh b/include/olm/message.hh new file mode 100644 index 0000000..fefdd20 --- /dev/null +++ b/include/olm/message.hh @@ -0,0 +1,126 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + + +namespace olm { + +/** + * The length of the buffer needed to hold a message. + */ +std::size_t encode_message_length( + std::uint32_t counter, + std::size_t ratchet_key_length, + std::size_t ciphertext_length, + std::size_t mac_length +); + + +struct MessageWriter { + std::uint8_t * ratchet_key; + std::uint8_t * ciphertext; +}; + + +struct MessageReader { + std::uint8_t version; + bool has_counter; + std::uint32_t counter; + std::uint8_t const * input; std::size_t input_length; + std::uint8_t const * ratchet_key; std::size_t ratchet_key_length; + std::uint8_t const * ciphertext; std::size_t ciphertext_length; +}; + + +/** + * Writes the message headers into the output buffer. + * Populates the writer struct with pointers into the output buffer. + */ +void encode_message( + MessageWriter & writer, + std::uint8_t version, + std::uint32_t counter, + std::size_t ratchet_key_length, + std::size_t ciphertext_length, + std::uint8_t * output +); + + +/** + * Reads the message headers from the input buffer. + * Populates the reader struct with pointers into the input buffer. + */ +void decode_message( + MessageReader & reader, + std::uint8_t const * input, std::size_t input_length, + std::size_t mac_length +); + + +struct PreKeyMessageWriter { + std::uint8_t * identity_key; + std::uint8_t * base_key; + std::uint8_t * message; +}; + + +struct PreKeyMessageReader { + std::uint8_t version; + bool has_one_time_key_id; + std::uint32_t one_time_key_id; + std::uint8_t const * identity_key; std::size_t identity_key_length; + std::uint8_t const * base_key; std::size_t base_key_length; + std::uint8_t const * message; std::size_t message_length; +}; + + +/** + * The length of the buffer needed to hold a message. + */ +std::size_t encode_one_time_key_message_length( + std::uint32_t one_time_key_id, + std::size_t identity_key_length, + std::size_t base_key_length, + std::size_t message_length +); + + +/** + * Writes the message headers into the output buffer. + * Populates the writer struct with pointers into the output buffer. + */ +void encode_one_time_key_message( + PreKeyMessageWriter & writer, + std::uint8_t version, + std::uint32_t one_time_key_id, + std::size_t identity_key_length, + std::size_t base_key_length, + std::size_t message_length, + std::uint8_t * output +); + + +/** + * Reads the message headers from the input buffer. + * Populates the reader struct with pointers into the input buffer. + */ +void decode_one_time_key_message( + PreKeyMessageReader & reader, + std::uint8_t const * input, std::size_t input_length +); + + +} // namespace olm diff --git a/include/olm/olm.hh b/include/olm/olm.hh new file mode 100644 index 0000000..fca35c4 --- /dev/null +++ b/include/olm/olm.hh @@ -0,0 +1,295 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OLM_HH_ +#define OLM_HH_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static const size_t OLM_MESSAGE_TYPE_PRE_KEY = 0; +static const size_t OLM_MESSAGE_TYPE_MESSAGE = 1; + +struct OlmAccount; +struct OlmSession; + +/** The size of an account object in bytes */ +size_t olm_account_size(); + +/** The size of a session object in bytes */ +size_t olm_session_size(); + +/** Initialise an account object using the supplied memory + * The supplied memory must be at least olm_account_size() bytes */ +OlmAccount * olm_account( + void * memory +); + +/** Initialise a session object using the supplied memory + * The supplied memory must be at least olm_session_size() bytes */ +OlmSession * olm_session( + void * memory +); + +/** The value that olm will return from a function if there was an error */ +size_t olm_error(); + +/** A null terminated string describing the most recent error to happen to an + * account */ +const char * olm_account_last_error( + OlmSession * account +); + +/** A null terminated string describing the most recent error to happen to a + * session */ +const char * olm_session_last_error( + OlmSession * session +); + +/** Returns the number of bytes needed to store an account */ +size_t olm_pickle_account_length( + OlmAccount * account +); + +/** Returns the number of bytes needed to store a session */ +size_t olm_pickle_session_length( + OlmSession * session +); + +/** Stores an account as a base64 string. Encrypts the account using the + * supplied key. Returns the length of the pickled account on success. + * Returns olm_error() on failure. If the pickle output buffer + * is smaller than olm_pickle_account_length() then + * olm_account_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" */ +size_t olm_pickle_account( + OlmAccount * account, + void const * key, size_t key_length, + void * pickled, size_t pickled_length +); + +/** Stores a session as a base64 string. Encrypts the session using the + * supplied key. Returns the length of the pickled session on success. + * Returns olm_error() on failure. If the pickle output buffer + * is smaller than olm_pickle_session_length() then + * olm_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" */ +size_t olm_pickle_session( + OlmSession * session, + void const * key, size_t key_length, + void * pickled, size_t pickled_length +); + +/** Loads an account from a pickled base64 string. Decrypts the account using + * the supplied key. Returns olm_error() on failure. If the key doesn't + * match the one used to encrypt the account then olm_account_last_error() + * will be "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then + * olm_account_last_error() will be "INVALID_BASE64". The input pickled + * buffer is destroyed */ +size_t olm_unpickle_account( + OlmAccount * account, + void const * key, size_t key_length, + void * pickled, size_t pickled_length +); + +/** Loads a session from a pickled base64 string. Decrypts the session using + * the supplied key. Returns olm_error() on failure. If the key doesn't + * match the one used to encrypt the account then olm_session_last_error() + * will be "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then + * olm_session_last_error() will be "INVALID_BASE64". The input pickled + * buffer is destroyed */ +size_t olm_unpickle_session( + OlmSession * session, + void const * key, size_t key_length, + void * pickled, size_t pickled_length +); + +/** The number of random bytes needed to create an account.*/ +size_t olm_create_account_random_length( + OlmAccount * account +); + +/** Creates a new account. Returns olm_error() on failure. If weren't + * enough random bytes then olm_account_last_error() will be + * "NOT_ENOUGH_RANDOM" */ +size_t olm_create_account( + OlmAccount * account, + void const * random, size_t random_length +); + +/** The size of the output buffer needed to hold the identity keys */ +size_t olm_account_identity_keys_length( + OlmAccount * account +); + +/** Writes the public parts of the identity keys for the account into the + * identity_keys output buffer. The output is formatted as though it was + * created with sprintf(output, "[[%10d,\"%43s\"]\n]", key_id, key_base64). + * The output can either be parsed as fixed width using the above format or by + * a JSON parser. Returns olm_error() on failure. If the identity_keys + * buffer was too small then olm_account_last_error() will be + * "OUTPUT_BUFFER_TOO_SMALL". */ +size_t olm_account_identity_keys( + OlmAccount * account, + void * identity_keys, size_t identity_key_length +); + +/** The size of the output buffer needed to hold the one time keys */ +size_t olm_account_one_time_keys_length( + OlmAccount * account +); + +/** Writes the public parts of the one time keys for the account into the + * one_time_keys output buffer. The first key will be formatted as though it was + * created with sprintf(output, "[[%10d,\"%43s\"]\n", key_id, key_base64). + * subsequent keys are formatted with ",[%10d,\"%43s\"]\n". The final byte of + * output will be "]". The output can either be parsed as fixed width using + * the above format or by a JSON parser. Returns olm_error() on failure. + * If the one_time_keys buffer was too small then olm_account_last_error() + * will be "OUTPUT_BUFFER_TOO_SMALL". */ +size_t olm_account_one_time_keys( + OlmAccount * account, + void * one_time_keys, size_t one_time_keys_length +); + +/* TODO: Add methods for marking keys as used, generating new keys, and + * tracking which keys have been uploaded to the central servers */ + +/** The number of random bytes needed to create an outbound session */ +size_t olm_create_outbound_session_random_length( + OlmSession * session +); + +/** Creates a new out-bound session for sending messages to a given identity_key + * and one_time_key. Returns olm_error() on failure. If the keys couldn't be + * decoded as base64 then olm_session_last_error() will be "INVALID_BASE64" + * If there weren't enough random bytes then olm_session_last_error() will + * be "NOT_ENOUGH_RANDOM". */ +size_t olm_create_outbound_session( + OlmSession * session, + OlmAccount * account, + void const * their_identity_key, size_t their_identity_key_length, + unsigned their_one_time_key_id, + void const * their_one_time_key, size_t their_one_time_key_length, + void const * random, size_t random_length +); + +/** Create a new in-bound session for sending/receiving messages from an + * incoming PRE_KEY message. Returns olm_error() on failure. If the base64 + * couldn't be decoded then olm_session_last_error will be "INVALID_BASE64". + * If the message was for an unsupported protocol version then + * olm_session_last_error() will be "BAD_MESSAGE_VERSION". If the message + * couldn't be decoded then then olm_session_last_error() will be + * "BAD_MESSAGE_FORMAT". If the message refers to an unknown one time + * key then olm_session_last_error() will be "BAD_MESSAGE_KEY_ID". */ +size_t olm_create_inbound_session( + OlmSession * session, + OlmAccount * account, + void * one_time_key_message, size_t message_length +); + +/** Checks if the PRE_KEY message is for this in-bound session. This can happen + * if multiple messages are sent to this account before this account sends a + * message in reply. Returns olm_error() on failure. If the base64 + * couldn't be decoded then olm_session_last_error will be "INVALID_BASE64". + * If the message was for an unsupported protocol version then + * olm_session_last_error() will be "BAD_MESSAGE_VERSION". If the message + * couldn't be decoded then then olm_session_last_error() will be + * "BAD_MESSAGE_FORMAT". */ +size_t olm_matches_inbound_session( + OlmSession * session, + void * one_time_key_message, size_t message_length +); + +/** Removes the one time keys that the session used from the account. Returns + * olm_error() on failure. If the account doesn't have any matching one time + * keys then olm_account_last_error() will be "BAD_MESSAGE_KEY_ID". */ +size_t olm_remove_one_time_keys( + OlmAccount * account, + OlmSession * session +); + +/** The type of the next message that olm_encrypt() will return. Returns + * OLM_MESSAGE_TYPE_PRE_KEY if the message will be a PRE_KEY message. + * Returns OLM_MESSAGE_TYPE_MESSAGE if the message will be a normal message. + * Returns olm_error on failure. */ +size_t olm_encrypt_message_type( + OlmSession * session +); + +/** The number of random bytes needed to encrypt the next message. */ +size_t olm_encrypt_random_length( + OlmSession * session +); + +/** The size of the next message in bytes for the given number of plain-text + * bytes. */ +size_t olm_encrypt_message_length( + OlmSession * session, + size_t plaintext_length +); + +/** Encrypts a message using the session. Returns the length of the message in + * bytes on success. Writes the message as base64 into the message buffer. + * Returns olm_error() on failure. If the message buffer is too small then + * olm_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". If there + * weren't enough random bytes then olm_session_last_error() will be + * "NOT_ENOUGH_RANDOM". */ +size_t olm_encrypt( + OlmSession * session, + void const * plaintext, size_t plaintext_length, + void const * random, size_t random_length, + void * message, size_t message_length +); + +/** The maximum number of bytes of plain-text a given message could decode to. + * The actual size could be different due to padding. The input message buffer + * is destroyed. Returns olm_error() on failure. If the message base64 + * couldn't be decoded then olm_session_last_error() will be + * "INVALID_BASE64". If the message is for an unsupported version of the + * protocol then olm_session_last_error() will be "BAD_MESSAGE_VERSION". + * If the message couldn't be decoded then olm_session_last_error() will be + * "BAD_MESSAGE_FORMAT". */ +size_t olm_decrypt_max_plaintext_length( + OlmSession * session, + size_t message_type, + void * message, size_t message_length +); + +/** Decrypts a message using the session. The input message buffer is destroyed. + * Returns the length of the plain-text on success. Returns olm_error() on + * failure. If the plain-text buffer is smaller than + * olm_decrypt_max_plaintext_length() then olm_session_last_error() + * will be "OUTPUT_BUFFER_TOO_SMALL". If the base64 couldn't be decoded then + * olm_session_last_error() will be "INVALID_BASE64". If the message is for + * an unsupported version of the protocol then olm_session_last_error() will + * be "BAD_MESSAGE_VERSION". If the message couldn't be decoded then + * olm_session_last_error() will be BAD_MESSAGE_FORMAT". + * If the MAC on the message was invalid then olm_session_last_error() will + * be "BAD_MESSAGE_MAC". */ +size_t olm_decrypt( + OlmSession * session, + size_t message_type, + void * message, size_t message_length, + void * plaintext, size_t max_plaintext_length +); + + + +#ifdef __cplusplus +} +#endif + +#endif /* OLM_HH_ */ diff --git a/include/olm/pickle.hh b/include/olm/pickle.hh new file mode 100644 index 0000000..1676e23 --- /dev/null +++ b/include/olm/pickle.hh @@ -0,0 +1,178 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OLM_PICKLE_HH_ +#define OLM_PICKLE_HH_ + +#include "olm/list.hh" +#include "olm/crypto.hh" + +#include +#include + +namespace olm { + +static std::size_t pickle_length( + const std::uint32_t & value +) { + return 4; +} + + +static std::uint8_t * pickle( + std::uint8_t * pos, + std::uint32_t value +) { + pos += 4; + for (unsigned i = 4; i--;) { *(--pos) = value; value >>= 8; } + return pos + 4; +} + + +static std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + std::uint32_t & value +) { + value = 0; + if (end - pos < 4) return end; + for (unsigned i = 4; i--;) { value <<= 8; value |= *(pos++); } + return pos; +} + +static std::size_t pickle_length( + const bool & value +) { + return 1; +} + + +static std::uint8_t * pickle( + std::uint8_t * pos, + bool value +) { + *(pos++) = value ? 1 : 0; + return pos; +} + + +static std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + bool & value +) { + if (pos == end) return end; + value = *(pos++); + return pos; +} + + + +template +std::size_t pickle_length( + olm::List const & list +) { + std::size_t length = pickle_length(std::uint32_t(list.size())); + for (auto const & value : list) { + length += pickle_length(value); + } + return length; +} + + +template +std::uint8_t * pickle( + std::uint8_t * pos, + olm::List const & list +) { + pos = pickle(pos, std::uint32_t(list.size())); + for (auto const & value : list) { + pos = pickle(pos, value); + } + return pos; +} + + +template +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + olm::List & list +) { + std::uint32_t size; + pos = unpickle(pos, end, size); + while (size--) { + T * value = list.insert(list.end()); + pos = unpickle(pos, end, *value); + } + return pos; +} + + +static std::uint8_t * pickle_bytes( + std::uint8_t * pos, + std::uint8_t const * bytes, std::size_t bytes_length +) { + std::memcpy(pos, bytes, bytes_length); + return pos + bytes_length; +} + + +static std::uint8_t const * unpickle_bytes( + std::uint8_t const * pos, std::uint8_t const * end, + std::uint8_t * bytes, std::size_t bytes_length +) { + if (end - pos < bytes_length) return end; + std::memcpy(bytes, pos, bytes_length); + return pos + bytes_length; +} + + +std::size_t pickle_length( + const Curve25519PublicKey & value +); + + +std::uint8_t * pickle( + std::uint8_t * pos, + const Curve25519PublicKey & value +); + + +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + Curve25519PublicKey & value +); + + +std::size_t pickle_length( + const Curve25519KeyPair & value +); + + +std::uint8_t * pickle( + std::uint8_t * pos, + const Curve25519KeyPair & value +); + + +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + Curve25519KeyPair & value +); + + +} // namespace olm + + + + +#endif /* OLM_PICKLE_HH */ diff --git a/include/olm/ratchet.hh b/include/olm/ratchet.hh new file mode 100644 index 0000000..7274255 --- /dev/null +++ b/include/olm/ratchet.hh @@ -0,0 +1,177 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "olm/crypto.hh" +#include "olm/list.hh" +#include "olm/error.hh" + +namespace olm { + +class Cipher; + +typedef std::uint8_t SharedKey[32]; + + +struct ChainKey { + std::uint32_t index; + SharedKey key; +}; + + +struct MessageKey { + std::uint32_t index; + SharedKey key; +}; + + +struct SenderChain { + Curve25519KeyPair ratchet_key; + ChainKey chain_key; +}; + + +struct ReceiverChain { + Curve25519PublicKey ratchet_key; + ChainKey chain_key; +}; + + +struct SkippedMessageKey { + Curve25519PublicKey ratchet_key; + MessageKey message_key; +}; + + +static std::size_t const MAX_RECEIVER_CHAINS = 5; +static std::size_t const MAX_SKIPPED_MESSAGE_KEYS = 40; + + +struct KdfInfo { + std::uint8_t const * root_info; + std::size_t root_info_length; + std::uint8_t const * ratchet_info; + std::size_t ratchet_info_length; +}; + + +struct Ratchet { + + Ratchet( + KdfInfo const & kdf_info, + Cipher const & ratchet_cipher + ); + + /** A some strings identifying the application to feed into the KDF. */ + KdfInfo const & kdf_info; + + /** The AEAD cipher to use for encrypting messages. */ + Cipher const & ratchet_cipher; + + /** The last error that happened encrypting or decrypting a message. */ + ErrorCode last_error; + + /** 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. */ + SharedKey root_key; + + /** The sender chain is used to send messages. Each time a new ephemeral + * key is received from the remote server we generate a new sender chain + * with a new empheral key when we next send a message. */ + List sender_chain; + + /** The receiver chain is used to decrypt received messages. We store the + * last few chains so we can decrypt any out of order messages we haven't + * received yet. */ + List receiver_chains; + + /** List of message keys we've skipped over when advancing the receiver + * chain. */ + List skipped_message_keys; + + /** Initialise the session using a shared secret and the public part of the + * remote's first ratchet key */ + void initialise_as_bob( + std::uint8_t const * shared_secret, std::size_t shared_secret_length, + Curve25519PublicKey const & their_ratchet_key + ); + + /** Initialise the session using a shared secret and the public/private key + * pair for the first ratchet key */ + void initialise_as_alice( + std::uint8_t const * shared_secret, std::size_t shared_secret_length, + Curve25519KeyPair const & our_ratchet_key + ); + + /** The number of bytes of output the encrypt method will write for + * a given message length. */ + std::size_t encrypt_output_length( + std::size_t plaintext_length + ); + + /** The number of bytes of random data the encrypt method will need to + * encrypt a message. This will be 32 bytes if the session needs to + * generate a new ephemeral key, or will be 0 bytes otherwise.*/ + std::size_t encrypt_random_length(); + + /** Encrypt some plain-text. Returns the length of the encrypted message + * or std::size_t(-1) on failure. On failure last_error will be set with + * an error code. The last_error will be NOT_ENOUGH_RANDOM if the number + * of random bytes is too small. The last_error will be + * OUTPUT_BUFFER_TOO_SMALL if the output buffer is too small. */ + std::size_t encrypt( + std::uint8_t const * plaintext, std::size_t plaintext_length, + std::uint8_t const * random, std::size_t random_length, + std::uint8_t * output, std::size_t max_output_length + ); + + /** An upper bound on the number of bytes of plain-text the decrypt method + * will write for a given input message length. */ + std::size_t decrypt_max_plaintext_length( + std::uint8_t const * input, std::size_t input_length + ); + + /** Decrypt a message. Returns the length of the decrypted plain-text or + * std::size_t(-1) on failure. On failure last_error will be set with an + * error code. The last_error will be OUTPUT_BUFFER_TOO_SMALL if the + * plain-text buffer is too small. The last_error will be + * BAD_MESSAGE_VERSION if the message was encrypted with an unsupported + * version of the protocol. The last_error will be BAD_MESSAGE_FORMAT if + * the message headers could not be decoded. The last_error will be + * BAD_MESSAGE_MAC if the message could not be verified */ + std::size_t decrypt( + std::uint8_t const * input, std::size_t input_length, + std::uint8_t * plaintext, std::size_t max_plaintext_length + ); +}; + + +std::size_t pickle_length( + Ratchet const & value +); + + +std::uint8_t * pickle( + std::uint8_t * pos, + Ratchet const & value +); + + +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + Ratchet & value +); + + +} // namespace olm diff --git a/include/olm/session.hh b/include/olm/session.hh new file mode 100644 index 0000000..a0aff08 --- /dev/null +++ b/include/olm/session.hh @@ -0,0 +1,114 @@ +/* Copyright 2015 OpenMarket Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OLM_SESSION_HH_ +#define OLM_SESSION_HH_ + +#include "olm/ratchet.hh" + +namespace olm { + +class Account; + +struct RemoteKey { + std::uint32_t id; + Curve25519PublicKey key; +}; + + +enum struct MessageType { + PRE_KEY = 0, + MESSAGE = 1, +}; + + +struct Session { + + Session(); + + Ratchet ratchet; + ErrorCode last_error; + + bool received_message; + + RemoteKey alice_identity_key; + Curve25519PublicKey alice_base_key; + std::uint32_t bob_one_time_key_id; + + + std::size_t new_outbound_session_random_length(); + + std::size_t new_outbound_session( + Account const & local_account, + Curve25519PublicKey const & identity_key, + RemoteKey const & one_time_key, + std::uint8_t const * random, std::size_t random_length + ); + + std::size_t new_inbound_session( + Account & local_account, + std::uint8_t const * one_time_key_message, std::size_t message_length + ); + + bool matches_inbound_session( + std::uint8_t const * one_time_key_message, std::size_t message_length + ); + + MessageType encrypt_message_type(); + + std::size_t encrypt_message_length( + std::size_t plaintext_length + ); + + std::size_t encrypt_random_length(); + + std::size_t encrypt( + std::uint8_t const * plaintext, std::size_t plaintext_length, + std::uint8_t const * random, std::size_t random_length, + std::uint8_t * message, std::size_t message_length + ); + + std::size_t decrypt_max_plaintext_length( + MessageType message_type, + std::uint8_t const * message, std::size_t message_length + ); + + std::size_t decrypt( + MessageType message_type, + std::uint8_t const * message, std::size_t message_length, + std::uint8_t * plaintext, std::size_t max_plaintext_length + ); +}; + + +std::size_t pickle_length( + Session const & value +); + + +std::uint8_t * pickle( + std::uint8_t * pos, + Session const & value +); + + +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + Session & value +); + + +} // namespace olm + +#endif /* OLM_SESSION_HH_ */ -- cgit v1.2.3