diff options
Diffstat (limited to 'ext/olm/include')
25 files changed, 3667 insertions, 0 deletions
diff --git a/ext/olm/include/olm/account.hh b/ext/olm/include/olm/account.hh new file mode 100644 index 0000000..50708ed --- /dev/null +++ b/ext/olm/include/olm/account.hh @@ -0,0 +1,208 @@ +/* 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.h" +#include "olm/error.h" + +#include <cstdint> + +namespace olm { + + +struct IdentityKeys { + _olm_ed25519_key_pair ed25519_key; + _olm_curve25519_key_pair curve25519_key; +}; + +struct OneTimeKey { + std::uint32_t id; + bool published; + _olm_curve25519_key_pair key; +}; + + +static std::size_t const MAX_ONE_TIME_KEYS = 100; + + +struct Account { + Account(); + IdentityKeys identity_keys; + List<OneTimeKey, MAX_ONE_TIME_KEYS> one_time_keys; + std::uint8_t num_fallback_keys; + OneTimeKey current_fallback_key; + OneTimeKey prev_fallback_key; + std::uint32_t next_one_time_key_id; + OlmErrorCode last_error; + + /** Number of random bytes needed to create a new account */ + std::size_t new_account_random_length() const; + + /** Create a new account. Returns std::size_t(-1) on error. If the number of + * random bytes is too small then last_error will be NOT_ENOUGH_RANDOM */ + std::size_t new_account( + uint8_t const * random, std::size_t random_length + ); + + /** Number of bytes needed to output the identity keys for this account */ + std::size_t get_identity_json_length() const; + + /** Output the identity keys for this account as JSON in the following + * format: + * + * {"curve25519":"<43 base64 characters>" + * ,"ed25519":"<43 base64 characters>" + * } + * + * + * Returns the size of the JSON written or std::size_t(-1) on error. + * If the buffer is too small last_error will be OUTPUT_BUFFER_TOO_SMALL. */ + std::size_t get_identity_json( + std::uint8_t * identity_json, std::size_t identity_json_length + ); + + /** + * The length of an ed25519 signature in bytes. + */ + std::size_t signature_length() const; + + /** + * Signs a message with the ed25519 key for this account. + */ + std::size_t sign( + std::uint8_t const * message, std::size_t message_length, + std::uint8_t * signature, std::size_t signature_length + ); + + /** Number of bytes needed to output the one time keys for this account */ + std::size_t get_one_time_keys_json_length() const; + + /** Output the one time keys that haven't been published yet as JSON: + * + * {"curve25519": + * ["<6 byte key id>":"<43 base64 characters>" + * ,"<6 byte key id>":"<43 base64 characters>" + * ... + * ] + * } + * + * Returns the size of the JSON written or std::size_t(-1) on error. + * If the buffer is too small last_error will be OUTPUT_BUFFER_TOO_SMALL. + */ + std::size_t get_one_time_keys_json( + std::uint8_t * one_time_json, std::size_t one_time_json_length + ); + + /** Mark the current list of one_time_keys and the current fallback key as + * being published. The current one time keys will no longer be returned by + * get_one_time_keys_json() and the current fallback key will no longer be + * returned by get_unpublished_fallback_key_json(). */ + std::size_t mark_keys_as_published(); + + /** The largest number of one time keys this account can store. */ + std::size_t max_number_of_one_time_keys() const; + + /** The number of random bytes needed to generate a given number of new one + * time keys. */ + std::size_t generate_one_time_keys_random_length( + std::size_t number_of_keys + ) const; + + /** Generates a number of new one time keys. If the total number of keys + * stored by this account exceeds max_number_of_one_time_keys() then the + * old keys are discarded. Returns std::size_t(-1) on error. If the number + * of random bytes is too small then last_error will be NOT_ENOUGH_RANDOM */ + std::size_t generate_one_time_keys( + std::size_t number_of_keys, + std::uint8_t const * random, std::size_t random_length + ); + + /** The number of random bytes needed to generate a fallback key. */ + std::size_t generate_fallback_key_random_length() const; + + /** Generates a new fallback key. Returns std::size_t(-1) on error. If the + * number of random bytes is too small then last_error will be + * NOT_ENOUGH_RANDOM */ + std::size_t generate_fallback_key( + std::uint8_t const * random, std::size_t random_length + ); + + /** Number of bytes needed to output the fallback keys for this account */ + std::size_t get_fallback_key_json_length() const; + + /** Deprecated: use get_unpublished_fallback_key_json instead */ + std::size_t get_fallback_key_json( + std::uint8_t * fallback_json, std::size_t fallback_json_length + ); + + /** Number of bytes needed to output the unpublished fallback keys for this + * account */ + std::size_t get_unpublished_fallback_key_json_length() const; + + /** Output the fallback key as JSON: + * + * {"curve25519": + * ["<6 byte key id>":"<43 base64 characters>" + * ,"<6 byte key id>":"<43 base64 characters>" + * ... + * ] + * } + * + * if there is a fallback key and it has not been published yet. + * + * Returns the size of the JSON written or std::size_t(-1) on error. + * If the buffer is too small last_error will be OUTPUT_BUFFER_TOO_SMALL. + */ + std::size_t get_unpublished_fallback_key_json( + std::uint8_t * fallback_json, std::size_t fallback_json_length + ); + + /** Forget about the old fallback key */ + void forget_old_fallback_key(); + + /** Lookup a one time key with the given public key */ + OneTimeKey const * lookup_key( + _olm_curve25519_public_key const & public_key + ); + + /** Remove a one time key with the given public key */ + std::size_t remove_key( + _olm_curve25519_public_key const & public_key + ); +}; + + +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/ext/olm/include/olm/base64.h b/ext/olm/include/olm/base64.h new file mode 100644 index 0000000..23bd010 --- /dev/null +++ b/ext/olm/include/olm/base64.h @@ -0,0 +1,81 @@ +/* Copyright 2015, 2016 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. + */ + +/* C bindings for base64 functions */ + + +#ifndef OLM_BASE64_H_ +#define OLM_BASE64_H_ + +#include <stddef.h> +#include <stdint.h> + +// Note: exports in this file are only for unit tests. Nobody else should be +// using this externally +#include "olm/olm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * The number of bytes of unpadded base64 needed to encode a length of input. + */ +OLM_EXPORT size_t _olm_encode_base64_length( + size_t input_length +); + +/** + * 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. + * + * Returns number of bytes encoded + */ +OLM_EXPORT size_t _olm_encode_base64( + uint8_t const * input, size_t input_length, + uint8_t * output +); + +/** + * The number of bytes of raw data a length of unpadded base64 will encode to. + * Returns size_t(-1) if the length is not a valid length for base64. + */ +OLM_EXPORT size_t _olm_decode_base64_length( + 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. + * + * Returns number of bytes decoded + */ +OLM_EXPORT size_t _olm_decode_base64( + uint8_t const * input, size_t input_length, + uint8_t * output +); + + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif /* OLM_BASE64_H_ */ diff --git a/ext/olm/include/olm/base64.hh b/ext/olm/include/olm/base64.hh new file mode 100644 index 0000000..1fe549e --- /dev/null +++ b/ext/olm/include/olm/base64.hh @@ -0,0 +1,71 @@ +/* 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_BASE64_HH_ +#define OLM_BASE64_HH_ + +#include <cstddef> +#include <cstdint> + +// Note: exports in this file are only for unit tests. Nobody else should be +// using this externally +#include "olm/olm_export.h" + +namespace olm { + +/** + * The number of bytes of unpadded base64 needed to encode a length of input. + */ +OLM_EXPORT std::size_t encode_base64_length( + std::size_t input_length +); + +/** + * 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. + */ +OLM_EXPORT 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. + */ +OLM_EXPORT 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. + * + * Returns the number of bytes of raw data the base64 input decoded to. If the + * input length supplied is not a valid length for base64, returns + * std::size_t(-1) and does not decode. + */ +OLM_EXPORT std::size_t decode_base64( + std::uint8_t const * input, std::size_t input_length, + std::uint8_t * output +); + +} // namespace olm + + +#endif /* OLM_BASE64_HH_ */ diff --git a/ext/olm/include/olm/cipher.h b/ext/olm/include/olm/cipher.h new file mode 100644 index 0000000..76236dc --- /dev/null +++ b/ext/olm/include/olm/cipher.h @@ -0,0 +1,142 @@ +/* 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_H_ +#define OLM_CIPHER_H_ + +#include <stdint.h> +#include <stdlib.h> + +// Note: exports in this file are only for unit tests. Nobody else should be +// using this externally +#include "olm/olm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct _olm_cipher; + +struct _olm_cipher_ops { + /** + * Returns the length of the message authentication code that will be + * appended to the output. + */ + size_t (*mac_length)(const struct _olm_cipher *cipher); + + /** + * Returns the length of cipher-text for a given length of plain-text. + */ + size_t (*encrypt_ciphertext_length)( + const struct _olm_cipher *cipher, + size_t plaintext_length + ); + + /* + * 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 + * + * The plain-text pointers and cipher-text pointers may be the same. + * + * Returns 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. + */ + size_t (*encrypt)( + const struct _olm_cipher *cipher, + uint8_t const * key, size_t key_length, + uint8_t const * plaintext, size_t plaintext_length, + uint8_t * ciphertext, size_t ciphertext_length, + uint8_t * output, size_t output_length + ); + + /** + * Returns the maximum length of plain-text that a given length of + * cipher-text can contain. + */ + size_t (*decrypt_max_plaintext_length)( + const struct _olm_cipher *cipher, + size_t ciphertext_length + ); + + /** + * Authenticates the input and decrypts the cipher-text into the plain-text + * buffer. + * + * |----------------------------------------input_length-->| + * input |--ciphertext_length-->| |---mac_length-->| + * ciphertext + * + * The plain-text pointers and cipher-text pointers may be the same. + * + * Returns 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. + */ + size_t (*decrypt)( + const struct _olm_cipher *cipher, + uint8_t const * key, size_t key_length, + uint8_t const * input, size_t input_length, + uint8_t const * ciphertext, size_t ciphertext_length, + uint8_t * plaintext, size_t max_plaintext_length + ); +}; + +struct _olm_cipher { + const struct _olm_cipher_ops *ops; + /* cipher-specific fields follow */ +}; + +struct _olm_cipher_aes_sha_256 { + struct _olm_cipher base_cipher; + + /** context string for the HKDF used for deriving the AES256 key, HMAC key, + * and AES IV, from the key material passed to encrypt/decrypt. + */ + uint8_t const * kdf_info; + + /** length of context string kdf_info */ + size_t kdf_info_length; +}; + +OLM_EXPORT extern const struct _olm_cipher_ops _olm_cipher_aes_sha_256_ops; + +/** + * get an initializer for an instance of struct _olm_cipher_aes_sha_256. + * + * To use it, declare: + * + * struct _olm_cipher_aes_sha_256 MY_CIPHER = + * OLM_CIPHER_INIT_AES_SHA_256("MY_KDF"); + * struct _olm_cipher *cipher = OLM_CIPHER_BASE(&MY_CIPHER); + */ +#define OLM_CIPHER_INIT_AES_SHA_256(KDF_INFO) { \ + /*.base_cipher = */{ &_olm_cipher_aes_sha_256_ops },\ + /*.kdf_info = */(uint8_t *)(KDF_INFO), \ + /*.kdf_info_length = */sizeof(KDF_INFO) - 1 \ +} +#define OLM_CIPHER_BASE(CIPHER) \ + (&((CIPHER)->base_cipher)) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* OLM_CIPHER_H_ */ diff --git a/ext/olm/include/olm/crypto.h b/ext/olm/include/olm/crypto.h new file mode 100644 index 0000000..939c6d9 --- /dev/null +++ b/ext/olm/include/olm/crypto.h @@ -0,0 +1,206 @@ +/* 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. + */ + +/* C-compatible crpyto utility functions. At some point all of crypto.hh will + * move here. + */ + +#ifndef OLM_CRYPTO_H_ +#define OLM_CRYPTO_H_ + +// Note: exports in this file are only for unit tests. Nobody else should be +// using this externally +#include "olm/olm_export.h" + +#include <stdint.h> +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** length of a sha256 hash */ +#define SHA256_OUTPUT_LENGTH 32 + +/** length of a public or private Curve25519 key */ +#define CURVE25519_KEY_LENGTH 32 + +/** length of the shared secret created by a Curve25519 ECDH operation */ +#define CURVE25519_SHARED_SECRET_LENGTH 32 + +/** amount of random data required to create a Curve25519 keypair */ +#define CURVE25519_RANDOM_LENGTH CURVE25519_KEY_LENGTH + +/** length of a public Ed25519 key */ +#define ED25519_PUBLIC_KEY_LENGTH 32 + +/** length of a private Ed25519 key */ +#define ED25519_PRIVATE_KEY_LENGTH 64 + +/** amount of random data required to create a Ed25519 keypair */ +#define ED25519_RANDOM_LENGTH 32 + +/** length of an Ed25519 signature */ +#define ED25519_SIGNATURE_LENGTH 64 + +/** length of an aes256 key */ +#define AES256_KEY_LENGTH 32 + +/** length of an aes256 initialisation vector */ +#define AES256_IV_LENGTH 16 + +struct _olm_aes256_key { + uint8_t key[AES256_KEY_LENGTH]; +}; + +struct _olm_aes256_iv { + uint8_t iv[AES256_IV_LENGTH]; +}; + + +struct _olm_curve25519_public_key { + uint8_t public_key[CURVE25519_KEY_LENGTH]; +}; + +struct _olm_curve25519_private_key { + uint8_t private_key[CURVE25519_KEY_LENGTH]; +}; + +struct _olm_curve25519_key_pair { + struct _olm_curve25519_public_key public_key; + struct _olm_curve25519_private_key private_key; +}; + +struct _olm_ed25519_public_key { + uint8_t public_key[ED25519_PUBLIC_KEY_LENGTH]; +}; + +struct _olm_ed25519_private_key { + uint8_t private_key[ED25519_PRIVATE_KEY_LENGTH]; +}; + +struct _olm_ed25519_key_pair { + struct _olm_ed25519_public_key public_key; + struct _olm_ed25519_private_key private_key; +}; + + +/** The length of output the aes_encrypt_cbc function will write */ +OLM_EXPORT size_t _olm_crypto_aes_encrypt_cbc_length( + 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 */ +OLM_EXPORT void _olm_crypto_aes_encrypt_cbc( + const struct _olm_aes256_key *key, + const struct _olm_aes256_iv *iv, + const uint8_t *input, size_t input_length, + 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. + */ +OLM_EXPORT size_t _olm_crypto_aes_decrypt_cbc( + const struct _olm_aes256_key *key, + const struct _olm_aes256_iv *iv, + uint8_t const * input, size_t input_length, + uint8_t * output +); + + +/** Computes SHA-256 of the input. The output buffer must be a least + * SHA256_OUTPUT_LENGTH (32) bytes long. */ +OLM_EXPORT void _olm_crypto_sha256( + uint8_t const * input, size_t input_length, + uint8_t * output +); + +/** 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 SHA256_OUTPUT_LENGTH (32) bytes long. */ +OLM_EXPORT void _olm_crypto_hmac_sha256( + uint8_t const * key, size_t key_length, + uint8_t const * input, size_t input_length, + uint8_t * output +); + + +/** HMAC-based Key Derivation Function (HKDF) + * https://tools.ietf.org/html/rfc5869 + * Derives key material from the input bytes. */ +OLM_EXPORT void _olm_crypto_hkdf_sha256( + uint8_t const * input, size_t input_length, + uint8_t const * info, size_t info_length, + uint8_t const * salt, size_t salt_length, + uint8_t * output, size_t output_length +); + + +/** Generate a curve25519 key pair + * random_32_bytes should be CURVE25519_RANDOM_LENGTH (32) bytes long. + */ +OLM_EXPORT void _olm_crypto_curve25519_generate_key( + uint8_t const * random_32_bytes, + struct _olm_curve25519_key_pair *output +); + + +/** Create a shared secret using our private key and their public key. + * The output buffer must be at least CURVE25519_SHARED_SECRET_LENGTH (32) bytes long. + */ +OLM_EXPORT void _olm_crypto_curve25519_shared_secret( + const struct _olm_curve25519_key_pair *our_key, + const struct _olm_curve25519_public_key *their_key, + uint8_t * output +); + +/** Generate an ed25519 key pair + * random_32_bytes should be ED25519_RANDOM_LENGTH (32) bytes long. + */ +OLM_EXPORT void _olm_crypto_ed25519_generate_key( + uint8_t const * random_bytes, + struct _olm_ed25519_key_pair *output +); + +/** Signs the message using our private key. + * + * The output buffer must be at least ED25519_SIGNATURE_LENGTH (64) bytes + * long. */ +OLM_EXPORT void _olm_crypto_ed25519_sign( + const struct _olm_ed25519_key_pair *our_key, + const uint8_t * message, size_t message_length, + uint8_t * output +); + +/** Verify an ed25519 signature + * The signature input buffer must be ED25519_SIGNATURE_LENGTH (64) bytes long. + * Returns non-zero if the signature is valid. */ +OLM_EXPORT int _olm_crypto_ed25519_verify( + const struct _olm_ed25519_public_key *their_key, + const uint8_t * message, size_t message_length, + const uint8_t * signature +); + + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* OLM_CRYPTO_H_ */ diff --git a/ext/olm/include/olm/error.h b/ext/olm/include/olm/error.h new file mode 100644 index 0000000..c91e89f --- /dev/null +++ b/ext/olm/include/olm/error.h @@ -0,0 +1,80 @@ +/* Copyright 2015-2016 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_ERROR_H_ +#define OLM_ERROR_H_ + +#include "olm/olm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum OlmErrorCode { + OLM_SUCCESS = 0, /*!< There wasn't an error */ + OLM_NOT_ENOUGH_RANDOM = 1, /*!< Not enough entropy was supplied */ + OLM_OUTPUT_BUFFER_TOO_SMALL = 2, /*!< Supplied output buffer is too small */ + OLM_BAD_MESSAGE_VERSION = 3, /*!< The message version is unsupported */ + OLM_BAD_MESSAGE_FORMAT = 4, /*!< The message couldn't be decoded */ + OLM_BAD_MESSAGE_MAC = 5, /*!< The message couldn't be decrypted */ + OLM_BAD_MESSAGE_KEY_ID = 6, /*!< The message references an unknown key id */ + OLM_INVALID_BASE64 = 7, /*!< The input base64 was invalid */ + OLM_BAD_ACCOUNT_KEY = 8, /*!< The supplied account key is invalid */ + OLM_UNKNOWN_PICKLE_VERSION = 9, /*!< The pickled object is too new */ + OLM_CORRUPTED_PICKLE = 10, /*!< The pickled object couldn't be decoded */ + + OLM_BAD_SESSION_KEY = 11, /*!< Attempt to initialise an inbound group + session from an invalid session key */ + OLM_UNKNOWN_MESSAGE_INDEX = 12, /*!< Attempt to decode a message whose + * index is earlier than our earliest + * known session key. + */ + + /** + * Attempt to unpickle an account which uses pickle version 1 (which did + * not save enough space for the Ed25519 key; the key should be considered + * compromised. We don't let the user reload the account. + */ + OLM_BAD_LEGACY_ACCOUNT_PICKLE = 13, + + /** + * Received message had a bad signature + */ + OLM_BAD_SIGNATURE = 14, + + OLM_INPUT_BUFFER_TOO_SMALL = 15, + + /** + * SAS doesn't have their key set. + */ + OLM_SAS_THEIR_KEY_NOT_SET = 16, + + /** + * The pickled object was successfully decoded, but the unpickling still failed + * because it had some extraneous junk data at the end. + */ + OLM_PICKLE_EXTRA_DATA = 17, + + /* remember to update the list of string constants in error.c when updating + * this list. */ +}; + +/** get a string representation of the given error code. */ +OLM_EXPORT const char * _olm_error_to_string(enum OlmErrorCode error); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* OLM_ERROR_H_ */ diff --git a/ext/olm/include/olm/inbound_group_session.h b/ext/olm/include/olm/inbound_group_session.h new file mode 100644 index 0000000..ef68513 --- /dev/null +++ b/ext/olm/include/olm/inbound_group_session.h @@ -0,0 +1,246 @@ +/* Copyright 2016 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_INBOUND_GROUP_SESSION_H_ +#define OLM_INBOUND_GROUP_SESSION_H_ + +#include <stddef.h> +#include <stdint.h> + +#include "olm/error.h" + +#include "olm/olm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OlmInboundGroupSession OlmInboundGroupSession; + +/** get the size of an inbound group session, in bytes. */ +OLM_EXPORT size_t olm_inbound_group_session_size(void); + +/** + * Initialise an inbound group session object using the supplied memory + * The supplied memory should be at least olm_inbound_group_session_size() + * bytes. + */ +OLM_EXPORT OlmInboundGroupSession * olm_inbound_group_session( + void *memory +); + +/** + * A null terminated string describing the most recent error to happen to a + * group session */ +OLM_EXPORT const char *olm_inbound_group_session_last_error( + const OlmInboundGroupSession *session +); + +/** + * An error code describing the most recent error to happen to a group + * session */ +OLM_EXPORT enum OlmErrorCode olm_inbound_group_session_last_error_code( + const OlmInboundGroupSession *session +); + +/** Clears the memory used to back this group session */ +OLM_EXPORT size_t olm_clear_inbound_group_session( + OlmInboundGroupSession *session +); + +/** Returns the number of bytes needed to store an inbound group session */ +OLM_EXPORT size_t olm_pickle_inbound_group_session_length( + const OlmInboundGroupSession *session +); + +/** + * Stores a group session as a base64 string. Encrypts the session using the + * supplied key. Returns the length of the session on success. + * + * Returns olm_error() on failure. If the pickle output buffer + * is smaller than olm_pickle_inbound_group_session_length() then + * olm_inbound_group_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" + */ +OLM_EXPORT size_t olm_pickle_inbound_group_session( + OlmInboundGroupSession *session, + void const * key, size_t key_length, + void * pickled, size_t pickled_length +); + +/** + * Loads a group 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_inbound_group_session_last_error() will be + * "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then + * olm_inbound_group_session_last_error() will be "INVALID_BASE64". The input + * pickled buffer is destroyed + */ +OLM_EXPORT size_t olm_unpickle_inbound_group_session( + OlmInboundGroupSession *session, + void const * key, size_t key_length, + void * pickled, size_t pickled_length +); + + +/** + * Start a new inbound group session, from a key exported from + * olm_outbound_group_session_key + * + * Returns olm_error() on failure. On failure last_error will be set with an + * error code. The last_error will be: + * + * * OLM_INVALID_BASE64 if the session_key is not valid base64 + * * OLM_BAD_SESSION_KEY if the session_key is invalid + */ +OLM_EXPORT size_t olm_init_inbound_group_session( + OlmInboundGroupSession *session, + /* base64-encoded keys */ + uint8_t const * session_key, size_t session_key_length +); + +/** + * Import an inbound group session, from a previous export. + * + * Returns olm_error() on failure. On failure last_error will be set with an + * error code. The last_error will be: + * + * * OLM_INVALID_BASE64 if the session_key is not valid base64 + * * OLM_BAD_SESSION_KEY if the session_key is invalid + */ +OLM_EXPORT size_t olm_import_inbound_group_session( + OlmInboundGroupSession *session, + /* base64-encoded keys; note that it will be overwritten with the base64-decoded + data. */ + uint8_t const * session_key, size_t session_key_length +); + + +/** + * Get an upper bound on the number of bytes of plain-text the decrypt method + * will write for a given input message length. The actual size could be + * different due to padding. + * + * The input message buffer is destroyed. + * + * Returns olm_error() on failure. + */ +OLM_EXPORT size_t olm_group_decrypt_max_plaintext_length( + OlmInboundGroupSession *session, + uint8_t * message, size_t message_length +); + +/** + * Decrypt a message. + * + * The input message buffer is destroyed. + * + * Returns the length of the decrypted plain-text, or olm_error() on failure. + * + * On failure last_error will be set with an error code. The last_error will + * be: + * * OLM_OUTPUT_BUFFER_TOO_SMALL if the plain-text buffer is too small + * * OLM_INVALID_BASE64 if the message is not valid base-64 + * * OLM_BAD_MESSAGE_VERSION if the message was encrypted with an unsupported + * version of the protocol + * * OLM_BAD_MESSAGE_FORMAT if the message headers could not be decoded + * * OLM_BAD_MESSAGE_MAC if the message could not be verified + * * OLM_UNKNOWN_MESSAGE_INDEX if we do not have a session key corresponding to the + * message's index (ie, it was sent before the session key was shared with + * us) + */ +OLM_EXPORT size_t olm_group_decrypt( + OlmInboundGroupSession *session, + + /* input; note that it will be overwritten with the base64-decoded + message. */ + uint8_t * message, size_t message_length, + + /* output */ + uint8_t * plaintext, size_t max_plaintext_length, + uint32_t * message_index +); + + +/** + * Get the number of bytes returned by olm_inbound_group_session_id() + */ +OLM_EXPORT size_t olm_inbound_group_session_id_length( + const OlmInboundGroupSession *session +); + +/** + * Get a base64-encoded identifier for this session. + * + * Returns the length of the session id on success or olm_error() 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. + */ +OLM_EXPORT size_t olm_inbound_group_session_id( + OlmInboundGroupSession *session, + uint8_t * id, size_t id_length +); + +/** + * Get the first message index we know how to decrypt. + */ +OLM_EXPORT uint32_t olm_inbound_group_session_first_known_index( + const OlmInboundGroupSession *session +); + + +/** + * Check if the session has been verified as a valid session. + * + * (A session is verified either because the original session share was signed, + * or because we have subsequently successfully decrypted a message.) + * + * This is mainly intended for the unit tests, currently. + */ +OLM_EXPORT int olm_inbound_group_session_is_verified( + const OlmInboundGroupSession *session +); + +/** + * Get the number of bytes returned by olm_export_inbound_group_session() + */ +OLM_EXPORT size_t olm_export_inbound_group_session_length( + const OlmInboundGroupSession *session +); + +/** + * Export the base64-encoded ratchet key for this session, at the given index, + * in a format which can be used by olm_import_inbound_group_session + * + * Returns the length of the ratchet key on success or olm_error() on + * failure. On failure last_error will be set with an error code. The + * last_error will be: + * * OUTPUT_BUFFER_TOO_SMALL if the buffer was too small + * * OLM_UNKNOWN_MESSAGE_INDEX if we do not have a session key corresponding to the + * given index (ie, it was sent before the session key was shared with + * us) + */ +OLM_EXPORT size_t olm_export_inbound_group_session( + OlmInboundGroupSession *session, + uint8_t * key, size_t key_length, uint32_t message_index +); + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* OLM_INBOUND_GROUP_SESSION_H_ */ diff --git a/ext/olm/include/olm/list.hh b/ext/olm/include/olm/list.hh new file mode 100644 index 0000000..6906c87 --- /dev/null +++ b/ext/olm/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 <cstddef> + +namespace olm { + +template<typename T, std::size_t max_size> +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 = _end - 1; + while (tmp != pos) { + *tmp = *(tmp - 1); + --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<T, max_size> & operator=(List<T, max_size> 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/ext/olm/include/olm/megolm.h b/ext/olm/include/olm/megolm.h new file mode 100644 index 0000000..338ab21 --- /dev/null +++ b/ext/olm/include/olm/megolm.h @@ -0,0 +1,99 @@ +/* Copyright 2016 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_MEGOLM_H_ +#define OLM_MEGOLM_H_ + +/** + * implementation of the Megolm multi-part ratchet used in group chats. + */ + +#include <stdint.h> +#include <stdlib.h> + +// Note: exports in this file are only for unit tests. Nobody else should be +// using this externally +#include "olm/olm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * number of bytes in each part of the ratchet; this should be the same as + * the length of the hash function used in the HMAC (32 bytes for us, as we + * use HMAC-SHA-256) + */ +#define MEGOLM_RATCHET_PART_LENGTH 32 /* SHA256_OUTPUT_LENGTH */ + +/** + * number of parts in the ratchet; the advance() implementations rely on + * this being 4. + */ +#define MEGOLM_RATCHET_PARTS 4 + +#define MEGOLM_RATCHET_LENGTH (MEGOLM_RATCHET_PARTS * MEGOLM_RATCHET_PART_LENGTH) + +typedef struct Megolm { + uint8_t data[MEGOLM_RATCHET_PARTS][MEGOLM_RATCHET_PART_LENGTH]; + uint32_t counter; +} Megolm; + + +/** + * The cipher used in megolm-backed conversations + * + * (AES256 + SHA256, with keys based on an HKDF with info of MEGOLM_KEYS) + */ +extern const struct _olm_cipher *megolm_cipher; + +/** + * initialize the megolm ratchet. random_data should be at least + * MEGOLM_RATCHET_LENGTH bytes of randomness. + */ +OLM_EXPORT void megolm_init(Megolm *megolm, uint8_t const *random_data, uint32_t counter); + +/** Returns the number of bytes needed to store a megolm */ +OLM_EXPORT size_t megolm_pickle_length(const Megolm *megolm); + +/** + * Pickle the megolm. Returns a pointer to the next free space in the buffer. + */ +OLM_EXPORT uint8_t * megolm_pickle(const Megolm *megolm, uint8_t *pos); + +/** + * Unpickle the megolm. Returns a pointer to the next item in the buffer. + */ +OLM_EXPORT const uint8_t * megolm_unpickle(Megolm *megolm, const uint8_t *pos, + const uint8_t *end); + + +/** advance the ratchet by one step */ +OLM_EXPORT void megolm_advance(Megolm *megolm); + +/** + * get the key data in the ratchet. The returned data is + * MEGOLM_RATCHET_LENGTH bytes long. + */ +#define megolm_get_data(megolm) ((const uint8_t *)((megolm)->data)) + +/** advance the ratchet to a given count */ +OLM_EXPORT void megolm_advance_to(Megolm *megolm, uint32_t advance_to); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* OLM_MEGOLM_H_ */ diff --git a/ext/olm/include/olm/memory.h b/ext/olm/include/olm/memory.h new file mode 100644 index 0000000..cc346d0 --- /dev/null +++ b/ext/olm/include/olm/memory.h @@ -0,0 +1,41 @@ +/* Copyright 2015, 2016 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. + */ + +/* C bindings for memory functions */ + + +#ifndef OLM_MEMORY_H_ +#define OLM_MEMORY_H_ + +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Clear the memory held in the buffer. This is more resilient to being + * optimised away than memset or bzero. + */ +void _olm_unset( + void volatile * buffer, size_t buffer_length +); + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif /* OLM_MEMORY_H_ */ diff --git a/ext/olm/include/olm/memory.hh b/ext/olm/include/olm/memory.hh new file mode 100644 index 0000000..74ff9f8 --- /dev/null +++ b/ext/olm/include/olm/memory.hh @@ -0,0 +1,90 @@ +/* Copyright 2015, 2016 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 <cstddef> +#include <cstdint> +#include <cstring> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <type_traits> + +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<typename T> +void unset(T & value) { + unset(reinterpret_cast<void volatile *>(&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 +); + +/** 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/ext/olm/include/olm/message.h b/ext/olm/include/olm/message.h new file mode 100644 index 0000000..cc4158b --- /dev/null +++ b/ext/olm/include/olm/message.h @@ -0,0 +1,97 @@ +/* Copyright 2016 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. + */ + +/** + * functions for encoding and decoding messages in the Olm protocol. + * + * Some of these functions have only C++ bindings, and are declared in + * message.hh; in time, they should probably be converted to plain C and + * declared here. + */ + +#ifndef OLM_MESSAGE_H_ +#define OLM_MESSAGE_H_ + +#include <stdint.h> +#include <stddef.h> + +// Note: exports in this file are only for unit tests. Nobody else should be +// using this externally +#include "olm/olm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The length of the buffer needed to hold a group message. + */ +OLM_EXPORT size_t _olm_encode_group_message_length( + uint32_t chain_index, + size_t ciphertext_length, + size_t mac_length, + size_t signature_length +); + +/** + * Writes the message headers into the output buffer. + * + * version: version number of the olm protocol + * message_index: message index + * ciphertext_length: length of the ciphertext + * output: where to write the output. Should be at least + * olm_encode_group_message_length() bytes long. + * ciphertext_ptr: returns the address that the ciphertext + * should be written to, followed by the MAC and the + * signature. + * + * Returns the size of the message, up to the MAC. + */ +OLM_EXPORT size_t _olm_encode_group_message( + uint8_t version, + uint32_t message_index, + size_t ciphertext_length, + uint8_t *output, + uint8_t **ciphertext_ptr +); + + +struct _OlmDecodeGroupMessageResults { + uint8_t version; + uint32_t message_index; + int has_message_index; + const uint8_t *ciphertext; + size_t ciphertext_length; +}; + + +/** + * Reads the message headers from the input buffer. + */ +OLM_EXPORT void _olm_decode_group_message( + const uint8_t *input, size_t input_length, + size_t mac_length, size_t signature_length, + + /* output structure: updated with results */ + struct _OlmDecodeGroupMessageResults *results +); + + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* OLM_MESSAGE_H_ */ diff --git a/ext/olm/include/olm/message.hh b/ext/olm/include/olm/message.hh new file mode 100644 index 0000000..6da4851 --- /dev/null +++ b/ext/olm/include/olm/message.hh @@ -0,0 +1,141 @@ +/* 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. + */ + + +/** + * functions for encoding and decoding messages in the Olm protocol. + * + * Some of these functions have plain-C bindings, and are declared in + * message.h; in time, all of the functions declared here should probably be + * converted to plain C and moved to message.h. + */ + +#include "message.h" + +#include <cstddef> +#include <cstdint> + +// Note: exports in this file are only for unit tests. Nobody else should be +// using this externally +#include "olm/olm_export.h" + +namespace olm { + +/** + * The length of the buffer needed to hold a message. + */ +OLM_EXPORT 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. + */ +OLM_EXPORT 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. + */ +OLM_EXPORT 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 * one_time_key; + std::uint8_t * message; +}; + + +struct PreKeyMessageReader { + std::uint8_t version; + 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 * one_time_key; std::size_t one_time_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::size_t identity_key_length, + std::size_t base_key_length, + std::size_t one_time_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::size_t identity_key_length, + std::size_t base_key_length, + std::size_t one_time_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/ext/olm/include/olm/olm.h b/ext/olm/include/olm/olm.h new file mode 100644 index 0000000..2cd5339 --- /dev/null +++ b/ext/olm/include/olm/olm.h @@ -0,0 +1,527 @@ +/* Copyright 2015, 2016 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_H_ +#define OLM_H_ + +#include <stddef.h> +#include <stdint.h> + +#include "olm/error.h" +#include "olm/inbound_group_session.h" +#include "olm/outbound_group_session.h" + +#include "olm/olm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static const size_t OLM_MESSAGE_TYPE_PRE_KEY = 0; +static const size_t OLM_MESSAGE_TYPE_MESSAGE = 1; + +typedef struct OlmAccount OlmAccount; +typedef struct OlmSession OlmSession; +typedef struct OlmUtility OlmUtility; + +/** Get the version number of the library. + * Arguments will be updated if non-null. + */ +OLM_EXPORT void olm_get_library_version(uint8_t *major, uint8_t *minor, uint8_t *patch); + +/** The size of an account object in bytes */ +OLM_EXPORT size_t olm_account_size(void); + +/** The size of a session object in bytes */ +OLM_EXPORT size_t olm_session_size(void); + +/** The size of a utility object in bytes */ +OLM_EXPORT size_t olm_utility_size(void); + +/** Initialise an account object using the supplied memory + * The supplied memory must be at least olm_account_size() bytes */ +OLM_EXPORT OlmAccount * olm_account( + void * memory +); + +/** Initialise a session object using the supplied memory + * The supplied memory must be at least olm_session_size() bytes */ +OLM_EXPORT OlmSession * olm_session( + void * memory +); + +/** Initialise a utility object using the supplied memory + * The supplied memory must be at least olm_utility_size() bytes */ +OLM_EXPORT OlmUtility * olm_utility( + void * memory +); + +/** The value that olm will return from a function if there was an error */ +OLM_EXPORT size_t olm_error(void); + +/** A null terminated string describing the most recent error to happen to an + * account */ +OLM_EXPORT const char * olm_account_last_error( + OlmAccount const * account +); + +/** An error code describing the most recent error to happen to an account */ +OLM_EXPORT enum OlmErrorCode olm_account_last_error_code( + OlmAccount const * account +); + +/** A null terminated string describing the most recent error to happen to a + * session */ +OLM_EXPORT const char * olm_session_last_error( + OlmSession const * session +); + +/** An error code describing the most recent error to happen to a session */ +OLM_EXPORT enum OlmErrorCode olm_session_last_error_code( + OlmSession const * session +); + +/** A null terminated string describing the most recent error to happen to a + * utility */ +OLM_EXPORT const char * olm_utility_last_error( + OlmUtility const * utility +); + +/** An error code describing the most recent error to happen to a utility */ +OLM_EXPORT enum OlmErrorCode olm_utility_last_error_code( + OlmUtility const * utility +); + +/** Clears the memory used to back this account */ +OLM_EXPORT size_t olm_clear_account( + OlmAccount * account +); + +/** Clears the memory used to back this session */ +OLM_EXPORT size_t olm_clear_session( + OlmSession * session +); + +/** Clears the memory used to back this utility */ +OLM_EXPORT size_t olm_clear_utility( + OlmUtility * utility +); + +/** Returns the number of bytes needed to store an account */ +OLM_EXPORT size_t olm_pickle_account_length( + OlmAccount const * account +); + +/** Returns the number of bytes needed to store a session */ +OLM_EXPORT size_t olm_pickle_session_length( + OlmSession const * 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" */ +OLM_EXPORT 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" */ +OLM_EXPORT 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 */ +OLM_EXPORT 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 */ +OLM_EXPORT 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.*/ +OLM_EXPORT size_t olm_create_account_random_length( + OlmAccount const * account +); + +/** Creates a new account. Returns olm_error() on failure. If there weren't + * enough random bytes then olm_account_last_error() will be + * "NOT_ENOUGH_RANDOM" */ +OLM_EXPORT size_t olm_create_account( + OlmAccount * account, + void * random, size_t random_length +); + +/** The size of the output buffer needed to hold the identity keys */ +OLM_EXPORT size_t olm_account_identity_keys_length( + OlmAccount const * account +); + +/** Writes the public parts of the identity keys for the account into the + * identity_keys output buffer. Returns olm_error() on failure. If the + * identity_keys buffer was too small then olm_account_last_error() will be + * "OUTPUT_BUFFER_TOO_SMALL". */ +OLM_EXPORT size_t olm_account_identity_keys( + OlmAccount * account, + void * identity_keys, size_t identity_key_length +); + + +/** The length of an ed25519 signature encoded as base64. */ +OLM_EXPORT size_t olm_account_signature_length( + OlmAccount const * account +); + +/** Signs a message with the ed25519 key for this account. Returns olm_error() + * on failure. If the signature buffer was too small then + * olm_account_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" */ +OLM_EXPORT size_t olm_account_sign( + OlmAccount * account, + void const * message, size_t message_length, + void * signature, size_t signature_length +); + +/** The size of the output buffer needed to hold the one time keys */ +OLM_EXPORT size_t olm_account_one_time_keys_length( + OlmAccount const * account +); + +/** Writes the public parts of the unpublished one time keys for the account + * into the one_time_keys output buffer. + * <p> + * The returned data is a JSON-formatted object with the single property + * <tt>curve25519</tt>, which is itself an object mapping key id to + * base64-encoded Curve25519 key. For example: + * <pre> + * { + * curve25519: { + * "AAAAAA": "wo76WcYtb0Vk/pBOdmduiGJ0wIEjW4IBMbbQn7aSnTo", + * "AAAAAB": "LRvjo46L1X2vx69sS9QNFD29HWulxrmW11Up5AfAjgU" + * } + * } + * </pre> + * Returns olm_error() on failure. + * <p> + * If the one_time_keys buffer was too small then olm_account_last_error() + * will be "OUTPUT_BUFFER_TOO_SMALL". */ +OLM_EXPORT size_t olm_account_one_time_keys( + OlmAccount * account, + void * one_time_keys, size_t one_time_keys_length +); + +/** Marks the current set of one time keys and fallback key as being published + * Once marked as published, the one time keys will no longer be returned by + * olm_account_one_time_keys(), and the fallback key will no longer be returned + * by olm_account_unpublished_fallback_key(). + * + * Returns the number of one-time keys that were marked as published. Note that + * this count does not include the fallback key. */ +OLM_EXPORT size_t olm_account_mark_keys_as_published( + OlmAccount * account +); + +/** The largest number of one time keys this account can store. */ +OLM_EXPORT size_t olm_account_max_number_of_one_time_keys( + OlmAccount const * account +); + +/** The number of random bytes needed to generate a given number of new one + * time keys. */ +OLM_EXPORT size_t olm_account_generate_one_time_keys_random_length( + OlmAccount const * account, + size_t number_of_keys +); + +/** Generates a number of new one time keys. If the total number of keys stored + * by this account exceeds max_number_of_one_time_keys() then the old keys are + * discarded. Returns olm_error() on error. If the number of random bytes is + * too small then olm_account_last_error() will be "NOT_ENOUGH_RANDOM". */ +OLM_EXPORT size_t olm_account_generate_one_time_keys( + OlmAccount * account, + size_t number_of_keys, + void * random, size_t random_length +); + +/** The number of random bytes needed to generate a fallback key. */ +OLM_EXPORT size_t olm_account_generate_fallback_key_random_length( + OlmAccount const * account +); + +/** Generates a new fallback key. Only one previous fallback key is + * stored. Returns olm_error() on error. If the number of random bytes is too + * small then olm_account_last_error() will be "NOT_ENOUGH_RANDOM". */ +OLM_EXPORT size_t olm_account_generate_fallback_key( + OlmAccount * account, + void * random, size_t random_length +); + +/** The number of bytes needed to hold the fallback key as returned by + * olm_account_fallback_key. */ +OLM_EXPORT size_t olm_account_fallback_key_length( + OlmAccount const * account +); + +/** Deprecated: use olm_account_unpublished_fallback_key instead */ +OLM_EXPORT size_t olm_account_fallback_key( + OlmAccount * account, + void * fallback_key, size_t fallback_key_size +); + +/** The number of bytes needed to hold the unpublished fallback key as returned + * by olm_account_unpublished fallback_key. */ +OLM_EXPORT size_t olm_account_unpublished_fallback_key_length( + OlmAccount const * account +); + +/** Returns the fallback key (if present, and if unpublished) into the + * fallback_key buffer */ +OLM_EXPORT size_t olm_account_unpublished_fallback_key( + OlmAccount * account, + void * fallback_key, size_t fallback_key_size +); + +/** Forget about the old fallback key. This should be called once you are + * reasonably certain that you will not receive any more messages that use + * the old fallback key (e.g. 5 minutes after the new fallback key has been + * published). + */ +OLM_EXPORT void olm_account_forget_old_fallback_key( + OlmAccount * account +); + + +/** The number of random bytes needed to create an outbound session */ +OLM_EXPORT size_t olm_create_outbound_session_random_length( + OlmSession const * 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". */ +OLM_EXPORT size_t olm_create_outbound_session( + OlmSession * session, + OlmAccount const * account, + void const * their_identity_key, size_t their_identity_key_length, + void const * their_one_time_key, size_t their_one_time_key_length, + void * 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 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". */ +OLM_EXPORT size_t olm_create_inbound_session( + OlmSession * session, + OlmAccount * account, + void * one_time_key_message, size_t message_length +); + +/** Same as olm_create_inbound_session, but ensures that the identity key + * in the pre-key message matches the expected identity key, supplied via the + * `their_identity_key` parameter. Fails early if there is no match. */ +OLM_EXPORT size_t olm_create_inbound_session_from( + OlmSession * session, + OlmAccount * account, + void const * their_identity_key, size_t their_identity_key_length, + void * one_time_key_message, size_t message_length +); + +/** The length of the buffer needed to return the id for this session. */ +OLM_EXPORT size_t olm_session_id_length( + OlmSession const * session +); + +/** An identifier for this session. Will be the same for both ends of the + * conversation. If the id buffer is too small then olm_session_last_error() + * will be "OUTPUT_BUFFER_TOO_SMALL". */ +OLM_EXPORT size_t olm_session_id( + OlmSession * session, + void * id, size_t id_length +); + +OLM_EXPORT int olm_session_has_received_message( + OlmSession const *session +); + +/** + * Write a null-terminated string describing the internal state of an olm + * session to the buffer provided for debugging and logging purposes. If the + * buffer is not large enough to hold the entire string, it will be truncated + * and will end with "...". A buffer length of 600 will be enough to hold any + * output. + */ +OLM_EXPORT void olm_session_describe(OlmSession * session, char *buf, size_t buflen); + +/** 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. The one_time_key_message buffer is destroyed. Returns 1 if + * the session matches. Returns 0 if the session does not match. 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". */ +OLM_EXPORT size_t olm_matches_inbound_session( + OlmSession * session, + 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. The one_time_key_message buffer is destroyed. Returns 1 if + * the session matches. Returns 0 if the session does not match. 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". */ +OLM_EXPORT size_t olm_matches_inbound_session_from( + OlmSession * session, + void const * their_identity_key, size_t their_identity_key_length, + 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". */ +OLM_EXPORT 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. */ +OLM_EXPORT size_t olm_encrypt_message_type( + OlmSession const * session +); + +/** The number of random bytes needed to encrypt the next message. */ +OLM_EXPORT size_t olm_encrypt_random_length( + OlmSession const * session +); + +/** The size of the next message in bytes for the given number of plain-text + * bytes. */ +OLM_EXPORT size_t olm_encrypt_message_length( + OlmSession const * 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". */ +OLM_EXPORT size_t olm_encrypt( + OlmSession * session, + void const * plaintext, size_t plaintext_length, + void * 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". */ +OLM_EXPORT 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". */ +OLM_EXPORT size_t olm_decrypt( + OlmSession * session, + size_t message_type, + void * message, size_t message_length, + void * plaintext, size_t max_plaintext_length +); + +/** The length of the buffer needed to hold the SHA-256 hash. */ +OLM_EXPORT size_t olm_sha256_length( + OlmUtility const * utility +); + +/** Calculates the SHA-256 hash of the input and encodes it as base64. If the + * output buffer is smaller than olm_sha256_length() then + * olm_utility_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". */ +OLM_EXPORT size_t olm_sha256( + OlmUtility * utility, + void const * input, size_t input_length, + void * output, size_t output_length +); + +/** Verify an ed25519 signature. If the key was too small then + * olm_utility_last_error() will be "INVALID_BASE64". If the signature was invalid + * then olm_utility_last_error() will be "BAD_MESSAGE_MAC". */ +OLM_EXPORT size_t olm_ed25519_verify( + OlmUtility * utility, + void const * key, size_t key_length, + void const * message, size_t message_length, + void * signature, size_t signature_length +); + +#ifdef __cplusplus +} +#endif + +#endif /* OLM_H_ */ diff --git a/ext/olm/include/olm/olm.hh b/ext/olm/include/olm/olm.hh new file mode 100644 index 0000000..5ca59c3 --- /dev/null +++ b/ext/olm/include/olm/olm.hh @@ -0,0 +1,4 @@ +/* this file exists only for compatibility with existing applications. + * You should use "#include <olm/olm.h>" instead. + */ +#include "olm/olm.h" diff --git a/ext/olm/include/olm/olm_export.h b/ext/olm/include/olm/olm_export.h new file mode 100644 index 0000000..d7197a2 --- /dev/null +++ b/ext/olm/include/olm/olm_export.h @@ -0,0 +1,42 @@ + +#ifndef OLM_EXPORT_H +#define OLM_EXPORT_H + +#ifdef OLM_STATIC_DEFINE +# define OLM_EXPORT +# define OLM_NO_EXPORT +#else +# ifndef OLM_EXPORT +# ifdef olm_EXPORTS + /* We are building this library */ +# define OLM_EXPORT +# else + /* We are using this library */ +# define OLM_EXPORT +# endif +# endif + +# ifndef OLM_NO_EXPORT +# define OLM_NO_EXPORT +# endif +#endif + +#ifndef OLM_DEPRECATED +# define OLM_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef OLM_DEPRECATED_EXPORT +# define OLM_DEPRECATED_EXPORT OLM_EXPORT OLM_DEPRECATED +#endif + +#ifndef OLM_DEPRECATED_NO_EXPORT +# define OLM_DEPRECATED_NO_EXPORT OLM_NO_EXPORT OLM_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef OLM_NO_DEPRECATED +# define OLM_NO_DEPRECATED +# endif +#endif + +#endif /* OLM_EXPORT_H */ diff --git a/ext/olm/include/olm/outbound_group_session.h b/ext/olm/include/olm/outbound_group_session.h new file mode 100644 index 0000000..ccfbee5 --- /dev/null +++ b/ext/olm/include/olm/outbound_group_session.h @@ -0,0 +1,192 @@ +/* Copyright 2016 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_OUTBOUND_GROUP_SESSION_H_ +#define OLM_OUTBOUND_GROUP_SESSION_H_ + +#include <stddef.h> +#include <stdint.h> + +#include "olm/error.h" + +#include "olm/olm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OlmOutboundGroupSession OlmOutboundGroupSession; + +/** get the size of an outbound group session, in bytes. */ +OLM_EXPORT size_t olm_outbound_group_session_size(void); + +/** + * Initialise an outbound group session object using the supplied memory + * The supplied memory should be at least olm_outbound_group_session_size() + * bytes. + */ +OLM_EXPORT OlmOutboundGroupSession * olm_outbound_group_session( + void *memory +); + +/** + * A null terminated string describing the most recent error to happen to a + * group session */ +OLM_EXPORT const char *olm_outbound_group_session_last_error( + const OlmOutboundGroupSession *session +); + +/** + * An error code describing the most recent error to happen to a group + * session */ +OLM_EXPORT enum OlmErrorCode olm_outbound_group_session_last_error_code( + const OlmOutboundGroupSession *session +); + +/** Clears the memory used to back this group session */ +OLM_EXPORT size_t olm_clear_outbound_group_session( + OlmOutboundGroupSession *session +); + +/** Returns the number of bytes needed to store an outbound group session */ +OLM_EXPORT size_t olm_pickle_outbound_group_session_length( + const OlmOutboundGroupSession *session +); + +/** + * Stores a group session as a base64 string. Encrypts the session using the + * supplied key. Returns the length of the session on success. + * + * Returns olm_error() on failure. If the pickle output buffer + * is smaller than olm_pickle_outbound_group_session_length() then + * olm_outbound_group_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" + */ +OLM_EXPORT size_t olm_pickle_outbound_group_session( + OlmOutboundGroupSession *session, + void const * key, size_t key_length, + void * pickled, size_t pickled_length +); + +/** + * Loads a group 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_outbound_group_session_last_error() will be + * "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then + * olm_outbound_group_session_last_error() will be "INVALID_BASE64". The input + * pickled buffer is destroyed + */ +OLM_EXPORT size_t olm_unpickle_outbound_group_session( + OlmOutboundGroupSession *session, + void const * key, size_t key_length, + void * pickled, size_t pickled_length +); + + +/** The number of random bytes needed to create an outbound group session */ +OLM_EXPORT size_t olm_init_outbound_group_session_random_length( + const OlmOutboundGroupSession *session +); + +/** + * Start a new outbound group session. Returns olm_error() 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. + */ +OLM_EXPORT size_t olm_init_outbound_group_session( + OlmOutboundGroupSession *session, + uint8_t *random, size_t random_length +); + +/** + * The number of bytes that will be created by encrypting a message + */ +OLM_EXPORT size_t olm_group_encrypt_message_length( + OlmOutboundGroupSession *session, + size_t plaintext_length +); + +/** + * Encrypt some plain-text. Returns the length of the encrypted message or + * olm_error() on failure. On failure last_error will be set with an + * error code. The last_error will be OUTPUT_BUFFER_TOO_SMALL if the output + * buffer is too small. + */ +OLM_EXPORT size_t olm_group_encrypt( + OlmOutboundGroupSession *session, + uint8_t const * plaintext, size_t plaintext_length, + uint8_t * message, size_t message_length +); + + +/** + * Get the number of bytes returned by olm_outbound_group_session_id() + */ +OLM_EXPORT size_t olm_outbound_group_session_id_length( + const OlmOutboundGroupSession *session +); + +/** + * Get a base64-encoded identifier for this session. + * + * Returns the length of the session id on success or olm_error() 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. + */ +OLM_EXPORT size_t olm_outbound_group_session_id( + OlmOutboundGroupSession *session, + uint8_t * id, size_t id_length +); + +/** + * Get the current message index for this session. + * + * Each message is sent with an increasing index; this returns the index for + * the next message. + */ +OLM_EXPORT uint32_t olm_outbound_group_session_message_index( + OlmOutboundGroupSession *session +); + +/** + * Get the number of bytes returned by olm_outbound_group_session_key() + */ +OLM_EXPORT size_t olm_outbound_group_session_key_length( + const OlmOutboundGroupSession *session +); + +/** + * Get the base64-encoded current ratchet key for this session. + * + * Each message is sent with a different ratchet key. This function returns the + * ratchet key that will be used for the next message. + * + * Returns the length of the ratchet key on success or olm_error() on + * failure. On failure last_error will be set with an error code. The + * last_error will be OUTPUT_BUFFER_TOO_SMALL if the buffer was too small. + */ +OLM_EXPORT size_t olm_outbound_group_session_key( + OlmOutboundGroupSession *session, + uint8_t * key, size_t key_length +); + + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* OLM_OUTBOUND_GROUP_SESSION_H_ */ diff --git a/ext/olm/include/olm/pickle.h b/ext/olm/include/olm/pickle.h new file mode 100644 index 0000000..d62c371 --- /dev/null +++ b/ext/olm/include/olm/pickle.h @@ -0,0 +1,107 @@ +/* Copyright 2015-2016 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_H_ +#define OLM_PICKLE_H_ + +#include <stddef.h> +#include <stdint.h> + +/* Convenience macro for checking the return value of internal unpickling + * functions and returning early on failure. */ +#ifndef UNPICKLE_OK +#define UNPICKLE_OK(x) do { if (!(x)) return NULL; } while(0) +#endif + +/* Convenience macro for failing on corrupted pickles from public + * API unpickling functions. */ +#define FAIL_ON_CORRUPTED_PICKLE(pos, session) \ + do { \ + if (!pos) { \ + session->last_error = OLM_CORRUPTED_PICKLE; \ + return (size_t)-1; \ + } \ + } while(0) + +#ifdef __cplusplus +extern "C" { +#endif + +struct _olm_ed25519_public_key; +struct _olm_ed25519_key_pair; + + +#define _olm_pickle_uint32_length(value) 4 +uint8_t * _olm_pickle_uint32(uint8_t * pos, uint32_t value); +uint8_t const * _olm_unpickle_uint32( + uint8_t const * pos, uint8_t const * end, + uint32_t *value +); + + +#define _olm_pickle_bool_length(value) 1 +uint8_t * _olm_pickle_bool(uint8_t * pos, int value); +uint8_t const * _olm_unpickle_bool( + uint8_t const * pos, uint8_t const * end, + int *value +); + +#define _olm_pickle_bytes_length(bytes, bytes_length) (bytes_length) +uint8_t * _olm_pickle_bytes(uint8_t * pos, uint8_t const * bytes, + size_t bytes_length); +uint8_t const * _olm_unpickle_bytes(uint8_t const * pos, uint8_t const * end, + uint8_t * bytes, size_t bytes_length); + + +/** Get the number of bytes needed to pickle an ed25519 public key */ +size_t _olm_pickle_ed25519_public_key_length( + const struct _olm_ed25519_public_key * value +); + +/** Pickle the ed25519 public key. Returns a pointer to the next free space in + * the buffer. */ +uint8_t * _olm_pickle_ed25519_public_key( + uint8_t *pos, const struct _olm_ed25519_public_key * value +); + +/** Unpickle the ed25519 public key. Returns a pointer to the next item in the + * buffer on success, NULL on error. */ +const uint8_t * _olm_unpickle_ed25519_public_key( + const uint8_t *pos, const uint8_t *end, + struct _olm_ed25519_public_key * value +); + +/** Get the number of bytes needed to pickle an ed25519 key pair */ +size_t _olm_pickle_ed25519_key_pair_length( + const struct _olm_ed25519_key_pair * value +); + +/** Pickle the ed25519 key pair. Returns a pointer to the next free space in + * the buffer. */ +uint8_t * _olm_pickle_ed25519_key_pair( + uint8_t *pos, const struct _olm_ed25519_key_pair * value +); + +/** Unpickle the ed25519 key pair. Returns a pointer to the next item in the + * buffer on success, NULL on error. */ +const uint8_t * _olm_unpickle_ed25519_key_pair( + const uint8_t *pos, const uint8_t *end, + struct _olm_ed25519_key_pair * value +); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* OLM_PICKLE_H */ diff --git a/ext/olm/include/olm/pickle.hh b/ext/olm/include/olm/pickle.hh new file mode 100644 index 0000000..f8d41b6 --- /dev/null +++ b/ext/olm/include/olm/pickle.hh @@ -0,0 +1,182 @@ +/* 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.h" + +#include <cstring> +#include <cstdint> + +/* Convenience macro for checking the return value of internal unpickling + * functions and returning early on failure. */ +#ifndef UNPICKLE_OK +#define UNPICKLE_OK(x) do { if (!(x)) return nullptr; } while(0) +#endif + +namespace olm { + +inline std::size_t pickle_length( + const std::uint32_t & value +) { + return 4; +} + +std::uint8_t * pickle( + std::uint8_t * pos, + std::uint32_t value +); + +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + std::uint32_t & value +); + + +inline std::size_t pickle_length( + const std::uint8_t & value +) { + return 1; +} + +std::uint8_t * pickle( + std::uint8_t * pos, + std::uint8_t value +); + +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + std::uint8_t & value +); + + +inline std::size_t pickle_length( + const bool & value +) { + return 1; +} + +std::uint8_t * pickle( + std::uint8_t * pos, + bool value +); + +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + bool & value +); + + +template<typename T, std::size_t max_size> +std::size_t pickle_length( + olm::List<T, max_size> 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<typename T, std::size_t max_size> +std::uint8_t * pickle( + std::uint8_t * pos, + olm::List<T, max_size> const & list +) { + pos = pickle(pos, std::uint32_t(list.size())); + for (auto const & value : list) { + pos = pickle(pos, value); + } + return pos; +} + + +template<typename T, std::size_t max_size> +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + olm::List<T, max_size> & list +) { + std::uint32_t size; + + pos = unpickle(pos, end, size); + if (!pos) { + return nullptr; + } + + while (size-- && pos != end) { + T * value = list.insert(list.end()); + pos = unpickle(pos, end, *value); + + if (!pos) { + return nullptr; + } + } + + return pos; +} + + +std::uint8_t * pickle_bytes( + std::uint8_t * pos, + std::uint8_t const * bytes, std::size_t bytes_length +); + +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 +); + + +std::size_t pickle_length( + const _olm_curve25519_public_key & value +); + + +std::uint8_t * pickle( + std::uint8_t * pos, + const _olm_curve25519_public_key & value +); + + +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + _olm_curve25519_public_key & value +); + + +std::size_t pickle_length( + const _olm_curve25519_key_pair & value +); + + +std::uint8_t * pickle( + std::uint8_t * pos, + const _olm_curve25519_key_pair & value +); + + +std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + _olm_curve25519_key_pair & value +); + +} // namespace olm + + + + +#endif /* OLM_PICKLE_HH */ diff --git a/ext/olm/include/olm/pickle_encoding.h b/ext/olm/include/olm/pickle_encoding.h new file mode 100644 index 0000000..ec2a2d6 --- /dev/null +++ b/ext/olm/include/olm/pickle_encoding.h @@ -0,0 +1,80 @@ +/* Copyright 2016 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. + */ + +/* functions for encrypting and decrypting pickled representations of objects */ + +#ifndef OLM_PICKLE_ENCODING_H_ +#define OLM_PICKLE_ENCODING_H_ + +#include <stddef.h> +#include <stdint.h> + +#include "olm/error.h" + +// Note: exports in this file are only for unit tests. Nobody else should be +// using this externally +#include "olm/olm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Get the number of bytes needed to encode a pickle of the length given + */ +OLM_EXPORT size_t _olm_enc_output_length(size_t raw_length); + +/** + * Get the point in the output buffer that the raw pickle should be written to. + * + * In order that we can use the same buffer for the raw pickle, and the encoded + * pickle, the raw pickle needs to be written at the end of the buffer. (The + * base-64 encoding would otherwise overwrite the end of the input before it + * was encoded.) + */ +OLM_EXPORT uint8_t *_olm_enc_output_pos(uint8_t * output, size_t raw_length); + +/** + * Encrypt and encode the given pickle in-situ. + * + * The raw pickle should have been written to enc_output_pos(pickle, + * raw_length). + * + * Returns the number of bytes in the encoded pickle. + */ +OLM_EXPORT size_t _olm_enc_output( + uint8_t const * key, size_t key_length, + uint8_t *pickle, size_t raw_length +); + +/** + * Decode and decrypt the given pickle in-situ. + * + * Returns the number of bytes in the decoded pickle, or olm_error() on error, + * in which case *last_error will be updated, if last_error is non-NULL. + */ +OLM_EXPORT size_t _olm_enc_input( + uint8_t const * key, size_t key_length, + uint8_t * input, size_t b64_length, + enum OlmErrorCode * last_error +); + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* OLM_PICKLE_ENCODING_H_ */ diff --git a/ext/olm/include/olm/pk.h b/ext/olm/include/olm/pk.h new file mode 100644 index 0000000..b3670fe --- /dev/null +++ b/ext/olm/include/olm/pk.h @@ -0,0 +1,298 @@ +/* Copyright 2018, 2019 New Vector 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_PK_H_ +#define OLM_PK_H_ + +#include <stddef.h> +#include <stdint.h> + +#include "olm/error.h" + +#include "olm/olm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OlmPkEncryption OlmPkEncryption; + +/* The size of an encryption object in bytes */ +OLM_EXPORT size_t olm_pk_encryption_size(void); + +/** Initialise an encryption object using the supplied memory + * The supplied memory must be at least olm_pk_encryption_size() bytes */ +OLM_EXPORT OlmPkEncryption *olm_pk_encryption( + void * memory +); + +/** A null terminated string describing the most recent error to happen to an + * encryption object */ +OLM_EXPORT const char * olm_pk_encryption_last_error( + const OlmPkEncryption * encryption +); + +/** An error code describing the most recent error to happen to an encryption + * object */ +OLM_EXPORT enum OlmErrorCode olm_pk_encryption_last_error_code( + const OlmPkEncryption * encryption +); + +/** Clears the memory used to back this encryption object */ +OLM_EXPORT size_t olm_clear_pk_encryption( + OlmPkEncryption *encryption +); + +/** Set the recipient's public key for encrypting to */ +OLM_EXPORT size_t olm_pk_encryption_set_recipient_key( + OlmPkEncryption *encryption, + void const *public_key, size_t public_key_length +); + +/** Get the length of the ciphertext that will correspond to a plaintext of the + * given length. */ +OLM_EXPORT size_t olm_pk_ciphertext_length( + const OlmPkEncryption *encryption, + size_t plaintext_length +); + +/** Get the length of the message authentication code. */ +OLM_EXPORT size_t olm_pk_mac_length( + const OlmPkEncryption *encryption +); + +/** Get the length of a public or ephemeral key */ +OLM_EXPORT size_t olm_pk_key_length(void); + +/** The number of random bytes needed to encrypt a message. */ +OLM_EXPORT size_t olm_pk_encrypt_random_length( + const OlmPkEncryption *encryption +); + +/** Encrypt a plaintext for the recipient set using + * olm_pk_encryption_set_recipient_key. Writes to the ciphertext, mac, and + * ephemeral_key buffers, whose values should be sent to the recipient. mac is + * a Message Authentication Code to ensure that the data is received and + * decrypted properly. ephemeral_key is the public part of the ephemeral key + * used (together with the recipient's key) to generate a symmetric encryption + * key. Returns olm_error() on failure. If the ciphertext, mac, or + * ephemeral_key buffers were too small then olm_pk_encryption_last_error() + * will be "OUTPUT_BUFFER_TOO_SMALL". If there weren't enough random bytes then + * olm_pk_encryption_last_error() will be "OLM_INPUT_BUFFER_TOO_SMALL". */ +OLM_EXPORT size_t olm_pk_encrypt( + OlmPkEncryption *encryption, + void const * plaintext, size_t plaintext_length, + void * ciphertext, size_t ciphertext_length, + void * mac, size_t mac_length, + void * ephemeral_key, size_t ephemeral_key_size, + const void * random, size_t random_length +); + +typedef struct OlmPkDecryption OlmPkDecryption; + +/* The size of a decryption object in bytes */ +OLM_EXPORT size_t olm_pk_decryption_size(void); + +/** Initialise a decryption object using the supplied memory + * The supplied memory must be at least olm_pk_decryption_size() bytes */ +OLM_EXPORT OlmPkDecryption *olm_pk_decryption( + void * memory +); + +/** A null terminated string describing the most recent error to happen to a + * decription object */ +OLM_EXPORT const char * olm_pk_decryption_last_error( + const OlmPkDecryption * decryption +); + +/** An error code describing the most recent error to happen to a decription + * object */ +OLM_EXPORT enum OlmErrorCode olm_pk_decryption_last_error_code( + const OlmPkDecryption * decryption +); + +/** Clears the memory used to back this decryption object */ +OLM_EXPORT size_t olm_clear_pk_decryption( + OlmPkDecryption *decryption +); + +/** Get the number of bytes required to store an olm private key + */ +OLM_EXPORT size_t olm_pk_private_key_length(void); + +/** DEPRECATED: Use olm_pk_private_key_length() + */ +OLM_EXPORT size_t olm_pk_generate_key_random_length(void); + +/** Initialise the key from the private part of a key as returned by + * olm_pk_get_private_key(). The associated public key will be written to the + * pubkey buffer. Returns olm_error() on failure. If the pubkey buffer is too + * small then olm_pk_decryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". + * If the private key was not long enough then olm_pk_decryption_last_error() + * will be "OLM_INPUT_BUFFER_TOO_SMALL". + * + * Note that the pubkey is a base64 encoded string, but the private key is + * an unencoded byte array + */ +OLM_EXPORT size_t olm_pk_key_from_private( + OlmPkDecryption * decryption, + void * pubkey, size_t pubkey_length, + const void * privkey, size_t privkey_length +); + +/** DEPRECATED: Use olm_pk_key_from_private + */ +OLM_EXPORT size_t olm_pk_generate_key( + OlmPkDecryption * decryption, + void * pubkey, size_t pubkey_length, + const void * privkey, size_t privkey_length +); + +/** Returns the number of bytes needed to store a decryption object. */ +OLM_EXPORT size_t olm_pickle_pk_decryption_length( + const OlmPkDecryption * decryption +); + +/** Stores decryption object as a base64 string. Encrypts the object using the + * supplied key. Returns the length of the pickled object on success. + * Returns olm_error() on failure. If the pickle output buffer + * is smaller than olm_pickle_pk_decryption_length() then + * olm_pk_decryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" */ +OLM_EXPORT size_t olm_pickle_pk_decryption( + OlmPkDecryption * decryption, + void const * key, size_t key_length, + void *pickled, size_t pickled_length +); + +/** Loads a decryption object from a pickled base64 string. The associated + * public key will be written to the pubkey buffer. Decrypts the object using + * the supplied key. Returns olm_error() on failure. If the key doesn't + * match the one used to encrypt the account then olm_pk_decryption_last_error() + * will be "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then + * olm_pk_decryption_last_error() will be "INVALID_BASE64". The input pickled + * buffer is destroyed */ +OLM_EXPORT size_t olm_unpickle_pk_decryption( + OlmPkDecryption * decryption, + void const * key, size_t key_length, + void *pickled, size_t pickled_length, + void *pubkey, size_t pubkey_length +); + +/** Get the length of the plaintext that will correspond to a ciphertext of the + * given length. */ +OLM_EXPORT size_t olm_pk_max_plaintext_length( + const OlmPkDecryption * decryption, + size_t ciphertext_length +); + +/** Decrypt a ciphertext. The input ciphertext buffer is destroyed. See the + * olm_pk_encrypt function for descriptions of the ephemeral_key and mac + * arguments. Returns the length of the plaintext on success. Returns + * olm_error() on failure. If the plaintext buffer is too small then + * olm_pk_encryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". */ +OLM_EXPORT size_t olm_pk_decrypt( + OlmPkDecryption * decryption, + void const * ephemeral_key, size_t ephemeral_key_length, + void const * mac, size_t mac_length, + void * ciphertext, size_t ciphertext_length, + void * plaintext, size_t max_plaintext_length +); + +/** + * Get the private key for an OlmDecryption object as an unencoded byte array + * private_key must be a pointer to a buffer of at least + * olm_pk_private_key_length() bytes and this length must be passed in + * private_key_length. If the given buffer is too small, returns olm_error() + * and olm_pk_encryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". + * Returns the number of bytes written. + */ +OLM_EXPORT size_t olm_pk_get_private_key( + OlmPkDecryption * decryption, + void *private_key, size_t private_key_length +); + +typedef struct OlmPkSigning OlmPkSigning; + +/* The size of a signing object in bytes */ +OLM_EXPORT size_t olm_pk_signing_size(void); + +/** Initialise a signing object using the supplied memory + * The supplied memory must be at least olm_pk_signing_size() bytes */ +OLM_EXPORT OlmPkSigning *olm_pk_signing( + void * memory +); + +/** A null terminated string describing the most recent error to happen to a + * signing object */ +OLM_EXPORT const char * olm_pk_signing_last_error( + const OlmPkSigning * sign +); + +/** A null terminated string describing the most recent error to happen to a + * signing object */ +OLM_EXPORT enum OlmErrorCode olm_pk_signing_last_error_code( + const OlmPkSigning * sign +); + +/** Clears the memory used to back this signing object */ +OLM_EXPORT size_t olm_clear_pk_signing( + OlmPkSigning *sign +); + +/** + * Initialise the signing object with a public/private keypair from a seed. The + * associated public key will be written to the pubkey buffer. Returns + * olm_error() on failure. If the public key buffer is too small then + * olm_pk_signing_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". If the seed + * buffer is too small then olm_pk_signing_last_error() will be + * "INPUT_BUFFER_TOO_SMALL". + */ +OLM_EXPORT size_t olm_pk_signing_key_from_seed( + OlmPkSigning * sign, + void * pubkey, size_t pubkey_length, + const void * seed, size_t seed_length +); + +/** + * The size required for the seed for initialising a signing object. + */ +OLM_EXPORT size_t olm_pk_signing_seed_length(void); + +/** + * The size of the public key of a signing object. + */ +OLM_EXPORT size_t olm_pk_signing_public_key_length(void); + +/** + * The size of a signature created by a signing object. + */ +OLM_EXPORT size_t olm_pk_signature_length(void); + +/** + * Sign a message. The signature will be written to the signature + * buffer. Returns olm_error() on failure. If the signature buffer is too + * small, olm_pk_signing_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". + */ +OLM_EXPORT size_t olm_pk_sign( + OlmPkSigning *sign, + uint8_t const * message, size_t message_length, + uint8_t * signature, size_t signature_length +); + +#ifdef __cplusplus +} +#endif + +#endif /* OLM_PK_H_ */ diff --git a/ext/olm/include/olm/ratchet.hh b/ext/olm/include/olm/ratchet.hh new file mode 100644 index 0000000..2ada0eb --- /dev/null +++ b/ext/olm/include/olm/ratchet.hh @@ -0,0 +1,188 @@ +/* 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 <cstdint> + +#include "olm/crypto.h" +#include "olm/list.hh" +#include "olm/error.h" + +// Note: exports in this file are only for unit tests. Nobody else should be +// using this externally +#include "olm/olm_export.h" + +struct _olm_cipher; + +namespace olm { + +/** length of a shared key: the root key R(i), chain key C(i,j), and message key + * M(i,j)). They are all only used to stuff into HMACs, so could be any length + * for that. The chain key and message key are both derived from SHA256 + * operations, so their length is determined by that. */ +const std::size_t OLM_SHARED_KEY_LENGTH = SHA256_OUTPUT_LENGTH; + +typedef std::uint8_t SharedKey[OLM_SHARED_KEY_LENGTH]; + +struct ChainKey { + std::uint32_t index; + SharedKey key; +}; + +struct MessageKey { + std::uint32_t index; + SharedKey key; +}; + + +struct SenderChain { + _olm_curve25519_key_pair ratchet_key; + ChainKey chain_key; +}; + + +struct ReceiverChain { + _olm_curve25519_public_key ratchet_key; + ChainKey chain_key; +}; + + +struct SkippedMessageKey { + _olm_curve25519_public_key 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 OLM_EXPORT Ratchet { + + Ratchet( + KdfInfo const & kdf_info, + _olm_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. */ + _olm_cipher const *ratchet_cipher; + + /** The last error that happened encrypting or decrypting a message. */ + OlmErrorCode last_error; + + /** The root key is used to generate chain keys from the ephemeral keys. + * A new root_key derived each time a new chain is started. */ + 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 ephemeral key when we next send a message. */ + List<SenderChain, 1> 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<ReceiverChain, MAX_RECEIVER_CHAINS> receiver_chains; + + /** List of message keys we've skipped over when advancing the receiver + * chain. */ + List<SkippedMessageKey, MAX_SKIPPED_MESSAGE_KEYS> 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, + _olm_curve25519_public_key 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, + _olm_curve25519_key_pair 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 + ) const; + + /** 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() const; + + /** 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, + bool includes_chain_index +); + + +} // namespace olm diff --git a/ext/olm/include/olm/sas.h b/ext/olm/include/olm/sas.h new file mode 100644 index 0000000..df5a1f5 --- /dev/null +++ b/ext/olm/include/olm/sas.h @@ -0,0 +1,197 @@ +/* Copyright 2018-2019 New Vector 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_SAS_H_ +#define OLM_SAS_H_ + +#include <stddef.h> + +#include "olm/error.h" + +#include "olm/olm_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup SAS Short Authentication String verification + * These functions are used for verifying keys using the Short Authentication + * String (SAS) method. + * @{ + */ + +typedef struct OlmSAS OlmSAS; + +/** A null terminated string describing the most recent error to happen to an + * SAS object. */ +OLM_EXPORT const char * olm_sas_last_error( + const OlmSAS * sas +); + +/** An error code describing the most recent error to happen to an SAS + * object. */ +OLM_EXPORT enum OlmErrorCode olm_sas_last_error_code( + const OlmSAS * sas +); + +/** The size of an SAS object in bytes. */ +OLM_EXPORT size_t olm_sas_size(void); + +/** Initialize an SAS object using the supplied memory. + * The supplied memory must be at least `olm_sas_size()` bytes. */ +OLM_EXPORT OlmSAS * olm_sas( + void * memory +); + +/** Clears the memory used to back an SAS object. */ +OLM_EXPORT size_t olm_clear_sas( + OlmSAS * sas +); + +/** The number of random bytes needed to create an SAS object. */ +OLM_EXPORT size_t olm_create_sas_random_length( + const OlmSAS * sas +); + +/** Creates a new SAS object. + * + * @param[in] sas the SAS object to create, initialized by `olm_sas()`. + * @param[in] random array of random bytes. The contents of the buffer may be + * overwritten. + * @param[in] random_length the number of random bytes provided. Must be at + * least `olm_create_sas_random_length()`. + * + * @return `olm_error()` on failure. If there weren't enough random bytes then + * `olm_sas_last_error()` will be `NOT_ENOUGH_RANDOM`. + */ +OLM_EXPORT size_t olm_create_sas( + OlmSAS * sas, + void * random, size_t random_length +); + +/** The size of a public key in bytes. */ +OLM_EXPORT size_t olm_sas_pubkey_length(const OlmSAS * sas); + +/** Get the public key for the SAS object. + * + * @param[in] sas the SAS object. + * @param[out] pubkey buffer to store the public key. + * @param[in] pubkey_length the size of the `pubkey` buffer. Must be at least + * `olm_sas_pubkey_length()`. + * + * @return `olm_error()` on failure. If the `pubkey` buffer is too small, then + * `olm_sas_last_error()` will be `OUTPUT_BUFFER_TOO_SMALL`. + */ +OLM_EXPORT size_t olm_sas_get_pubkey( + OlmSAS * sas, + void * pubkey, size_t pubkey_length +); + +/** Sets the public key of other user. + * + * @param[in] sas the SAS object. + * @param[in] their_key the other user's public key. The contents of the + * buffer will be overwritten. + * @param[in] their_key_length the size of the `their_key` buffer. + * + * @return `olm_error()` on failure. If the `their_key` buffer is too small, + * then `olm_sas_last_error()` will be `INPUT_BUFFER_TOO_SMALL`. + */ +OLM_EXPORT size_t olm_sas_set_their_key( + OlmSAS *sas, + void * their_key, size_t their_key_length +); + +/** Checks if their key was set. + * + * @param[in] sas the SAS object. + * + */ +OLM_EXPORT int olm_sas_is_their_key_set( + const OlmSAS *sas +); + +/** Generate bytes to use for the short authentication string. + * + * @param[in] sas the SAS object. + * @param[in] info extra information to mix in when generating the bytes, as + * per the Matrix spec. + * @param[in] info_length the length of the `info` parameter. + * @param[out] output the output buffer. + * @param[in] output_length the size of the output buffer. For hex-based SAS + * as in the Matrix spec, this will be 5. + * + * @return `olm_error()` on failure. If their key wasn't set then + * `olm_sas_last_error()` will be `SAS_THEIR_KEY_NOT_SET`. + */ +OLM_EXPORT size_t olm_sas_generate_bytes( + OlmSAS * sas, + const void * info, size_t info_length, + void * output, size_t output_length +); + +/** The size of the message authentication code generated by + * olm_sas_calculate_mac()`. */ +OLM_EXPORT size_t olm_sas_mac_length( + const OlmSAS *sas +); + +/** Generate a message authentication code (MAC) based on the shared secret. + * + * @param[in] sas the SAS object. + * @param[in] input the message to produce the authentication code for. + * @param[in] input_length the length of the message. + * @param[in] info extra information to mix in when generating the MAC, as per + * the Matrix spec. + * @param[in] info_length the length of the `info` parameter. + * @param[out] mac the buffer in which to store the MAC. + * @param[in] mac_length the size of the `mac` buffer. Must be at least + * `olm_sas_mac_length()` + * + * @return `olm_error()` on failure. If the `mac` buffer is too small, then + * `olm_sas_last_error()` will be `OUTPUT_BUFFER_TOO_SMALL`. + */ +OLM_EXPORT size_t olm_sas_calculate_mac( + OlmSAS * sas, + const void * input, size_t input_length, + const void * info, size_t info_length, + void * mac, size_t mac_length +); + +// A version of the calculate mac function that produces base64 strings that are +// compatible with other base64 implementations. +OLM_EXPORT size_t olm_sas_calculate_mac_fixed_base64( + OlmSAS * sas, + const void * input, size_t input_length, + const void * info, size_t info_length, + void * mac, size_t mac_length +); + +// for compatibility with an old version of Riot +OLM_EXPORT size_t olm_sas_calculate_mac_long_kdf( + OlmSAS * sas, + const void * input, size_t input_length, + const void * info, size_t info_length, + void * mac, size_t mac_length +); + +/** @} */ // end of SAS group + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* OLM_SAS_H_ */ diff --git a/ext/olm/include/olm/session.hh b/ext/olm/include/olm/session.hh new file mode 100644 index 0000000..41300db --- /dev/null +++ b/ext/olm/include/olm/session.hh @@ -0,0 +1,168 @@ +/* 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" + +// Note: exports in this file are only for unit tests. Nobody else should be +// using this externally +#include "olm/olm_export.h" + +namespace olm { + +struct Account; + +enum struct MessageType { + PRE_KEY = 0, + MESSAGE = 1, +}; + +struct OLM_EXPORT Session { + + Session(); + + Ratchet ratchet; + OlmErrorCode last_error; + + bool received_message; + + _olm_curve25519_public_key alice_identity_key; + _olm_curve25519_public_key alice_base_key; + _olm_curve25519_public_key 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() const; + + /** 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, + _olm_curve25519_public_key const & identity_key, + _olm_curve25519_public_key const & one_time_key, + 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, + _olm_curve25519_public_key const * their_identity_key, + 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() const; + + /** 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( + _olm_curve25519_public_key const * their_identity_key, + std::uint8_t const * pre_key_message, std::size_t message_length + ) const; + + /** 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() const; + + std::size_t encrypt_message_length( + std::size_t plaintext_length + ) const; + + /** 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() const; + + /** 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, + std::uint8_t * plaintext, std::size_t max_plaintext_length + ); + + /** + * Write a string describing this session and its state (not including the + * private key) into the buffer provided. + * + * Takes a buffer to write to and the length of that buffer + */ + void describe(char *buf, size_t buflen); +}; + + +std::size_t pickle_length( + Session const & value +); + + +std::uint8_t * pickle( + std::uint8_t * pos, + Session const & value +); + + +OLM_EXPORT std::uint8_t const * unpickle( + std::uint8_t const * pos, std::uint8_t const * end, + Session & value +); + + +} // namespace olm + +#endif /* OLM_SESSION_HH_ */ diff --git a/ext/olm/include/olm/utility.hh b/ext/olm/include/olm/utility.hh new file mode 100644 index 0000000..3e5f5b7 --- /dev/null +++ b/ext/olm/include/olm/utility.hh @@ -0,0 +1,61 @@ +/* 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 UTILITY_HH_ +#define UTILITY_HH_ + +#include "olm/error.h" + +#include <cstddef> +#include <cstdint> + +struct _olm_ed25519_public_key; + +namespace olm { + +struct Utility { + + Utility(); + + OlmErrorCode last_error; + + /** The length of a SHA-256 hash in bytes. */ + std::size_t sha256_length() const; + + /** 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( + _olm_ed25519_public_key const & key, + std::uint8_t const * message, std::size_t message_length, + std::uint8_t const * signature, std::size_t signature_length + ); + +}; + + +} // namespace olm + +#endif /* UTILITY_HH_ */ |
