diff options
Diffstat (limited to 'include/olm')
-rw-r--r-- | include/olm/base64.hh | 24 | ||||
-rw-r--r-- | include/olm/cipher.hh | 4 | ||||
-rw-r--r-- | include/olm/crypto.hh | 26 | ||||
-rw-r--r-- | include/olm/memory.hh | 49 | ||||
-rw-r--r-- | include/olm/pickle.hh | 2 | ||||
-rw-r--r-- | include/olm/ratchet.hh | 2 | ||||
-rw-r--r-- | include/olm/session.hh | 46 | ||||
-rw-r--r-- | include/olm/utility.hh | 9 |
8 files changed, 137 insertions, 25 deletions
diff --git a/include/olm/base64.hh b/include/olm/base64.hh index 018924a..da4641d 100644 --- a/include/olm/base64.hh +++ b/include/olm/base64.hh @@ -20,31 +20,45 @@ namespace olm { - +/** + * The number of bytes of unpadded base64 needed to encode a length of input. + */ static std::size_t encode_base64_length( std::size_t input_length ) { return 4 * ((input_length + 2) / 3) + (input_length + 2) % 3 - 2; } - +/** + * Encode the raw input as unpadded base64. + * Writes encode_base64_length(input_length) bytes to the output buffer. + * The input can overlap with the last three quarters of the output buffer. + * That is, the input pointer may be output + output_length - input_length. + */ std::uint8_t * encode_base64( std::uint8_t const * input, std::size_t input_length, std::uint8_t * output ); - +/** + * The number of bytes of raw data a length of unpadded base64 will encode to. + * Returns std::size_t(-1) if the length is not a valid length for base64. + */ std::size_t decode_base64_length( std::size_t input_length ); - +/** + * Decodes the unpadded base64 input to raw bytes. + * Writes decode_base64_length(input_length) bytes to the output buffer. + * The output can overlap with the first three quarters of the input buffer. + * That is, the input pointers and output pointer may be the same. + */ std::uint8_t const * decode_base64( std::uint8_t const * input, std::size_t input_length, std::uint8_t * output ); - } // namespace olm diff --git a/include/olm/cipher.hh b/include/olm/cipher.hh index f71b3af..c561972 100644 --- a/include/olm/cipher.hh +++ b/include/olm/cipher.hh @@ -47,6 +47,8 @@ public: * output |--ciphertext_length-->| |---mac_length-->| * ciphertext * + * The plain-text pointers and cipher-text pointers may be the same. + * * 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. */ @@ -73,6 +75,8 @@ public: * input |--ciphertext_length-->| |---mac_length-->| * ciphertext * + * The plain-text pointers and cipher-text pointers may be the same. + * * 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. diff --git a/include/olm/crypto.hh b/include/olm/crypto.hh index b845bfe..7a05f8d 100644 --- a/include/olm/crypto.hh +++ b/include/olm/crypto.hh @@ -20,28 +20,27 @@ namespace olm { +static const std::size_t KEY_LENGTH = 32; +static const std::size_t SIGNATURE_LENGTH = 64; +static const std::size_t IV_LENGTH = 16; struct Curve25519PublicKey { - static const int LENGTH = 32; - std::uint8_t public_key[32]; + std::uint8_t public_key[KEY_LENGTH]; }; struct Curve25519KeyPair : public Curve25519PublicKey { - static const int LENGTH = 64; - std::uint8_t private_key[32]; + std::uint8_t private_key[KEY_LENGTH]; }; struct Ed25519PublicKey { - static const int LENGTH = 32; - std::uint8_t public_key[32]; + std::uint8_t public_key[KEY_LENGTH]; }; struct Ed25519KeyPair : public Ed25519PublicKey { - static const int LENGTH = 64; - std::uint8_t private_key[32]; + std::uint8_t private_key[KEY_LENGTH]; }; @@ -52,9 +51,6 @@ void curve25519_generate_key( ); -const std::size_t CURVE25519_SHARED_SECRET_LENGTH = 32; - - /** Create a shared secret using our private key and their public key. * The output buffer must be at least 32 bytes long. */ void curve25519_shared_secret( @@ -109,14 +105,12 @@ bool ed25519_verify( struct Aes256Key { - static const int LENGTH = 32; - std::uint8_t key[32]; + std::uint8_t key[KEY_LENGTH]; }; struct Aes256Iv { - static const int LENGTH = 16; - std::uint8_t iv[16]; + std::uint8_t iv[IV_LENGTH]; }; @@ -156,7 +150,7 @@ void sha256( ); -const std::size_t HMAC_SHA256_OUTPUT_LENGTH = 32; +const std::size_t SHA256_OUTPUT_LENGTH = 32; /** HMAC: Keyed-Hashing for Message Authentication diff --git a/include/olm/memory.hh b/include/olm/memory.hh index b19c74b..128990a 100644 --- a/include/olm/memory.hh +++ b/include/olm/memory.hh @@ -14,6 +14,8 @@ */ #include <cstddef> #include <cstdint> +#include <cstring> +#include <type_traits> namespace olm { @@ -35,4 +37,51 @@ bool is_equal( std::size_t length ); +/** Check if two fixed size arrays are equals */ +template<typename T> +bool array_equal( + T const & array_a, + T const & array_b +) { + static_assert( + std::is_array<T>::value + && std::is_convertible<T, std::uint8_t *>::value + && sizeof(T) > 0, + "Arguments to array_equal must be std::uint8_t arrays[]." + ); + return is_equal(array_a, array_b, sizeof(T)); +} + +/** Copy into a fixed size array */ +template<typename T> +std::uint8_t const * load_array( + T & destination, + std::uint8_t const * source +) { + static_assert( + std::is_array<T>::value + && std::is_convertible<T, std::uint8_t *>::value + && sizeof(T) > 0, + "The first argument to load_array must be a std::uint8_t array[]." + ); + std::memcpy(destination, source, sizeof(T)); + return source + sizeof(T); +} + +/** Copy from a fixed size array */ +template<typename T> +std::uint8_t * store_array( + std::uint8_t * destination, + T const & source +) { + static_assert( + std::is_array<T>::value + && std::is_convertible<T, std::uint8_t *>::value + && sizeof(T) > 0, + "The second argument to store_array must be a std::uint8_t array[]." + ); + std::memcpy(destination, source, sizeof(T)); + return destination + sizeof(T); +} + } // namespace olm diff --git a/include/olm/pickle.hh b/include/olm/pickle.hh index 7a2bd1b..27f1f26 100644 --- a/include/olm/pickle.hh +++ b/include/olm/pickle.hh @@ -109,7 +109,7 @@ std::uint8_t const * unpickle( ) { std::uint32_t size; pos = unpickle(pos, end, size); - while (size--) { + while (size-- && pos != end) { T * value = list.insert(list.end()); pos = unpickle(pos, end, *value); } diff --git a/include/olm/ratchet.hh b/include/olm/ratchet.hh index 7274255..2393e5b 100644 --- a/include/olm/ratchet.hh +++ b/include/olm/ratchet.hh @@ -21,7 +21,7 @@ namespace olm { class Cipher; -typedef std::uint8_t SharedKey[32]; +typedef std::uint8_t SharedKey[olm::KEY_LENGTH]; struct ChainKey { diff --git a/include/olm/session.hh b/include/olm/session.hh index 993a8da..b21b0aa 100644 --- a/include/olm/session.hh +++ b/include/olm/session.hh @@ -39,8 +39,13 @@ struct Session { Curve25519PublicKey alice_base_key; Curve25519PublicKey bob_one_time_key; + /** The number of random bytes that are needed to create a new outbound + * session. This will be 64 bytes since two ephemeral keys are needed. */ std::size_t new_outbound_session_random_length(); + /** Start a new outbound session. Returns 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 was too small. */ std::size_t new_outbound_session( Account const & local_account, Curve25519PublicKey const & identity_key, @@ -48,42 +53,79 @@ struct Session { std::uint8_t const * random, std::size_t random_length ); + /** Start a new inbound session from a pre-key message. + * Returns std::size_t(-1) on failure. On failure last_error will be set + * with an error code. The last_error will be BAD_MESSAGE_FORMAT if + * the message headers could not be decoded. */ std::size_t new_inbound_session( Account & local_account, Curve25519PublicKey const * their_identity_key, - std::uint8_t const * one_time_key_message, std::size_t message_length + std::uint8_t const * pre_key_message, std::size_t message_length ); + /** The number of bytes written by session_id() */ std::size_t session_id_length(); + /** An identifier for this session. Generated by hashing the public keys + * used to create the session. Returns the length of the session id on + * success 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 id buffer was too small. */ std::size_t session_id( std::uint8_t * id, std::size_t id_length ); + /** True if this session can be used to decode an inbound pre-key message. + * This can be used to test whether a pre-key message should be decoded + * with an existing session or if a new session will need to be created. + * Returns true if the session is the same. Returns false if either the + * session does not match or the pre-key message could not be decoded. + */ bool matches_inbound_session( Curve25519PublicKey const * their_identity_key, - std::uint8_t const * one_time_key_message, std::size_t message_length + std::uint8_t const * pre_key_message, std::size_t message_length ); + /** Whether the next message will be a pre-key message or a normal message. + * An outbound session will send pre-key messages until it receives a + * message with a ratchet key. */ MessageType encrypt_message_type(); std::size_t encrypt_message_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 * message, std::size_t message_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( MessageType message_type, std::uint8_t const * message, std::size_t message_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( MessageType message_type, std::uint8_t const * message, std::size_t message_length, diff --git a/include/olm/utility.hh b/include/olm/utility.hh index 241d7e0..5329a59 100644 --- a/include/olm/utility.hh +++ b/include/olm/utility.hh @@ -31,13 +31,22 @@ struct Utility { ErrorCode last_error; + /** The length of a SHA-256 hash in bytes. */ std::size_t sha256_length(); + /** Compute a SHA-256 hash. Returns the length of the SHA-256 hash in bytes + * on success. Returns std::size_t(-1) on failure. On failure last_error + * will be set with an error code. If the output buffer was too small then + * last error will be OUTPUT_BUFFER_TOO_SMALL. */ std::size_t sha256( std::uint8_t const * input, std::size_t input_length, std::uint8_t * output, std::size_t output_length ); + /** Verify a ed25519 signature. Returns std::size_t(0) on success. Returns + * std::size_t(-1) on failure or if the signature was invalid. On failure + * last_error will be set with an error code. If the signature was too short + * or was not a valid signature then last_error will be BAD_MESSAGE_MAC. */ std::size_t ed25519_verify( Ed25519PublicKey const & key, std::uint8_t const * message, std::size_t message_length, |