Merge branch 'master' into logging_enabled

This commit is contained in:
Richard van der Hoff 2016-09-22 16:04:57 +01:00
commit 9001d3520a
46 changed files with 1175 additions and 751 deletions

6
.gitignore vendored
View file

@ -1,2 +1,6 @@
build
/build
/CHANGELOG.html
/docs/olm.html
/olm-*.tgz
/README.html
/tracing/README.html

69
CHANGELOG.rst Normal file
View file

@ -0,0 +1,69 @@
Changes in `1.3.0 <http://matrix.org/git/olm/commit/?h=1.3.0>`_
===============================================================
The release updates the group session identifier to avoid collisions.
The group sessions are now identified by their ed25519 public key.
These changes alter the pickle format of outbound group sessions, attempting
to unpickle an outbound group session created with a previous version of olm
will give ``OLM_CORRUPTED_PICKLE``. Inbound sessions are unaffected.
This release alters the format of group session_key messages to include the
ratchet counter. The session_key messages are now self signed with their
ed25519 key. No attempt was made to preserve backwards-compatibility.
Attempting to send session_keys between old and new versions will give
``OLM_BAD_SESSION_KEY``.
Changes in `1.2.0 <http://matrix.org/git/olm/commit/?h=1.2.0>`_
===============================================================
This release updates the implementation of group session communications, to
include Ed25519 signatures on group messages, to ensure that participants in
group sessions cannot masquerade as each other.
These changes necessitate changes to the pickle format of inbound and outbound
group sessions, as well as the session_keys exchanged between them. No attempt
has been made to preserve backwards-compatibility:
* Attempting to restore old pickles will give ``OLM_CORRUPTED_PICKLE``.
* Attempting to send session_keys between old and new versions will give
``OLM_BAD_SESSION_KEY``.
* Attempting to send messages between old and new versions will give one of a
number of errors.
There were also a number of implementation changes made as part of this
release, aimed at making the codebase more consistent, and to help with the
implementation of the group message signatures.
Changes in `1.1.0 <http://matrix.org/git/olm/commit/?h=1.1.0>`_
===============================================================
This release includes a fix to a bug which caused Ed25519 keypairs to be
generated and used insecurely. Any Ed25519 keys generated by libolm 1.0.0
or earlier should be considered compromised.
The fix necessitates a change to the format of the OlmAccount pickle; since
existing OlmAccounts should in any case be considered compromised (as above),
the library refuses to load them, returning OLM_BAD_LEGACY_ACCOUNT_PICKLE.
Changes in `1.0.0 <http://matrix.org/git/olm/commit/?h=1.0.0>`_
===============================================================
This release includes a fix to a bug which had the potential to leak sensitive
data to the application: see
https://github.com/vector-im/vector-web/issues/1719. Users of pre-1.x.x
versions of the Olm library should upgrade. Our thanks to `Dmitry Luyciv
<https://github.com/dluciv>`_ for bringing our attention to the bug.
Other changes since 0.1.0:
* *Experimental* implementation of the primitives for group sessions. This
implementation has not yet been used in an application and developers are
advised not to rely on its stability.
* Replace custom build scripts with a Makefile.
* Include the major version number in the soname of libolm.so (credit to
Emmanuel Gil Peyrot).

View file

@ -1,5 +1,10 @@
#!/usr/bin/make -f
MAJOR := 1
MINOR := 3
PATCH := 0
VERSION := $(MAJOR).$(MINOR).$(PATCH)
PREFIX ?= /usr/local
BUILD_DIR := build
RELEASE_OPTIMIZE_FLAGS ?= -g -O3
DEBUG_OPTIMIZE_FLAGS ?= -g -O0
@ -9,8 +14,9 @@ CC = gcc
EMCC = emcc
AFL_CC = afl-gcc
AFL_CXX = afl-g++
RELEASE_TARGET := $(BUILD_DIR)/libolm.so
DEBUG_TARGET := $(BUILD_DIR)/libolm_debug.so
RELEASE_TARGET := $(BUILD_DIR)/libolm.so.$(VERSION)
DEBUG_TARGET := $(BUILD_DIR)/libolm_debug.so.$(VERSION)
JS_TARGET := javascript/olm.js
JS_EXPORTED_FUNCTIONS := javascript/exported_functions.json
@ -37,8 +43,15 @@ JS_PRE := $(wildcard javascript/*pre.js)
JS_POST := javascript/olm_outbound_group_session.js \
javascript/olm_inbound_group_session.js \
javascript/olm_post.js
DOCS := tracing/README.html \
docs/olm.html \
README.html \
CHANGELOG.html
CPPFLAGS += -Iinclude -Ilib \
-DOLMLIB_VERSION_MAJOR=$(MAJOR) -DOLMLIB_VERSION_MINOR=$(MINOR) \
-DOLMLIB_VERSION_PATCH=$(PATCH)
CPPFLAGS += -Iinclude -Ilib
# we rely on <stdint.h>, which was introduced in C99
CFLAGS += -Wall -Werror -std=c99 -fPIC
CXXFLAGS += -Wall -Werror -std=c++11 -fPIC
@ -92,16 +105,20 @@ lib: $(RELEASE_TARGET)
$(RELEASE_TARGET): $(RELEASE_OBJECTS)
$(CXX) $(LDFLAGS) --shared -fPIC \
-Wl,-soname,libolm.so.$(MAJOR) \
-Wl,--version-script,version_script.ver \
$(OUTPUT_OPTION) $(RELEASE_OBJECTS)
ln -sf libolm.so.$(VERSION) $(BUILD_DIR)/libolm.so.$(MAJOR)
debug: $(DEBUG_TARGET)
.PHONY: debug
$(DEBUG_TARGET): $(DEBUG_OBJECTS)
$(CXX) $(LDFLAGS) --shared -fPIC \
-Wl,-soname,libolm_debug.so.$(MAJOR) \
-Wl,--version-script,version_script.ver \
$(OUTPUT_OPTION) $(DEBUG_OBJECTS)
ln -sf libolm_debug.so.$(VERSION) $(BUILD_DIR)/libolm_debug.so.$(MAJOR)
js: $(JS_TARGET)
.PHONY: js
@ -128,13 +145,32 @@ $(JS_EXPORTED_FUNCTIONS): $(PUBLIC_HEADERS)
perl -MJSON -ne '$$f{"_$$1"}=1 if /(olm_[^( ]*)\(/; END { @f=sort keys %f; print encode_json \@f }' $^ > $@.tmp
mv $@.tmp $@
all: test js lib debug
all: test js lib debug doc
.PHONY: all
install-debug: debug
test -d $(DESTDIR)$(PREFIX) || mkdir -p $(DESTDIR)$(PREFIX)
test -d $(DESTDIR)$(PREFIX)/lib || mkdir $(DESTDIR)$(PREFIX)/lib
install -Dm755 $(DEBUG_TARGET) $(DESTDIR)$(PREFIX)/lib/libolm_debug.so.$(VERSION)
ln -s libolm_debug.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm_debug.so.$(MAJOR)
ln -s libolm_debug.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm_debug.so
.PHONY: install-debug
install: lib
test -d $(DESTDIR)$(PREFIX) || mkdir -p $(DESTDIR)$(PREFIX)
test -d $(DESTDIR)$(PREFIX)/lib || mkdir $(DESTDIR)$(PREFIX)/lib
install -Dm755 $(RELEASE_TARGET) $(DESTDIR)$(PREFIX)/lib/libolm.so.$(VERSION)
ln -s libolm.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm.so.$(MAJOR)
ln -s libolm.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm.so
.PHONY: install
clean:;
rm -rf $(BUILD_DIR)
rm -rf $(BUILD_DIR) $(DOCS)
.PHONY: clean
doc: $(DOCS)
.PHONY: doc
### rules for building objects
$(BUILD_DIR)/release/%.o: %.c
mkdir -p $(dir $@)
@ -188,6 +224,9 @@ $(BUILD_DIR)/fuzzers/debug_%: fuzzers/fuzz_%.c $(DEBUG_OBJECTS)
$(BUILD_DIR)/fuzzers/debug_%: fuzzers/fuzz_%.cpp $(DEBUG_OBJECTS)
$(LINK.cc) $< $(DEBUG_OBJECTS) $(LOADLIBES) $(LDLIBS) -o $@
%.html: %.rst
rst2html $< $@
### dependencies
-include $(RELEASE_OBJECTS:.o=.d)

View file

@ -1,8 +1,9 @@
Olm
===
An implementation of the cryptographic ratchet described by
https://github.com/trevp/axolotl/wiki, written in C++11 and exposed as a C API
An implementation of the Double Ratchet cryptographic ratchet described by
https://github.com/trevp/double_ratchet/wiki, written in C and C++11 and
exposed as a C API.
The specification of the Olm ratchet can be found in docs/olm.rst or
https://matrix.org/docs/spec/olm.html
@ -27,15 +28,28 @@ To build the javascript bindings, install emscripten from http://kripken.github.
.. code:: bash
make js
npm pack javascript # packages olm.js into olm-x.y.z.tgz
Remember to make a tag after releasing a tarball:
Release process
---------------
.. code:: bash
git tag x.y.z
# Bump version numbers in ``Makefile`` and ``javascript/package.json``
# Prepare changelog
git commit
make clean
make test
make js
npm pack javascript
VERSION=x.y.z
scp olm-$VERSION.tgz packages@ldc-prd-matrix-001:/sites/matrix/packages/npm/olm/
git tag $VERSION -s
git push --tags
It's probably sensible to do the above on a release branch (``release-vx.y.z``
by convention), and merge back to master once complete.
Design
------

View file

@ -16,7 +16,7 @@
#define OLM_ACCOUNT_HH_
#include "olm/list.hh"
#include "olm/crypto.hh"
#include "olm/crypto.h"
#include "olm/error.h"
#include <cstdint>
@ -25,14 +25,14 @@ namespace olm {
struct IdentityKeys {
Ed25519KeyPair ed25519_key;
Curve25519KeyPair curve25519_key;
_olm_ed25519_key_pair ed25519_key;
_olm_curve25519_key_pair curve25519_key;
};
struct OneTimeKey {
std::uint32_t id;
bool published;
Curve25519KeyPair key;
_olm_curve25519_key_pair key;
};
@ -128,12 +128,12 @@ struct Account {
/** Lookup a one time key with the given public key */
OneTimeKey const * lookup_key(
Curve25519PublicKey const & public_key
_olm_curve25519_public_key const & public_key
);
/** Remove a one time key with the given public key */
std::size_t remove_key(
Curve25519PublicKey const & public_key
_olm_curve25519_public_key const & public_key
);
};

View file

@ -27,10 +27,100 @@
extern "C" {
#endif
const size_t SHA256_OUTPUT_LENGTH = 32;
/** length of a sha256 hash */
#define SHA256_OUTPUT_LENGTH 32
/** Computes SHA-256 of the input. The output buffer must be a least 32
* bytes long. */
/** 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 */
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 */
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.
*/
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. */
void _olm_crypto_sha256(
uint8_t const * input, size_t input_length,
uint8_t * output
@ -39,7 +129,7 @@ void _olm_crypto_sha256(
/** HMAC: Keyed-Hashing for Message Authentication
* http://tools.ietf.org/html/rfc2104
* Computes HMAC-SHA-256 of the input for the key. The output buffer must
* be at least 32 bytes long. */
* be at least SHA256_OUTPUT_LENGTH (32) bytes long. */
void _olm_crypto_hmac_sha256(
uint8_t const * key, size_t key_length,
uint8_t const * input, size_t input_length,
@ -58,6 +148,53 @@ void _olm_crypto_hkdf_sha256(
);
/** Generate a curve25519 key pair
* random_32_bytes should be CURVE25519_RANDOM_LENGTH (32) bytes long.
*/
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.
*/
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.
*/
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. */
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. */
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

View file

@ -1,154 +0,0 @@
/* Copyright 2015 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OLM_CRYPTO_HH_
#define OLM_CRYPTO_HH_
#include <cstdint>
#include <cstddef>
#include <string>
// eventually all of this needs to move into crypto.h, and everything should
// use that. For now, include crypto.h here.
#include "olm/crypto.h"
namespace olm {
static const std::size_t KEY_LENGTH = 32;
static const std::size_t SIGNATURE_LENGTH = 64;
static const std::size_t IV_LENGTH = 16;
struct Curve25519PublicKey {
std::uint8_t public_key[KEY_LENGTH];
std::string to_string() const;
};
struct Curve25519KeyPair : public Curve25519PublicKey {
std::uint8_t private_key[KEY_LENGTH];
};
struct Ed25519PublicKey {
std::uint8_t public_key[KEY_LENGTH];
};
struct Ed25519KeyPair : public Ed25519PublicKey {
std::uint8_t private_key[KEY_LENGTH];
};
/** Generate a curve25519 key pair from 32 random bytes. */
void curve25519_generate_key(
std::uint8_t const * random_32_bytes,
Curve25519KeyPair & key_pair
);
/** Create a shared secret using our private key and their public key.
* The output buffer must be at least 32 bytes long. */
void curve25519_shared_secret(
Curve25519KeyPair const & our_key,
Curve25519PublicKey const & their_key,
std::uint8_t * output
);
/** Signs the message using our private key.
* The output buffer must be at least 64 bytes long. */
void curve25519_sign(
Curve25519KeyPair const & our_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t * output
);
/** Verify their message using their public key.
* The signature input buffer must be 64 bytes long.
* Returns true if the signature is valid. */
bool curve25519_verify(
Curve25519PublicKey const & their_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t const * signature
);
/** Generate a curve25519 key pair from 32 random bytes. */
void ed25519_generate_key(
std::uint8_t const * random_32_bytes,
Ed25519KeyPair & key_pair
);
/** Signs the message using our private key.
* The output buffer must be at least 64 bytes long. */
void ed25519_sign(
Ed25519KeyPair const & our_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t * output
);
/** Verify their message using their public key.
* The signature input buffer must be 64 bytes long.
* Returns true if the signature is valid. */
bool ed25519_verify(
Ed25519PublicKey const & their_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t const * signature
);
struct Aes256Key {
std::uint8_t key[KEY_LENGTH];
};
struct Aes256Iv {
std::uint8_t iv[IV_LENGTH];
};
/** The length of output the aes_encrypt_cbc function will write */
std::size_t aes_encrypt_cbc_length(
std::size_t input_length
);
/** Encrypts the input using AES256 in CBC mode with PKCS#7 padding.
* The output buffer must be big enough to hold the output including padding */
void aes_encrypt_cbc(
Aes256Key const & key,
Aes256Iv const & iv,
std::uint8_t const * input, std::size_t input_length,
std::uint8_t * output
);
/** Decrypts the input using AES256 in CBC mode. The output buffer must be at
* least the same size as the input buffer. Returns the length of the plaintext
* without padding on success or std::size_t(-1) if the padding is invalid.
*/
std::size_t aes_decrypt_cbc(
Aes256Key const & key,
Aes256Iv const & iv,
std::uint8_t const * input, std::size_t input_length,
std::uint8_t * output
);
} // namespace olm
#endif /* OLM_CRYPTO_HH_ */

View file

@ -39,6 +39,18 @@ enum OlmErrorCode {
* 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,
/* remember to update the list of string constants in error.c when updating
* this list. */
};

View file

@ -95,9 +95,7 @@ size_t olm_unpickle_inbound_group_session(
*/
size_t olm_init_inbound_group_session(
OlmInboundGroupSession *session,
uint32_t message_index,
/* base64-encoded key */
/* base64-encoded keys */
uint8_t const * session_key, size_t session_key_length
);
@ -146,6 +144,27 @@ size_t olm_group_decrypt(
);
/**
* Get the number of bytes returned by olm_inbound_group_session_id()
*/
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.
*/
size_t olm_inbound_group_session_id(
OlmInboundGroupSession *session,
uint8_t * id, size_t id_length
);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -37,7 +37,8 @@ extern "C" {
size_t _olm_encode_group_message_length(
uint32_t chain_index,
size_t ciphertext_length,
size_t mac_length
size_t mac_length,
size_t signature_length
);
/**
@ -49,7 +50,8 @@ size_t _olm_encode_group_message_length(
* 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.
* should be written to, followed by the MAC and the
* signature.
*
* Returns the size of the message, up to the MAC.
*/
@ -76,7 +78,7 @@ struct _OlmDecodeGroupMessageResults {
*/
void _olm_decode_group_message(
const uint8_t *input, size_t input_length,
size_t mac_length,
size_t mac_length, size_t signature_length,
/* output structure: updated with results */
struct _OlmDecodeGroupMessageResults *results

View file

@ -33,6 +33,11 @@ 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.
*/
void olm_get_library_version(uint8_t *major, uint8_t *minor, uint8_t *patch);
/** The size of an account object in bytes */
size_t olm_account_size();
@ -295,6 +300,10 @@ size_t olm_session_id(
void * id, size_t id_length
);
int olm_session_has_received_message(
OlmSession *session
);
/** Checks if the PRE_KEY message is for this in-bound session. This can happen
* if multiple messages are sent to this account before this account sends a
* message in reply. Returns olm_error() on failure. If the base64

View file

@ -160,7 +160,7 @@ size_t olm_outbound_group_session_key_length(
/**
* Get the base64-encoded current ratchet key for this session.
*
* Each message is sent with a diffent ratchet key. This function returns the
* 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

View file

@ -21,6 +21,10 @@
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(
@ -43,6 +47,42 @@ 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. */
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. */
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

View file

@ -16,7 +16,7 @@
#define OLM_PICKLE_HH_
#include "olm/list.hh"
#include "olm/crypto.hh"
#include "olm/crypto.h"
#include <cstring>
#include <cstdint>
@ -109,70 +109,36 @@ std::uint8_t const * unpickle_bytes(
std::size_t pickle_length(
const Curve25519PublicKey & value
const _olm_curve25519_public_key & value
);
std::uint8_t * pickle(
std::uint8_t * pos,
const Curve25519PublicKey & value
const _olm_curve25519_public_key & value
);
std::uint8_t const * unpickle(
std::uint8_t const * pos, std::uint8_t const * end,
Curve25519PublicKey & value
_olm_curve25519_public_key & value
);
std::size_t pickle_length(
const Curve25519KeyPair & value
const _olm_curve25519_key_pair & value
);
std::uint8_t * pickle(
std::uint8_t * pos,
const Curve25519KeyPair & value
const _olm_curve25519_key_pair & value
);
std::uint8_t const * unpickle(
std::uint8_t const * pos, std::uint8_t const * end,
Curve25519KeyPair & value
);
std::size_t pickle_length(
const Ed25519PublicKey & value
);
std::uint8_t * pickle(
std::uint8_t * pos,
const Ed25519PublicKey & value
);
std::uint8_t const * unpickle(
std::uint8_t const * pos, std::uint8_t const * end,
Ed25519PublicKey & value
);
std::size_t pickle_length(
const Ed25519KeyPair & value
);
std::uint8_t * pickle(
std::uint8_t * pos,
const Ed25519KeyPair & value
);
std::uint8_t const * unpickle(
std::uint8_t const * pos, std::uint8_t const * end,
Ed25519KeyPair & value
_olm_curve25519_key_pair & value
);
} // namespace olm

View file

@ -13,7 +13,9 @@
* limitations under the License.
*/
#include "olm/crypto.hh"
#include <cstdint>
#include "olm/crypto.h"
#include "olm/list.hh"
#include "olm/error.h"
@ -21,8 +23,13 @@ struct _olm_cipher;
namespace olm {
typedef std::uint8_t SharedKey[olm::KEY_LENGTH];
/** length of a shared key: the root key R(i), chain key C(i,j), and message key
* M(i,j)). They are all only used to stuff into HMACs, so could be any length
* for that. The chain key and message key are both derived from SHA256
* operations, so their length is determined by that. */
const std::size_t OLM_SHARED_KEY_LENGTH = SHA256_OUTPUT_LENGTH;
typedef std::uint8_t SharedKey[OLM_SHARED_KEY_LENGTH];
struct ChainKey {
std::uint32_t index;
@ -36,19 +43,19 @@ struct MessageKey {
struct SenderChain {
Curve25519KeyPair ratchet_key;
_olm_curve25519_key_pair ratchet_key;
ChainKey chain_key;
};
struct ReceiverChain {
Curve25519PublicKey ratchet_key;
_olm_curve25519_public_key ratchet_key;
ChainKey chain_key;
};
struct SkippedMessageKey {
Curve25519PublicKey ratchet_key;
_olm_curve25519_public_key ratchet_key;
MessageKey message_key;
};
@ -113,14 +120,14 @@ struct Ratchet {
* remote's first ratchet key */
void initialise_as_bob(
std::uint8_t const * shared_secret, std::size_t shared_secret_length,
Curve25519PublicKey const & their_ratchet_key
_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,
Curve25519KeyPair const & our_ratchet_key
_olm_curve25519_key_pair const & our_ratchet_key
);
/** The number of bytes of output the encrypt method will write for

View file

@ -35,9 +35,9 @@ struct Session {
bool received_message;
Curve25519PublicKey alice_identity_key;
Curve25519PublicKey alice_base_key;
Curve25519PublicKey bob_one_time_key;
_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. */
@ -48,8 +48,8 @@ struct Session {
* NOT_ENOUGH_RANDOM if the number of random bytes was too small. */
std::size_t new_outbound_session(
Account const & local_account,
Curve25519PublicKey const & identity_key,
Curve25519PublicKey const & one_time_key,
_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
);
@ -59,7 +59,7 @@ struct Session {
* the message headers could not be decoded. */
std::size_t new_inbound_session(
Account & local_account,
Curve25519PublicKey const * their_identity_key,
_olm_curve25519_public_key const * their_identity_key,
std::uint8_t const * pre_key_message, std::size_t message_length
);
@ -82,7 +82,7 @@ struct Session {
* session does not match or the pre-key message could not be decoded.
*/
bool matches_inbound_session(
Curve25519PublicKey const * their_identity_key,
_olm_curve25519_public_key const * their_identity_key,
std::uint8_t const * pre_key_message, std::size_t message_length
);

View file

@ -21,9 +21,9 @@
#include <cstddef>
#include <cstdint>
namespace olm {
struct _olm_ed25519_public_key;
struct Ed25519PublicKey;
namespace olm {
struct Utility {
@ -48,7 +48,7 @@ struct Utility {
* last_error will be set with an error code. If the signature was too short
* or was not a valid signature then last_error will be BAD_MESSAGE_MAC. */
std::size_t ed25519_verify(
Ed25519PublicKey const & key,
_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
);

View file

@ -261,7 +261,7 @@ DemoUser.prototype.receiveOneToOne = function(jsonpacket) {
if (!self.peerGroupSessions[sender] ||
!self.peerGroupSessions[sender][body.session_id]) {
self.createInboundSession(
sender, body.session_id, body.message_index, body.session_key
sender, body.session_id, body.session_key
);
}
});
@ -337,15 +337,18 @@ DemoUser.prototype.getGroupSession = function() {
* add a task to create an inbound group session
*/
DemoUser.prototype.createInboundSession = function(
peer_id, session_id, message_index, session_key, callback
peer_id, session_id, session_key, callback
) {
var self = this;
this.addTask("init inbound session", function(done) {
session = new Olm.InboundGroupSession();
session.create(message_index, session_key);
session.create(session_key);
if (!self.peerGroupSessions[peer_id]) {
self.peerGroupSessions[peer_id] = {};
}
if (session_id != session.session_id()) {
throw new Error("Mismatched session_ids");
}
self.peerGroupSessions[peer_id][session_id] = session;
done(session);
}, callback);

View file

@ -1,3 +1,9 @@
/* The 'length' argument to Pointer_stringify doesn't work if the input includes
* characters >= 128; we therefore need to add a NULL character to all of our
* strings. This acts as a symbolic constant to help show what we're doing.
*/
var NULL_BYTE_PADDING_LENGTH = 1;
function InboundGroupSession() {
var size = Module['_olm_inbound_group_session_size']();
this.buf = malloc(size);
@ -28,11 +34,11 @@ InboundGroupSession.prototype['pickle'] = restore_stack(function(key) {
Module['_olm_pickle_inbound_group_session_length']
)(this.ptr);
var key_buffer = stack(key_array);
var pickle_buffer = stack(pickle_length);
var pickle_buffer = stack(pickle_length + NULL_BYTE_PADDING_LENGTH);
inbound_group_session_method(Module['_olm_pickle_inbound_group_session'])(
this.ptr, key_buffer, key_array.length, pickle_buffer, pickle_length
);
return Pointer_stringify(pickle_buffer, pickle_length);
return Pointer_stringify(pickle_buffer);
});
InboundGroupSession.prototype['unpickle'] = restore_stack(function(key, pickle) {
@ -46,12 +52,12 @@ InboundGroupSession.prototype['unpickle'] = restore_stack(function(key, pickle)
);
});
InboundGroupSession.prototype['create'] = restore_stack(function(message_index, session_key) {
InboundGroupSession.prototype['create'] = restore_stack(function(session_key) {
var key_array = array_from_string(session_key);
var key_buffer = stack(key_array);
inbound_group_session_method(Module['_olm_init_inbound_group_session'])(
this.ptr, message_index, key_buffer, key_array.length
this.ptr, key_buffer, key_array.length
);
});
@ -60,19 +66,38 @@ InboundGroupSession.prototype['decrypt'] = restore_stack(function(
) {
var message_array = array_from_string(message);
var message_buffer = stack(message_array);
var max_plaintext_length = session_method(
var max_plaintext_length = inbound_group_session_method(
Module['_olm_group_decrypt_max_plaintext_length']
)(this.ptr, message_buffer, message_array.length);
// caculating the length destroys the input buffer.
// So we copy the array to a new buffer
var message_buffer = stack(message_array);
var plaintext_buffer = stack(max_plaintext_length);
var plaintext_length = session_method(Module["_olm_group_decrypt"])(
var plaintext_buffer = stack(max_plaintext_length + NULL_BYTE_PADDING_LENGTH);
var plaintext_length = inbound_group_session_method(Module["_olm_group_decrypt"])(
this.ptr,
message_buffer, message_array.length,
plaintext_buffer, max_plaintext_length
);
return Pointer_stringify(plaintext_buffer, plaintext_length);
// Pointer_stringify requires a null-terminated argument (the optional
// 'len' argument doesn't work for UTF-8 data).
Module['setValue'](
plaintext_buffer+plaintext_length,
0, "i8"
);
return Pointer_stringify(plaintext_buffer);
});
InboundGroupSession.prototype['session_id'] = restore_stack(function() {
var length = inbound_group_session_method(
Module['_olm_inbound_group_session_id_length']
)(this.ptr);
var session_id = stack(length + NULL_BYTE_PADDING_LENGTH);
inbound_group_session_method(Module['_olm_inbound_group_session_id'])(
this.ptr, session_id, length
);
return Pointer_stringify(session_id);
});
olm_exports['InboundGroupSession'] = InboundGroupSession;

View file

@ -1,3 +1,9 @@
/* The 'length' argument to Pointer_stringify doesn't work if the input includes
* characters >= 128; we therefore need to add a NULL character to all of our
* strings. This acts as a symbolic constant to help show what we're doing.
*/
var NULL_BYTE_PADDING_LENGTH = 1;
function OutboundGroupSession() {
var size = Module['_olm_outbound_group_session_size']();
@ -29,11 +35,11 @@ OutboundGroupSession.prototype['pickle'] = restore_stack(function(key) {
Module['_olm_pickle_outbound_group_session_length']
)(this.ptr);
var key_buffer = stack(key_array);
var pickle_buffer = stack(pickle_length);
var pickle_buffer = stack(pickle_length + NULL_BYTE_PADDING_LENGTH);
outbound_group_session_method(Module['_olm_pickle_outbound_group_session'])(
this.ptr, key_buffer, key_array.length, pickle_buffer, pickle_length
);
return Pointer_stringify(pickle_buffer, pickle_length);
return Pointer_stringify(pickle_buffer);
});
OutboundGroupSession.prototype['unpickle'] = restore_stack(function(key, pickle) {
@ -47,8 +53,8 @@ OutboundGroupSession.prototype['unpickle'] = restore_stack(function(key, pickle)
);
});
OutboundGroupSession.prototype['create'] = restore_stack(function(key) {
var random_length = session_method(
OutboundGroupSession.prototype['create'] = restore_stack(function() {
var random_length = outbound_group_session_method(
Module['_olm_init_outbound_group_session_random_length']
)(this.ptr);
var random = random_stack(random_length);
@ -63,35 +69,35 @@ OutboundGroupSession.prototype['encrypt'] = restore_stack(function(plaintext) {
Module['_olm_group_encrypt_message_length']
)(this.ptr, plaintext_array.length);
var plaintext_buffer = stack(plaintext_array);
var message_buffer = stack(message_length);
var message_buffer = stack(message_length + NULL_BYTE_PADDING_LENGTH);
outbound_group_session_method(Module['_olm_group_encrypt'])(
this.ptr,
plaintext_buffer, plaintext_array.length,
message_buffer, message_length
);
return Pointer_stringify(message_buffer, message_length);
return Pointer_stringify(message_buffer);
});
OutboundGroupSession.prototype['session_id'] = restore_stack(function(key) {
OutboundGroupSession.prototype['session_id'] = restore_stack(function() {
var length = outbound_group_session_method(
Module['_olm_outbound_group_session_id_length']
)(this.ptr);
var session_id = stack(length);
var session_id = stack(length + NULL_BYTE_PADDING_LENGTH);
outbound_group_session_method(Module['_olm_outbound_group_session_id'])(
this.ptr, session_id, length
);
return Pointer_stringify(session_id, length);
return Pointer_stringify(session_id);
});
OutboundGroupSession.prototype['session_key'] = restore_stack(function(key) {
OutboundGroupSession.prototype['session_key'] = restore_stack(function() {
var key_length = outbound_group_session_method(
Module['_olm_outbound_group_session_key_length']
)(this.ptr);
var key = stack(key_length);
var key = stack(key_length + NULL_BYTE_PADDING_LENGTH);
outbound_group_session_method(Module['_olm_outbound_group_session_key'])(
this.ptr, key, key_length
);
return Pointer_stringify(key, key_length);
return Pointer_stringify(key);
});
OutboundGroupSession.prototype['message_index'] = function() {

View file

@ -4,6 +4,16 @@ var free = Module['_free'];
var Pointer_stringify = Module['Pointer_stringify'];
var OLM_ERROR = Module['_olm_error']();
/* The 'length' argument to Pointer_stringify doesn't work if the input includes
* characters >= 128; we therefore need to add a NULL character to all of our
* strings. This acts as a symbolic constant to help show what we're doing.
*/
var NULL_BYTE_PADDING_LENGTH = 1;
/* allocate a number of bytes of storage on the stack.
*
* If size_or_array is a Number, allocates that number of zero-initialised bytes.
*/
function stack(size_or_array) {
return Module['allocate'](size_or_array, 'i8', Module['ALLOC_STACK']);
}
@ -68,11 +78,11 @@ Account.prototype['identity_keys'] = restore_stack(function() {
var keys_length = account_method(
Module['_olm_account_identity_keys_length']
)(this.ptr);
var keys = stack(keys_length);
var keys = stack(keys_length + NULL_BYTE_PADDING_LENGTH);
account_method(Module['_olm_account_identity_keys'])(
this.ptr, keys, keys_length
);
return Pointer_stringify(keys, keys_length);
return Pointer_stringify(keys);
});
Account.prototype['sign'] = restore_stack(function(message) {
@ -81,24 +91,24 @@ Account.prototype['sign'] = restore_stack(function(message) {
)(this.ptr);
var message_array = array_from_string(message);
var message_buffer = stack(message_array);
var signature_buffer = stack(signature_length);
var signature_buffer = stack(signature_length + NULL_BYTE_PADDING_LENGTH);
account_method(Module['_olm_account_sign'])(
this.ptr,
message_buffer, message_array.length,
signature_buffer, signature_length
);
return Pointer_stringify(signature_buffer, signature_length);
return Pointer_stringify(signature_buffer);
});
Account.prototype['one_time_keys'] = restore_stack(function() {
var keys_length = account_method(
Module['_olm_account_one_time_keys_length']
)(this.ptr);
var keys = stack(keys_length);
var keys = stack(keys_length + NULL_BYTE_PADDING_LENGTH);
account_method(Module['_olm_account_one_time_keys'])(
this.ptr, keys, keys_length
);
return Pointer_stringify(keys, keys_length);
return Pointer_stringify(keys);
});
Account.prototype['mark_keys_as_published'] = restore_stack(function() {
@ -135,11 +145,11 @@ Account.prototype['pickle'] = restore_stack(function(key) {
Module['_olm_pickle_account_length']
)(this.ptr);
var key_buffer = stack(key_array);
var pickle_buffer = stack(pickle_length);
var pickle_buffer = stack(pickle_length + NULL_BYTE_PADDING_LENGTH);
account_method(Module['_olm_pickle_account'])(
this.ptr, key_buffer, key_array.length, pickle_buffer, pickle_length
);
return Pointer_stringify(pickle_buffer, pickle_length);
return Pointer_stringify(pickle_buffer);
});
Account.prototype['unpickle'] = restore_stack(function(key, pickle) {
@ -183,11 +193,11 @@ Session.prototype['pickle'] = restore_stack(function(key) {
Module['_olm_pickle_session_length']
)(this.ptr);
var key_buffer = stack(key_array);
var pickle_buffer = stack(pickle_length);
var pickle_buffer = stack(pickle_length + NULL_BYTE_PADDING_LENGTH);
session_method(Module['_olm_pickle_session'])(
this.ptr, key_buffer, key_array.length, pickle_buffer, pickle_length
);
return Pointer_stringify(pickle_buffer, pickle_length);
return Pointer_stringify(pickle_buffer);
});
Session.prototype['unpickle'] = restore_stack(function(key, pickle) {
@ -246,13 +256,20 @@ Session.prototype['create_inbound_from'] = restore_stack(function(
Session.prototype['session_id'] = restore_stack(function() {
var id_length = session_method(Module['_olm_session_id_length'])(this.ptr);
var id_buffer = stack(id_length);
var id_buffer = stack(id_length + NULL_BYTE_PADDING_LENGTH);
session_method(Module['_olm_session_id'])(
this.ptr, id_buffer, id_length
);
return Pointer_stringify(id_buffer, id_length);
return Pointer_stringify(id_buffer);
});
Session.prototype['has_received_message'] = function() {
return session_method(Module['_olm_session_has_received_message'])(
this.ptr
) ? true : false;
};
Session.prototype['matches_inbound'] = restore_stack(function(
one_time_key_message
) {
@ -292,7 +309,7 @@ Session.prototype['encrypt'] = restore_stack(function(
)(this.ptr, plaintext_array.length);
var random = random_stack(random_length);
var plaintext_buffer = stack(plaintext_array);
var message_buffer = stack(message_length);
var message_buffer = stack(message_length + NULL_BYTE_PADDING_LENGTH);
session_method(Module['_olm_encrypt'])(
this.ptr,
plaintext_buffer, plaintext_array.length,
@ -301,7 +318,7 @@ Session.prototype['encrypt'] = restore_stack(function(
);
return {
"type": message_type,
"body": Pointer_stringify(message_buffer, message_length)
"body": Pointer_stringify(message_buffer)
};
});
@ -316,13 +333,23 @@ Session.prototype['decrypt'] = restore_stack(function(
// caculating the length destroys the input buffer.
// So we copy the array to a new buffer
var message_buffer = stack(message_array);
var plaintext_buffer = stack(max_plaintext_length);
var plaintext_buffer = stack(
max_plaintext_length + NULL_BYTE_PADDING_LENGTH
);
var plaintext_length = session_method(Module["_olm_decrypt"])(
this.ptr, message_type,
message_buffer, message.length,
plaintext_buffer, max_plaintext_length
);
return Pointer_stringify(plaintext_buffer, plaintext_length);
// Pointer_stringify requires a null-terminated argument (the optional
// 'len' argument doesn't work for UTF-8 data).
Module['setValue'](
plaintext_buffer+plaintext_length,
0, "i8"
);
return Pointer_stringify(plaintext_buffer);
});
function Utility() {
@ -353,13 +380,13 @@ Utility.prototype['sha256'] = restore_stack(function(input) {
var output_length = utility_method(Module['_olm_sha256_length'])(this.ptr);
var input_array = array_from_string(input);
var input_buffer = stack(input_array);
var output_buffer = stack(output_length);
var output_buffer = stack(output_length + NULL_BYTE_PADDING_LENGTH);
utility_method(Module['_olm_sha2516'])(
this.ptr,
input_buffer, input_array.length(),
output_buffer, output_length
);
return Pointer_stringify(output_buffer, output_length);
return Pointer_stringify(output_buffer);
});
Utility.prototype['ed25519_verify'] = restore_stack(function(
@ -384,4 +411,14 @@ olm_exports["Session"] = Session;
olm_exports["Utility"] = Utility;
olm_exports['set_log_level'] = Module['_olm_set_log_level'];
olm_exports["get_library_version"] = restore_stack(function() {
var buf = stack(3);
Module['_olm_get_library_version'](buf, buf+1, buf+2);
return [
getValue(buf, 'i8'),
getValue(buf+1, 'i8'),
getValue(buf+2, 'i8'),
];
});
}();

View file

@ -1,7 +1,7 @@
{
"name": "olm",
"version": "0.1.0",
"description": "An implementation of a well known cryptographic ratchet",
"version": "1.3.0",
"description": "An implementation of the Double Ratchet cryptographic ratchet",
"main": "olm.js",
"files": [
"olm.js",

View file

@ -3,7 +3,12 @@
set -e
make clean
rm olm-*.tgz
make lib
make test
./python/test_olm.sh
. ~/.emsdk_set_env.sh
make js
npm pack javascript

View file

@ -1,43 +0,0 @@
void convert_curve25519_to_ed25519(
unsigned char * public_key,
unsigned char * signature
) {
fe mont_x, mont_x_minus_one, mont_x_plus_one, inv_mont_x_plus_one;
fe one;
fe ed_y;
fe_frombytes(mont_x, public_key);
fe_1(one);
fe_sub(mont_x_minus_one, mont_x, one);
fe_add(mont_x_plus_one, mont_x, one);
fe_invert(inv_mont_x_plus_one, mont_x_plus_one);
fe_mul(ed_y, mont_x_minus_one, inv_mont_x_plus_one);
fe_tobytes(public_key, ed_y);
public_key[31] &= 0x7F;
public_key[31] |= (signature[63] & 0x80);
signature[63] &= 0x7F;
}
void convert_ed25519_to_curve25519(
unsigned char const * public_key,
unsigned char * signature
) {
unsigned char sign_bit = public_key[31] & 0x80;
signature[63] &= 0x7F;
signature[63] |= sign_bit;
}
void ed25519_keypair(
unsigned char * private_key,
unsigned char * public_key
) {
ge_p3 A;
private_key[0] &= 248;
private_key[31] &= 63;
private_key[31] |= 64;
ge_scalarmult_base(&A, private_key);
ge_p3_tobytes(public_key, &A);
}

View file

@ -1,24 +0,0 @@
#ifndef ED25519_ADDITIONS_H
#define ED25519_ADDITIONS_H
#ifdef __cplusplus
extern "C" {
#endif
void convert_curve25519_to_ed25519(
unsigned char * public_key,
unsigned char * signature);
void convert_ed25519_to_curve25519(
unsigned char const * public_key,
unsigned char * signature);
void ed25519_keypair(
unsigned char * private_key,
unsigned char * public_key);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -7,7 +7,7 @@ def read_random(n):
return f.read(n)
lib = cdll.LoadLibrary(os.path.join(
os.path.dirname(__file__), "..", "..", "build", "libolm.so")
os.path.dirname(__file__), "..", "..", "build", "libolm.so.1")
)
lib.olm_error.argtypes = []

View file

@ -33,7 +33,7 @@ inbound_group_session_function(
)
inbound_group_session_function(
lib.olm_init_inbound_group_session, c_uint32, c_void_p, c_size_t
lib.olm_init_inbound_group_session, c_void_p, c_size_t
)
inbound_group_session_function(
@ -45,6 +45,9 @@ inbound_group_session_function(
c_void_p, c_size_t, # plaintext
)
inbound_group_session_function(lib.olm_inbound_group_session_id_length)
inbound_group_session_function(lib.olm_inbound_group_session_id, c_void_p, c_size_t)
class InboundGroupSession(object):
def __init__(self):
self.buf = create_string_buffer(lib.olm_inbound_group_session_size())
@ -66,10 +69,10 @@ class InboundGroupSession(object):
self.ptr, key_buffer, len(key), pickle_buffer, len(pickle)
)
def init(self, message_index, session_key):
def init(self, session_key):
key_buffer = create_string_buffer(session_key)
lib.olm_init_inbound_group_session(
self.ptr, message_index, key_buffer, len(session_key)
self.ptr, key_buffer, len(session_key)
)
def decrypt(self, message):
@ -84,3 +87,9 @@ class InboundGroupSession(object):
plaintext_buffer, max_plaintext_length
)
return plaintext_buffer.raw[:plaintext_length]
def session_id(self):
id_length = lib.olm_inbound_group_session_id_length(self.ptr)
id_buffer = create_string_buffer(id_length)
lib.olm_inbound_group_session_id(self.ptr, id_buffer, id_length);
return id_buffer.raw

View file

@ -15,6 +15,7 @@
#include "olm/account.hh"
#include "olm/base64.hh"
#include "olm/logging.h"
#include "olm/pickle.h"
#include "olm/pickle.hh"
#include "olm/memory.hh"
@ -27,10 +28,10 @@ olm::Account::Account(
olm::OneTimeKey const * olm::Account::lookup_key(
olm::Curve25519PublicKey const & public_key
_olm_curve25519_public_key const & public_key
) {
for (olm::OneTimeKey const & key : one_time_keys) {
if (olm::array_equal(key.key.public_key, public_key.public_key)) {
if (olm::array_equal(key.key.public_key.public_key, public_key.public_key)) {
return &key;
}
}
@ -38,11 +39,11 @@ olm::OneTimeKey const * olm::Account::lookup_key(
}
std::size_t olm::Account::remove_key(
olm::Curve25519PublicKey const & public_key
_olm_curve25519_public_key const & public_key
) {
OneTimeKey * i;
for (i = one_time_keys.begin(); i != one_time_keys.end(); ++i) {
if (olm::array_equal(i->key.public_key, public_key.public_key)) {
if (olm::array_equal(i->key.public_key.public_key, public_key.public_key)) {
std::uint32_t id = i->id;
one_time_keys.erase(i);
olm_logf(OLM_LOG_INFO, LOG_CATEGORY, "removed key id %i", id);
@ -54,7 +55,7 @@ std::size_t olm::Account::remove_key(
}
std::size_t olm::Account::new_account_random_length() {
return 2 * olm::KEY_LENGTH;
return ED25519_RANDOM_LENGTH + CURVE25519_RANDOM_LENGTH;
}
std::size_t olm::Account::new_account(
@ -65,9 +66,9 @@ std::size_t olm::Account::new_account(
return std::size_t(-1);
}
olm::ed25519_generate_key(random, identity_keys.ed25519_key);
random += KEY_LENGTH;
olm::curve25519_generate_key(random, identity_keys.curve25519_key);
_olm_crypto_ed25519_generate_key(random, &identity_keys.ed25519_key);
random += ED25519_RANDOM_LENGTH;
_olm_crypto_curve25519_generate_key(random, &identity_keys.curve25519_key);
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY, "Created new account");
@ -125,16 +126,16 @@ std::size_t olm::Account::get_identity_json(
pos = write_string(pos, KEY_JSON_CURVE25519);
*(pos++) = '\"';
pos = olm::encode_base64(
identity_keys.curve25519_key.public_key,
sizeof(identity_keys.curve25519_key.public_key),
identity_keys.curve25519_key.public_key.public_key,
sizeof(identity_keys.curve25519_key.public_key.public_key),
pos
);
*(pos++) = '\"'; *(pos++) = ',';
pos = write_string(pos, KEY_JSON_ED25519);
*(pos++) = '\"';
pos = olm::encode_base64(
identity_keys.ed25519_key.public_key,
sizeof(identity_keys.ed25519_key.public_key),
identity_keys.ed25519_key.public_key.public_key,
sizeof(identity_keys.ed25519_key.public_key.public_key),
pos
);
*(pos++) = '\"'; *(pos++) = '}';
@ -144,7 +145,7 @@ std::size_t olm::Account::get_identity_json(
std::size_t olm::Account::signature_length(
) {
return olm::SIGNATURE_LENGTH;
return ED25519_SIGNATURE_LENGTH;
}
@ -156,8 +157,8 @@ std::size_t olm::Account::sign(
last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
return std::size_t(-1);
}
olm::ed25519_sign(
identity_keys.ed25519_key, message, message_length, signature
_olm_crypto_ed25519_sign(
&identity_keys.ed25519_key, message, message_length, signature
);
return this->signature_length();
}
@ -209,7 +210,7 @@ std::size_t olm::Account::get_one_time_keys_json(
pos = olm::encode_base64(key_id, sizeof(key_id), pos);
*(pos++) = '\"'; *(pos++) = ':'; *(pos++) = '\"';
pos = olm::encode_base64(
key.key.public_key, sizeof(key.key.public_key), pos
key.key.public_key.public_key, sizeof(key.key.public_key.public_key), pos
);
*(pos++) = '\"';
sep = ',';
@ -245,7 +246,7 @@ std::size_t olm::Account::max_number_of_one_time_keys(
std::size_t olm::Account::generate_one_time_keys_random_length(
std::size_t number_of_keys
) {
return olm::KEY_LENGTH * number_of_keys;
return CURVE25519_RANDOM_LENGTH * number_of_keys;
}
std::size_t olm::Account::generate_one_time_keys(
@ -260,8 +261,8 @@ std::size_t olm::Account::generate_one_time_keys(
OneTimeKey & key = *one_time_keys.insert(one_time_keys.begin());
key.id = ++next_one_time_key_id;
key.published = false;
olm::curve25519_generate_key(random, key.key);
random += olm::KEY_LENGTH;
_olm_crypto_curve25519_generate_key(random, &key.key);
random += CURVE25519_RANDOM_LENGTH;
}
return number_of_keys;
}
@ -272,7 +273,7 @@ static std::size_t pickle_length(
olm::IdentityKeys const & value
) {
size_t length = 0;
length += olm::pickle_length(value.ed25519_key);
length += _olm_pickle_ed25519_key_pair_length(&value.ed25519_key);
length += olm::pickle_length(value.curve25519_key);
return length;
}
@ -282,7 +283,7 @@ static std::uint8_t * pickle(
std::uint8_t * pos,
olm::IdentityKeys const & value
) {
pos = olm::pickle(pos, value.ed25519_key);
pos = _olm_pickle_ed25519_key_pair(pos, &value.ed25519_key);
pos = olm::pickle(pos, value.curve25519_key);
return pos;
}
@ -292,7 +293,7 @@ static std::uint8_t const * unpickle(
std::uint8_t const * pos, std::uint8_t const * end,
olm::IdentityKeys & value
) {
pos = olm::unpickle(pos, end, value.ed25519_key);
pos = _olm_unpickle_ed25519_key_pair(pos, end, &value.ed25519_key);
pos = olm::unpickle(pos, end, value.curve25519_key);
return pos;
}
@ -333,7 +334,9 @@ static std::uint8_t const * unpickle(
} // namespace olm
namespace {
static const std::uint32_t ACCOUNT_PICKLE_VERSION = 1;
// pickle version 1 used only 32 bytes for the ed25519 private key.
// Any keys thus used should be considered compromised.
static const std::uint32_t ACCOUNT_PICKLE_VERSION = 2;
}
@ -367,9 +370,15 @@ std::uint8_t const * olm::unpickle(
) {
uint32_t pickle_version;
pos = olm::unpickle(pos, end, pickle_version);
if (pickle_version != ACCOUNT_PICKLE_VERSION) {
value.last_error = OlmErrorCode::OLM_UNKNOWN_PICKLE_VERSION;
return end;
switch (pickle_version) {
case ACCOUNT_PICKLE_VERSION:
break;
case 1:
value.last_error = OlmErrorCode::OLM_BAD_LEGACY_ACCOUNT_PICKLE;
return end;
default:
value.last_error = OlmErrorCode::OLM_UNKNOWN_PICKLE_VERSION;
return end;
}
pos = olm::unpickle(pos, end, value.identity_keys);
pos = olm::unpickle(pos, end, value.one_time_keys);

View file

@ -13,16 +13,18 @@
* limitations under the License.
*/
#include "olm/cipher.h"
#include "olm/crypto.hh"
#include "olm/crypto.h"
#include "olm/memory.hh"
#include <cstring>
const std::size_t HMAC_KEY_LENGTH = 32;
namespace {
struct DerivedKeys {
olm::Aes256Key aes_key;
std::uint8_t mac_key[olm::KEY_LENGTH];
olm::Aes256Iv aes_iv;
_olm_aes256_key aes_key;
std::uint8_t mac_key[HMAC_KEY_LENGTH];
_olm_aes256_iv aes_iv;
};
@ -31,7 +33,9 @@ static void derive_keys(
std::uint8_t const * key, std::size_t key_length,
DerivedKeys & keys
) {
std::uint8_t derived_secrets[2 * olm::KEY_LENGTH + olm::IV_LENGTH];
std::uint8_t derived_secrets[
AES256_KEY_LENGTH + HMAC_KEY_LENGTH + AES256_IV_LENGTH
];
_olm_crypto_hkdf_sha256(
key, key_length,
nullptr, 0,
@ -54,7 +58,7 @@ size_t aes_sha_256_cipher_mac_length(const struct _olm_cipher *cipher) {
size_t aes_sha_256_cipher_encrypt_ciphertext_length(
const struct _olm_cipher *cipher, size_t plaintext_length
) {
return olm::aes_encrypt_cbc_length(plaintext_length);
return _olm_crypto_aes_encrypt_cbc_length(plaintext_length);
}
size_t aes_sha_256_cipher_encrypt(
@ -76,12 +80,12 @@ size_t aes_sha_256_cipher_encrypt(
derive_keys(c->kdf_info, c->kdf_info_length, key, key_length, keys);
olm::aes_encrypt_cbc(
keys.aes_key, keys.aes_iv, plaintext, plaintext_length, ciphertext
_olm_crypto_aes_encrypt_cbc(
&keys.aes_key, &keys.aes_iv, plaintext, plaintext_length, ciphertext
);
_olm_crypto_hmac_sha256(
keys.mac_key, olm::KEY_LENGTH, output, output_length - MAC_LENGTH, mac
keys.mac_key, HMAC_KEY_LENGTH, output, output_length - MAC_LENGTH, mac
);
std::memcpy(output + output_length - MAC_LENGTH, mac, MAC_LENGTH);
@ -113,7 +117,7 @@ size_t aes_sha_256_cipher_decrypt(
derive_keys(c->kdf_info, c->kdf_info_length, key, key_length, keys);
_olm_crypto_hmac_sha256(
keys.mac_key, olm::KEY_LENGTH, input, input_length - MAC_LENGTH, mac
keys.mac_key, HMAC_KEY_LENGTH, input, input_length - MAC_LENGTH, mac
);
std::uint8_t const * input_mac = input + input_length - MAC_LENGTH;
@ -122,8 +126,8 @@ size_t aes_sha_256_cipher_decrypt(
return std::size_t(-1);
}
std::size_t plaintext_length = olm::aes_decrypt_cbc(
keys.aes_key, keys.aes_iv, ciphertext, ciphertext_length, plaintext
std::size_t plaintext_length = _olm_crypto_aes_decrypt_cbc(
&keys.aes_key, &keys.aes_iv, ciphertext, ciphertext_length, plaintext
);
olm::unset(keys);

View file

@ -12,7 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "olm/crypto.hh"
#include "olm/crypto.h"
#include "olm/memory.hh"
#include <cstring>
@ -25,14 +25,13 @@ extern "C" {
}
#include "ed25519/src/ed25519.h"
#include "ed25519_additions.h"
#include "curve25519-donna.h"
namespace {
static const std::uint8_t CURVE25519_BASEPOINT[32] = {9};
static const std::size_t AES_KEY_SCHEDULE_LENGTH = 60;
static const std::size_t AES_KEY_BITS = 8 * olm::KEY_LENGTH;
static const std::size_t AES_KEY_BITS = 8 * AES256_KEY_LENGTH;
static const std::size_t AES_BLOCK_LENGTH = 16;
static const std::size_t SHA256_BLOCK_LENGTH = 64;
static const std::uint8_t HKDF_DEFAULT_SALT[32] = {};
@ -101,119 +100,86 @@ inline static void hmac_sha256_final(
} // namespace
std::string olm::Curve25519PublicKey::to_string() const {
return olm::bytes_to_string(std::begin(public_key),
std::end(public_key));
};
void olm::curve25519_generate_key(
std::uint8_t const * random_32_bytes,
olm::Curve25519KeyPair & key_pair
void _olm_crypto_curve25519_generate_key(
uint8_t const * random_32_bytes,
struct _olm_curve25519_key_pair *key_pair
) {
std::memcpy(key_pair.private_key, random_32_bytes, KEY_LENGTH);
std::memcpy(
key_pair->private_key.private_key, random_32_bytes,
CURVE25519_KEY_LENGTH
);
::curve25519_donna(
key_pair.public_key, key_pair.private_key, CURVE25519_BASEPOINT
key_pair->public_key.public_key,
key_pair->private_key.private_key,
CURVE25519_BASEPOINT
);
}
void olm::curve25519_shared_secret(
olm::Curve25519KeyPair const & our_key,
olm::Curve25519PublicKey const & their_key,
void _olm_crypto_curve25519_shared_secret(
const struct _olm_curve25519_key_pair *our_key,
const struct _olm_curve25519_public_key * their_key,
std::uint8_t * output
) {
::curve25519_donna(output, our_key.private_key, their_key.public_key);
::curve25519_donna(output, our_key->private_key.private_key, their_key->public_key);
}
void olm::curve25519_sign(
olm::Curve25519KeyPair const & our_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t * output
) {
std::uint8_t private_key[KEY_LENGTH];
std::uint8_t public_key[KEY_LENGTH];
std::memcpy(private_key, our_key.private_key, KEY_LENGTH);
::ed25519_keypair(private_key, public_key);
::ed25519_sign(
output,
message, message_length,
public_key, private_key
);
::convert_ed25519_to_curve25519(public_key, output);
}
bool olm::curve25519_verify(
olm::Curve25519PublicKey const & their_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t const * signature
) {
std::uint8_t public_key[KEY_LENGTH];
std::uint8_t signature_buffer[SIGNATURE_LENGTH];
std::memcpy(public_key, their_key.public_key, KEY_LENGTH);
std::memcpy(signature_buffer, signature, SIGNATURE_LENGTH);
::convert_curve25519_to_ed25519(public_key, signature_buffer);
return 0 != ::ed25519_verify(
signature,
message, message_length,
public_key
);
}
void olm::ed25519_generate_key(
void _olm_crypto_ed25519_generate_key(
std::uint8_t const * random_32_bytes,
olm::Ed25519KeyPair & key_pair
struct _olm_ed25519_key_pair *key_pair
) {
std::memcpy(key_pair.private_key, random_32_bytes, KEY_LENGTH);
::ed25519_keypair(key_pair.private_key, key_pair.public_key);
::ed25519_create_keypair(
key_pair->public_key.public_key, key_pair->private_key.private_key,
random_32_bytes
);
}
void olm::ed25519_sign(
olm::Ed25519KeyPair const & our_key,
void _olm_crypto_ed25519_sign(
const struct _olm_ed25519_key_pair *our_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t * output
) {
::ed25519_sign(
output,
message, message_length,
our_key.public_key, our_key.private_key
our_key->public_key.public_key,
our_key->private_key.private_key
);
}
bool olm::ed25519_verify(
olm::Ed25519PublicKey const & their_key,
int _olm_crypto_ed25519_verify(
const struct _olm_ed25519_public_key *their_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t const * signature
) {
return 0 != ::ed25519_verify(
signature,
message, message_length,
their_key.public_key
their_key->public_key
);
}
std::size_t olm::aes_encrypt_cbc_length(
std::size_t _olm_crypto_aes_encrypt_cbc_length(
std::size_t input_length
) {
return input_length + AES_BLOCK_LENGTH - input_length % AES_BLOCK_LENGTH;
}
void olm::aes_encrypt_cbc(
olm::Aes256Key const & key,
olm::Aes256Iv const & iv,
void _olm_crypto_aes_encrypt_cbc(
_olm_aes256_key const *key,
_olm_aes256_iv const *iv,
std::uint8_t const * input, std::size_t input_length,
std::uint8_t * output
) {
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
::aes_key_setup(key.key, key_schedule, AES_KEY_BITS);
::aes_key_setup(key->key, key_schedule, AES_KEY_BITS);
std::uint8_t input_block[AES_BLOCK_LENGTH];
std::memcpy(input_block, iv.iv, AES_BLOCK_LENGTH);
std::memcpy(input_block, iv->iv, AES_BLOCK_LENGTH);
while (input_length >= AES_BLOCK_LENGTH) {
xor_block<AES_BLOCK_LENGTH>(input_block, input);
::aes_encrypt(input_block, output, key_schedule, AES_KEY_BITS);
@ -235,17 +201,17 @@ void olm::aes_encrypt_cbc(
}
std::size_t olm::aes_decrypt_cbc(
olm::Aes256Key const & key,
olm::Aes256Iv const & iv,
std::size_t _olm_crypto_aes_decrypt_cbc(
_olm_aes256_key const *key,
_olm_aes256_iv const *iv,
std::uint8_t const * input, std::size_t input_length,
std::uint8_t * output
) {
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
::aes_key_setup(key.key, key_schedule, AES_KEY_BITS);
::aes_key_setup(key->key, key_schedule, AES_KEY_BITS);
std::uint8_t block1[AES_BLOCK_LENGTH];
std::uint8_t block2[AES_BLOCK_LENGTH];
std::memcpy(block1, iv.iv, AES_BLOCK_LENGTH);
std::memcpy(block1, iv->iv, AES_BLOCK_LENGTH);
for (std::size_t i = 0; i < input_length; i += AES_BLOCK_LENGTH) {
std::memcpy(block2, &input[i], AES_BLOCK_LENGTH);
::aes_decrypt(&input[i], &output[i], key_schedule, AES_KEY_BITS);

View file

@ -16,7 +16,7 @@
#include "ed25519/src/fe.c"
#include "ed25519/src/sc.c"
#include "ed25519/src/ge.c"
#include "ed25519/src/keypair.c"
#include "ed25519/src/sha512.c"
#include "ed25519/src/verify.c"
#include "ed25519/src/sign.c"
#include "ed25519_additions.c"

View file

@ -29,6 +29,8 @@ static const char * ERRORS[] = {
"CORRUPTED_PICKLE",
"BAD_SESSION_KEY",
"UNKNOWN_MESSAGE_INDEX",
"BAD_LEGACY_ACCOUNT_PICKLE",
"BAD_SIGNATURE",
};
const char * _olm_error_to_string(enum OlmErrorCode error)

View file

@ -19,6 +19,7 @@
#include "olm/base64.h"
#include "olm/cipher.h"
#include "olm/crypto.h"
#include "olm/error.h"
#include "olm/megolm.h"
#include "olm/memory.h"
@ -28,7 +29,9 @@
#define OLM_PROTOCOL_VERSION 3
#define GROUP_SESSION_ID_LENGTH ED25519_PUBLIC_KEY_LENGTH
#define PICKLE_VERSION 1
#define SESSION_KEY_VERSION 2
struct OlmInboundGroupSession {
/** our earliest known ratchet value */
@ -37,6 +40,9 @@ struct OlmInboundGroupSession {
/** The most recent ratchet value */
Megolm latest_ratchet;
/** The ed25519 signing key */
struct _olm_ed25519_public_key signing_key;
enum OlmErrorCode last_error;
};
@ -65,30 +71,69 @@ size_t olm_clear_inbound_group_session(
return sizeof(OlmInboundGroupSession);
}
#define SESSION_KEY_RAW_LENGTH \
(1 + 4 + MEGOLM_RATCHET_LENGTH + ED25519_PUBLIC_KEY_LENGTH\
+ ED25519_SIGNATURE_LENGTH)
/** init the session keys from the un-base64-ed session keys */
static size_t _init_group_session_keys(
OlmInboundGroupSession *session,
const uint8_t *key_buf
) {
const uint8_t *ptr = key_buf;
size_t version = *ptr++;
if (version != SESSION_KEY_VERSION) {
session->last_error = OLM_BAD_SESSION_KEY;
return (size_t)-1;
}
uint32_t counter = 0;
// Decode counter as a big endian 32-bit number.
for (unsigned i = 0; i < 4; i++) {
counter <<= 8; counter |= *ptr++;
}
megolm_init(&session->initial_ratchet, ptr, counter);
megolm_init(&session->latest_ratchet, ptr, counter);
ptr += MEGOLM_RATCHET_LENGTH;
memcpy(
session->signing_key.public_key, ptr, ED25519_PUBLIC_KEY_LENGTH
);
ptr += ED25519_PUBLIC_KEY_LENGTH;
if (!_olm_crypto_ed25519_verify(
&session->signing_key, key_buf, ptr - key_buf, ptr
)) {
session->last_error = OLM_BAD_SIGNATURE;
return (size_t)-1;
}
return 0;
}
size_t olm_init_inbound_group_session(
OlmInboundGroupSession *session,
uint32_t message_index,
const uint8_t * session_key, size_t session_key_length
) {
uint8_t key_buf[MEGOLM_RATCHET_LENGTH];
uint8_t key_buf[SESSION_KEY_RAW_LENGTH];
size_t raw_length = _olm_decode_base64_length(session_key_length);
size_t result;
if (raw_length == (size_t)-1) {
session->last_error = OLM_INVALID_BASE64;
return (size_t)-1;
}
if (raw_length != MEGOLM_RATCHET_LENGTH) {
if (raw_length != SESSION_KEY_RAW_LENGTH) {
session->last_error = OLM_BAD_SESSION_KEY;
return (size_t)-1;
}
_olm_decode_base64(session_key, session_key_length, key_buf);
megolm_init(&session->initial_ratchet, key_buf, message_index);
megolm_init(&session->latest_ratchet, key_buf, message_index);
_olm_unset(key_buf, MEGOLM_RATCHET_LENGTH);
return 0;
result = _init_group_session_keys(session, key_buf);
_olm_unset(key_buf, SESSION_KEY_RAW_LENGTH);
return result;
}
static size_t raw_pickle_length(
@ -98,6 +143,7 @@ static size_t raw_pickle_length(
length += _olm_pickle_uint32_length(PICKLE_VERSION);
length += megolm_pickle_length(&session->initial_ratchet);
length += megolm_pickle_length(&session->latest_ratchet);
length += _olm_pickle_ed25519_public_key_length(&session->signing_key);
return length;
}
@ -124,6 +170,7 @@ size_t olm_pickle_inbound_group_session(
pos = _olm_pickle_uint32(pos, PICKLE_VERSION);
pos = megolm_pickle(&session->initial_ratchet, pos);
pos = megolm_pickle(&session->latest_ratchet, pos);
pos = _olm_pickle_ed25519_public_key(pos, &session->signing_key);
return _olm_enc_output(key, key_length, pickled, raw_length);
}
@ -153,6 +200,7 @@ size_t olm_unpickle_inbound_group_session(
}
pos = megolm_unpickle(&session->initial_ratchet, pos, end);
pos = megolm_unpickle(&session->latest_ratchet, pos, end);
pos = _olm_unpickle_ed25519_public_key(pos, end, &session->signing_key);
if (end != pos) {
/* We had the wrong number of bytes in the input. */
@ -175,6 +223,7 @@ static size_t _decrypt_max_plaintext_length(
_olm_decode_group_message(
message, message_length,
megolm_cipher->ops->mac_length(megolm_cipher),
ED25519_SIGNATURE_LENGTH,
&decoded_results);
if (decoded_results.version != OLM_PROTOCOL_VERSION) {
@ -224,6 +273,7 @@ static size_t _decrypt(
_olm_decode_group_message(
message, message_length,
megolm_cipher->ops->mac_length(megolm_cipher),
ED25519_SIGNATURE_LENGTH,
&decoded_results);
if (decoded_results.version != OLM_PROTOCOL_VERSION) {
@ -231,11 +281,27 @@ static size_t _decrypt(
return (size_t)-1;
}
if (!decoded_results.has_message_index || !decoded_results.ciphertext ) {
if (!decoded_results.has_message_index || !decoded_results.ciphertext) {
session->last_error = OLM_BAD_MESSAGE_FORMAT;
return (size_t)-1;
}
/* verify the signature. We could do this before decoding the message, but
* we allow for the possibility of future protocol versions which use a
* different signing mechanism; we would rather throw "BAD_MESSAGE_VERSION"
* than "BAD_SIGNATURE" in this case.
*/
message_length -= ED25519_SIGNATURE_LENGTH;
r = _olm_crypto_ed25519_verify(
&session->signing_key,
message, message_length,
message + message_length
);
if (!r) {
session->last_error = OLM_BAD_SIGNATURE;
return (size_t)-1;
}
max_length = megolm_cipher->ops->decrypt_max_plaintext_length(
megolm_cipher,
decoded_results.ciphertext_length
@ -298,3 +364,23 @@ size_t olm_group_decrypt(
plaintext, max_plaintext_length
);
}
size_t olm_inbound_group_session_id_length(
const OlmInboundGroupSession *session
) {
return _olm_encode_base64_length(GROUP_SESSION_ID_LENGTH);
}
size_t olm_inbound_group_session_id(
OlmInboundGroupSession *session,
uint8_t * id, size_t id_length
) {
if (id_length < olm_inbound_group_session_id_length(session)) {
session->last_error = OLM_OUTPUT_BUFFER_TOO_SMALL;
return (size_t)-1;
}
return _olm_encode_base64(
session->signing_key.public_key, GROUP_SESSION_ID_LENGTH, id
);
}

View file

@ -354,12 +354,14 @@ static const std::uint8_t GROUP_CIPHERTEXT_TAG = 022;
size_t _olm_encode_group_message_length(
uint32_t message_index,
size_t ciphertext_length,
size_t mac_length
size_t mac_length,
size_t signature_length
) {
size_t length = VERSION_LENGTH;
length += 1 + varint_length(message_index);
length += 1 + varstring_length(ciphertext_length);
length += mac_length;
length += signature_length;
return length;
}
@ -381,11 +383,12 @@ size_t _olm_encode_group_message(
void _olm_decode_group_message(
const uint8_t *input, size_t input_length,
size_t mac_length,
size_t mac_length, size_t signature_length,
struct _OlmDecodeGroupMessageResults *results
) {
std::uint8_t const * pos = input;
std::uint8_t const * end = input + input_length - mac_length;
std::size_t trailer_length = mac_length + signature_length;
std::uint8_t const * end = input + input_length - trailer_length;
std::uint8_t const * unknown = nullptr;
bool has_message_index = false;
@ -393,8 +396,7 @@ void _olm_decode_group_message(
results->ciphertext = nullptr;
results->ciphertext_length = 0;
if (pos == end) return;
if (input_length < mac_length) return;
if (input_length < trailer_length) return;
results->version = *(pos++);
while (pos != end) {

View file

@ -99,6 +99,11 @@ std::size_t b64_input(
extern "C" {
void olm_get_library_version(uint8_t *major, uint8_t *minor, uint8_t *patch) {
if (major != NULL) *major = OLMLIB_VERSION_MAJOR;
if (minor != NULL) *minor = OLMLIB_VERSION_MINOR;
if (patch != NULL) *patch = OLMLIB_VERSION_PATCH;
}
size_t olm_error() {
return std::size_t(-1);
@ -432,14 +437,14 @@ size_t olm_create_outbound_session(
std::size_t id_key_length = their_identity_key_length;
std::size_t ot_key_length = their_one_time_key_length;
if (olm::decode_base64_length(id_key_length) != olm::KEY_LENGTH
|| olm::decode_base64_length(ot_key_length) != olm::KEY_LENGTH
if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH
|| olm::decode_base64_length(ot_key_length) != CURVE25519_KEY_LENGTH
) {
from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
return std::size_t(-1);
}
olm::Curve25519PublicKey identity_key;
olm::Curve25519PublicKey one_time_key;
_olm_curve25519_public_key identity_key;
_olm_curve25519_public_key one_time_key;
olm::decode_base64(id_key, id_key_length, identity_key.public_key);
olm::decode_base64(ot_key, ot_key_length, one_time_key.public_key);
@ -479,11 +484,11 @@ size_t olm_create_inbound_session_from(
std::uint8_t const * id_key = from_c(their_identity_key);
std::size_t id_key_length = their_identity_key_length;
if (olm::decode_base64_length(id_key_length) != olm::KEY_LENGTH) {
if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH) {
from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
return std::size_t(-1);
}
olm::Curve25519PublicKey identity_key;
_olm_curve25519_public_key identity_key;
olm::decode_base64(id_key, id_key_length, identity_key.public_key);
std::size_t raw_length = b64_input(
@ -525,6 +530,12 @@ size_t olm_session_id(
}
int olm_session_has_received_message(
OlmSession * session
) {
return from_c(session)->received_message;
}
size_t olm_matches_inbound_session(
OlmSession * session,
void * one_time_key_message, size_t message_length
@ -550,11 +561,11 @@ size_t olm_matches_inbound_session_from(
std::uint8_t const * id_key = from_c(their_identity_key);
std::size_t id_key_length = their_identity_key_length;
if (olm::decode_base64_length(id_key_length) != olm::KEY_LENGTH) {
if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH) {
from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
return std::size_t(-1);
}
olm::Curve25519PublicKey identity_key;
_olm_curve25519_public_key identity_key;
olm::decode_base64(id_key, id_key_length, identity_key.public_key);
std::size_t raw_length = b64_input(
@ -706,11 +717,11 @@ size_t olm_ed25519_verify(
void const * message, size_t message_length,
void * signature, size_t signature_length
) {
if (olm::decode_base64_length(key_length) != olm::KEY_LENGTH) {
if (olm::decode_base64_length(key_length) != CURVE25519_KEY_LENGTH) {
from_c(utility)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
return std::size_t(-1);
}
olm::Ed25519PublicKey verify_key;
_olm_ed25519_public_key verify_key;
olm::decode_base64(from_c(key), key_length, verify_key.public_key);
std::size_t raw_signature_length = b64_input(
from_c(signature), signature_length, from_c(utility)->last_error

View file

@ -20,6 +20,7 @@
#include "olm/base64.h"
#include "olm/cipher.h"
#include "olm/crypto.h"
#include "olm/error.h"
#include "olm/megolm.h"
#include "olm/memory.h"
@ -28,16 +29,16 @@
#include "olm/pickle_encoding.h"
#define OLM_PROTOCOL_VERSION 3
#define SESSION_ID_RANDOM_BYTES 4
#define GROUP_SESSION_ID_LENGTH (sizeof(struct timeval) + SESSION_ID_RANDOM_BYTES)
#define GROUP_SESSION_ID_LENGTH ED25519_PUBLIC_KEY_LENGTH
#define PICKLE_VERSION 1
#define SESSION_KEY_VERSION 2
struct OlmOutboundGroupSession {
/** the Megolm ratchet providing the encryption keys */
Megolm ratchet;
/** unique identifier for this session */
uint8_t session_id[GROUP_SESSION_ID_LENGTH];
/** The ed25519 keypair used for signing the messages */
struct _olm_ed25519_key_pair signing_key;
enum OlmErrorCode last_error;
};
@ -74,8 +75,7 @@ static size_t raw_pickle_length(
size_t length = 0;
length += _olm_pickle_uint32_length(PICKLE_VERSION);
length += megolm_pickle_length(&(session->ratchet));
length += _olm_pickle_bytes_length(session->session_id,
GROUP_SESSION_ID_LENGTH);
length += _olm_pickle_ed25519_key_pair_length(&(session->signing_key));
return length;
}
@ -101,7 +101,7 @@ size_t olm_pickle_outbound_group_session(
pos = _olm_enc_output_pos(pickled, raw_length);
pos = _olm_pickle_uint32(pos, PICKLE_VERSION);
pos = megolm_pickle(&(session->ratchet), pos);
pos = _olm_pickle_bytes(pos, session->session_id, GROUP_SESSION_ID_LENGTH);
pos = _olm_pickle_ed25519_key_pair(pos, &(session->signing_key));
return _olm_enc_output(key, key_length, pickled, raw_length);
}
@ -130,7 +130,7 @@ size_t olm_unpickle_outbound_group_session(
return (size_t)-1;
}
pos = megolm_unpickle(&(session->ratchet), pos, end);
pos = _olm_unpickle_bytes(pos, end, session->session_id, GROUP_SESSION_ID_LENGTH);
pos = _olm_unpickle_ed25519_key_pair(pos, end, &(session->signing_key));
if (end != pos) {
/* We had the wrong number of bytes in the input. */
@ -148,7 +148,8 @@ size_t olm_init_outbound_group_session_random_length(
/* we need data to initialize the megolm ratchet, plus some more for the
* session id.
*/
return MEGOLM_RATCHET_LENGTH + SESSION_ID_RANDOM_BYTES;
return MEGOLM_RATCHET_LENGTH +
ED25519_RANDOM_LENGTH;
}
size_t olm_init_outbound_group_session(
@ -164,12 +165,8 @@ size_t olm_init_outbound_group_session(
megolm_init(&(session->ratchet), random, 0);
random += MEGOLM_RATCHET_LENGTH;
/* initialise the session id. This just has to be unique. We use the
* current time plus some random data.
*/
gettimeofday((struct timeval *)(session->session_id), NULL);
memcpy((session->session_id) + sizeof(struct timeval),
random, SESSION_ID_RANDOM_BYTES);
_olm_crypto_ed25519_generate_key(random, &(session->signing_key));
random += ED25519_RANDOM_LENGTH;
return 0;
}
@ -188,7 +185,8 @@ static size_t raw_message_length(
return _olm_encode_group_message_length(
session->ratchet.counter,
ciphertext_length, mac_length);
ciphertext_length, mac_length, ED25519_SIGNATURE_LENGTH
);
}
size_t olm_group_encrypt_message_length(
@ -241,6 +239,13 @@ static size_t _encrypt(
megolm_advance(&(session->ratchet));
/* sign the whole thing with the ed25519 key. */
_olm_crypto_ed25519_sign(
&(session->signing_key),
buffer, message_length,
buffer + message_length
);
return result;
}
@ -293,7 +298,9 @@ size_t olm_outbound_group_session_id(
return (size_t)-1;
}
return _olm_encode_base64(session->session_id, GROUP_SESSION_ID_LENGTH, id);
return _olm_encode_base64(
session->signing_key.public_key.public_key, GROUP_SESSION_ID_LENGTH, id
);
}
uint32_t olm_outbound_group_session_message_index(
@ -302,23 +309,53 @@ uint32_t olm_outbound_group_session_message_index(
return session->ratchet.counter;
}
#define SESSION_KEY_RAW_LENGTH \
(1 + 4 + MEGOLM_RATCHET_LENGTH + ED25519_PUBLIC_KEY_LENGTH\
+ ED25519_SIGNATURE_LENGTH)
size_t olm_outbound_group_session_key_length(
const OlmOutboundGroupSession *session
) {
return _olm_encode_base64_length(MEGOLM_RATCHET_LENGTH);
return _olm_encode_base64_length(SESSION_KEY_RAW_LENGTH);
}
size_t olm_outbound_group_session_key(
OlmOutboundGroupSession *session,
uint8_t * key, size_t key_length
) {
if (key_length < olm_outbound_group_session_key_length(session)) {
uint8_t *raw;
uint8_t *ptr;
size_t encoded_length = olm_outbound_group_session_key_length(session);
if (key_length < encoded_length) {
session->last_error = OLM_OUTPUT_BUFFER_TOO_SMALL;
return (size_t)-1;
}
return _olm_encode_base64(
megolm_get_data(&session->ratchet),
MEGOLM_RATCHET_LENGTH, key
/* put the raw data at the end of the output buffer. */
raw = ptr = key + encoded_length - SESSION_KEY_RAW_LENGTH;
*ptr++ = SESSION_KEY_VERSION;
uint32_t counter = session->ratchet.counter;
// Encode counter as a big endian 32-bit number.
for (unsigned i = 0; i < 4; i++) {
*ptr++ = 0xFF & (counter >> 24); counter <<= 8;
}
memcpy(ptr, megolm_get_data(&session->ratchet), MEGOLM_RATCHET_LENGTH);
ptr += MEGOLM_RATCHET_LENGTH;
memcpy(
ptr, session->signing_key.public_key.public_key,
ED25519_PUBLIC_KEY_LENGTH
);
ptr += ED25519_PUBLIC_KEY_LENGTH;
/* sign the whole thing with the ed25519 key. */
_olm_crypto_ed25519_sign(
&(session->signing_key),
raw, ptr - raw, ptr
);
return _olm_encode_base64(raw, SESSION_KEY_RAW_LENGTH, key);
}

View file

@ -71,7 +71,7 @@ std::uint8_t const * olm::unpickle_bytes(
std::size_t olm::pickle_length(
const olm::Curve25519PublicKey & value
const _olm_curve25519_public_key & value
) {
return sizeof(value.public_key);
}
@ -79,7 +79,7 @@ std::size_t olm::pickle_length(
std::uint8_t * olm::pickle(
std::uint8_t * pos,
const olm::Curve25519PublicKey & value
const _olm_curve25519_public_key & value
) {
pos = olm::pickle_bytes(
pos, value.public_key, sizeof(value.public_key)
@ -90,7 +90,7 @@ std::uint8_t * olm::pickle(
std::uint8_t const * olm::unpickle(
std::uint8_t const * pos, std::uint8_t const * end,
olm::Curve25519PublicKey & value
_olm_curve25519_public_key & value
) {
pos = olm::unpickle_bytes(
pos, end, value.public_key, sizeof(value.public_key)
@ -101,21 +101,24 @@ std::uint8_t const * olm::unpickle(
std::size_t olm::pickle_length(
const olm::Curve25519KeyPair & value
const _olm_curve25519_key_pair & value
) {
return sizeof(value.public_key) + sizeof(value.private_key);
return sizeof(value.public_key.public_key)
+ sizeof(value.private_key.private_key);
}
std::uint8_t * olm::pickle(
std::uint8_t * pos,
const olm::Curve25519KeyPair & value
const _olm_curve25519_key_pair & value
) {
pos = olm::pickle_bytes(
pos, value.public_key, sizeof(value.public_key)
pos, value.public_key.public_key,
sizeof(value.public_key.public_key)
);
pos = olm::pickle_bytes(
pos, value.private_key, sizeof(value.private_key)
pos, value.private_key.private_key,
sizeof(value.private_key.private_key)
);
return pos;
}
@ -123,83 +126,89 @@ std::uint8_t * olm::pickle(
std::uint8_t const * olm::unpickle(
std::uint8_t const * pos, std::uint8_t const * end,
olm::Curve25519KeyPair & value
_olm_curve25519_key_pair & value
) {
pos = olm::unpickle_bytes(
pos, end, value.public_key, sizeof(value.public_key)
pos, end, value.public_key.public_key,
sizeof(value.public_key.public_key)
);
pos = olm::unpickle_bytes(
pos, end, value.private_key, sizeof(value.private_key)
);
return pos;
}
std::size_t olm::pickle_length(
const olm::Ed25519PublicKey & value
) {
return sizeof(value.public_key);
}
std::uint8_t * olm::pickle(
std::uint8_t * pos,
const olm::Ed25519PublicKey & value
) {
pos = olm::pickle_bytes(
pos, value.public_key, sizeof(value.public_key)
);
return pos;
}
std::uint8_t const * olm::unpickle(
std::uint8_t const * pos, std::uint8_t const * end,
olm::Ed25519PublicKey & value
) {
pos = olm::unpickle_bytes(
pos, end, value.public_key, sizeof(value.public_key)
);
return pos;
}
std::size_t olm::pickle_length(
const olm::Ed25519KeyPair & value
) {
return sizeof(value.public_key) + sizeof(value.private_key);
}
std::uint8_t * olm::pickle(
std::uint8_t * pos,
const olm::Ed25519KeyPair & value
) {
pos = olm::pickle_bytes(
pos, value.public_key, sizeof(value.public_key)
);
pos = olm::pickle_bytes(
pos, value.private_key, sizeof(value.private_key)
);
return pos;
}
std::uint8_t const * olm::unpickle(
std::uint8_t const * pos, std::uint8_t const * end,
olm::Ed25519KeyPair & value
) {
pos = olm::unpickle_bytes(
pos, end, value.public_key, sizeof(value.public_key)
);
pos = olm::unpickle_bytes(
pos, end, value.private_key, sizeof(value.private_key)
pos, end, value.private_key.private_key,
sizeof(value.private_key.private_key)
);
return pos;
}
////// pickle.h implementations
std::size_t _olm_pickle_ed25519_public_key_length(
const _olm_ed25519_public_key * value
) {
return sizeof(value->public_key);
}
std::uint8_t * _olm_pickle_ed25519_public_key(
std::uint8_t * pos,
const _olm_ed25519_public_key *value
) {
pos = olm::pickle_bytes(
pos, value->public_key, sizeof(value->public_key)
);
return pos;
}
std::uint8_t const * _olm_unpickle_ed25519_public_key(
std::uint8_t const * pos, std::uint8_t const * end,
_olm_ed25519_public_key * value
) {
pos = olm::unpickle_bytes(
pos, end, value->public_key, sizeof(value->public_key)
);
return pos;
}
std::size_t _olm_pickle_ed25519_key_pair_length(
const _olm_ed25519_key_pair *value
) {
return sizeof(value->public_key.public_key)
+ sizeof(value->private_key.private_key);
}
std::uint8_t * _olm_pickle_ed25519_key_pair(
std::uint8_t * pos,
const _olm_ed25519_key_pair *value
) {
pos = olm::pickle_bytes(
pos, value->public_key.public_key,
sizeof(value->public_key.public_key)
);
pos = olm::pickle_bytes(
pos, value->private_key.private_key,
sizeof(value->private_key.private_key)
);
return pos;
}
std::uint8_t const * _olm_unpickle_ed25519_key_pair(
std::uint8_t const * pos, std::uint8_t const * end,
_olm_ed25519_key_pair *value
) {
pos = olm::unpickle_bytes(
pos, end, value->public_key.public_key,
sizeof(value->public_key.public_key)
);
pos = olm::unpickle_bytes(
pos, end, value->private_key.private_key,
sizeof(value->private_key.private_key)
);
return pos;
}
uint8_t * _olm_pickle_uint32(uint8_t * pos, uint32_t value) {
return olm::pickle(pos, value);
}

View file

@ -44,15 +44,15 @@ static const std::size_t MAX_MESSAGE_GAP = 2000;
*/
static void create_chain_key(
olm::SharedKey const & root_key,
olm::Curve25519KeyPair const & our_key,
olm::Curve25519PublicKey const & their_key,
_olm_curve25519_key_pair const & our_key,
_olm_curve25519_public_key const & their_key,
olm::KdfInfo const & info,
olm::SharedKey & new_root_key,
olm::ChainKey & new_chain_key
) {
olm::SharedKey secret;
olm::curve25519_shared_secret(our_key, their_key, secret);
std::uint8_t derived_secrets[2 * olm::KEY_LENGTH];
_olm_crypto_curve25519_shared_secret(&our_key, &their_key, secret);
std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH];
_olm_crypto_hkdf_sha256(
secret, sizeof(secret),
root_key, sizeof(root_key),
@ -203,9 +203,9 @@ olm::Ratchet::Ratchet(
void olm::Ratchet::initialise_as_bob(
std::uint8_t const * shared_secret, std::size_t shared_secret_length,
olm::Curve25519PublicKey const & their_ratchet_key
_olm_curve25519_public_key const & their_ratchet_key
) {
std::uint8_t derived_secrets[2 * olm::KEY_LENGTH];
std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH];
_olm_crypto_hkdf_sha256(
shared_secret, shared_secret_length,
nullptr, 0,
@ -226,9 +226,9 @@ void olm::Ratchet::initialise_as_bob(
void olm::Ratchet::initialise_as_alice(
std::uint8_t const * shared_secret, std::size_t shared_secret_length,
olm::Curve25519KeyPair const & our_ratchet_key
_olm_curve25519_key_pair const & our_ratchet_key
) {
std::uint8_t derived_secrets[2 * olm::KEY_LENGTH];
std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH];
_olm_crypto_hkdf_sha256(
shared_secret, shared_secret_length,
nullptr, 0,
@ -252,7 +252,7 @@ namespace olm {
static std::size_t pickle_length(
const olm::SharedKey & value
) {
return olm::KEY_LENGTH;
return olm::OLM_SHARED_KEY_LENGTH;
}
@ -260,7 +260,7 @@ static std::uint8_t * pickle(
std::uint8_t * pos,
const olm::SharedKey & value
) {
return olm::pickle_bytes(pos, value, olm::KEY_LENGTH);
return olm::pickle_bytes(pos, value, olm::OLM_SHARED_KEY_LENGTH);
}
@ -268,7 +268,7 @@ static std::uint8_t const * unpickle(
std::uint8_t const * pos, std::uint8_t const * end,
olm::SharedKey & value
) {
return olm::unpickle_bytes(pos, end, value, olm::KEY_LENGTH);
return olm::unpickle_bytes(pos, end, value, olm::OLM_SHARED_KEY_LENGTH);
}
@ -377,7 +377,7 @@ std::size_t olm::pickle_length(
olm::Ratchet const & value
) {
std::size_t length = 0;
length += olm::KEY_LENGTH;
length += olm::OLM_SHARED_KEY_LENGTH;
length += olm::pickle_length(value.sender_chain);
length += olm::pickle_length(value.receiver_chains);
length += olm::pickle_length(value.skipped_message_keys);
@ -428,13 +428,13 @@ std::size_t olm::Ratchet::encrypt_output_length(
plaintext_length
);
return olm::encode_message_length(
counter, olm::KEY_LENGTH, padded, ratchet_cipher->ops->mac_length(ratchet_cipher)
counter, CURVE25519_KEY_LENGTH, padded, ratchet_cipher->ops->mac_length(ratchet_cipher)
);
}
std::size_t olm::Ratchet::encrypt_random_length() {
return sender_chain.empty() ? olm::KEY_LENGTH : 0;
return sender_chain.empty() ? CURVE25519_RANDOM_LENGTH : 0;
}
@ -456,10 +456,15 @@ std::size_t olm::Ratchet::encrypt(
if (sender_chain.empty()) {
sender_chain.insert();
olm::curve25519_generate_key(random, sender_chain[0].ratchet_key);
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY, "Created new ratchet key T(%i) %s",
chain_index + 1,
sender_chain[0].ratchet_key.to_string().c_str());
_olm_crypto_curve25519_generate_key(random, &sender_chain[0].ratchet_key);
olm_logf(
OLM_LOG_DEBUG, LOG_CATEGORY, "Created new ratchet key T(%i) %s",
chain_index + 1,
olm::bytes_to_string(
std::begin(sender_chain[0].ratchet_key.public_key.public_key),
std::end(sender_chain[0].ratchet_key.public_key.public_key)
).c_str()
);
create_chain_key(
root_key,
sender_chain[0].ratchet_key,
@ -481,12 +486,14 @@ std::size_t olm::Ratchet::encrypt(
plaintext_length
);
std::uint32_t counter = keys.index;
Curve25519PublicKey const & ratchet_key = sender_chain[0].ratchet_key;
_olm_curve25519_public_key const & ratchet_key =
sender_chain[0].ratchet_key.public_key;
olm::MessageWriter writer;
olm::encode_message(
writer, PROTOCOL_VERSION, counter, olm::KEY_LENGTH, ciphertext_length,
writer, PROTOCOL_VERSION, counter, CURVE25519_KEY_LENGTH,
ciphertext_length,
output
);
@ -500,12 +507,13 @@ std::size_t olm::Ratchet::encrypt(
output, output_length
);
olm_logf(OLM_LOG_TRACE, LOG_CATEGORY,
"Encoded message ver=%i ratchet_key=%s chain_idx=%i ciphertext=%s",
PROTOCOL_VERSION,
olm::bytes_to_string(writer.ratchet_key, olm::KEY_LENGTH).c_str(),
counter,
olm::bytes_to_string(writer.ciphertext, ciphertext_length).c_str()
olm_logf(
OLM_LOG_TRACE, LOG_CATEGORY,
"Encoded message ver=%i ratchet_key=%s chain_idx=%i ciphertext=%s",
PROTOCOL_VERSION,
olm::bytes_to_string(writer.ratchet_key, CURVE25519_KEY_LENGTH).c_str(),
counter,
olm::bytes_to_string(writer.ciphertext, ciphertext_length).c_str()
);
olm::unset(keys);
@ -566,7 +574,7 @@ std::size_t olm::Ratchet::decrypt(
return std::size_t(-1);
}
if (reader.ratchet_key_length != olm::KEY_LENGTH) {
if (reader.ratchet_key_length != CURVE25519_KEY_LENGTH) {
last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT;
return std::size_t(-1);
}
@ -582,7 +590,7 @@ std::size_t olm::Ratchet::decrypt(
for (olm::ReceiverChain & receiver_chain : receiver_chains) {
if (0 == std::memcmp(
receiver_chain.ratchet_key.public_key, reader.ratchet_key,
olm::KEY_LENGTH
CURVE25519_KEY_LENGTH
)) {
chain = &receiver_chain;
break;
@ -605,7 +613,7 @@ std::size_t olm::Ratchet::decrypt(
if (reader.counter == skipped.message_key.index
&& 0 == std::memcmp(
skipped.ratchet_key.public_key, reader.ratchet_key,
olm::KEY_LENGTH
CURVE25519_KEY_LENGTH
)
) {
/* Found the key for this message. Check the MAC. */

View file

@ -14,7 +14,7 @@
*/
#include "olm/session.hh"
#include "olm/cipher.h"
#include "olm/crypto.hh"
#include "olm/crypto.h"
#include "olm/account.hh"
#include "olm/logging.h"
#include "olm/memory.hh"
@ -41,6 +41,23 @@ static const olm::KdfInfo OLM_KDF_INFO = {
static const struct _olm_cipher_aes_sha_256 OLM_CIPHER =
OLM_CIPHER_INIT_AES_SHA_256(CIPHER_KDF_INFO);
static std::string to_string(const _olm_curve25519_public_key *key) {
return olm::bytes_to_string(
std::begin(key->public_key),
std::end(key->public_key)
);
};
static std::string to_string(const _olm_curve25519_key_pair *key) {
return olm::bytes_to_string(
std::begin(key->public_key.public_key),
std::end(key->public_key.public_key)
);
};
} // namespace
olm::Session::Session(
@ -52,14 +69,14 @@ olm::Session::Session(
std::size_t olm::Session::new_outbound_session_random_length() {
return olm::KEY_LENGTH * 2;
return CURVE25519_RANDOM_LENGTH * 2;
}
std::size_t olm::Session::new_outbound_session(
olm::Account const & local_account,
olm::Curve25519PublicKey const & identity_key,
olm::Curve25519PublicKey const & one_time_key,
_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
) {
if (random_length < new_outbound_session_random_length()) {
@ -69,37 +86,38 @@ std::size_t olm::Session::new_outbound_session(
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY,
"Creating new outbound session to receiver identity IB %s, "
"receiver ephemeral EB %s", identity_key.to_string().c_str(),
one_time_key.to_string().c_str()
"receiver ephemeral EB %s", to_string(&identity_key).c_str(),
to_string(&one_time_key).c_str()
);
olm::Curve25519KeyPair base_key;
olm::curve25519_generate_key(random, base_key);
_olm_curve25519_key_pair base_key;
_olm_crypto_curve25519_generate_key(random, &base_key);
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY, "Created new ephemeral key EA %s",
base_key.to_string().c_str());
to_string(&base_key).c_str());
olm::Curve25519KeyPair ratchet_key;
olm::curve25519_generate_key(random + olm::KEY_LENGTH, ratchet_key);
_olm_curve25519_key_pair ratchet_key;
_olm_crypto_curve25519_generate_key(random + CURVE25519_RANDOM_LENGTH, &ratchet_key);
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY, "Created new ratchet key T(0) %s",
ratchet_key.to_string().c_str());
to_string(&ratchet_key).c_str());
olm::Curve25519KeyPair const & alice_identity_key_pair = (
_olm_curve25519_key_pair const & alice_identity_key_pair = (
local_account.identity_keys.curve25519_key
);
received_message = false;
alice_identity_key = alice_identity_key_pair;
alice_base_key = base_key;
alice_identity_key = alice_identity_key_pair.public_key;
alice_base_key = base_key.public_key;
bob_one_time_key = one_time_key;
std::uint8_t secret[3 * olm::KEY_LENGTH];
// Calculate the shared secret S via triple DH
std::uint8_t secret[3 * CURVE25519_SHARED_SECRET_LENGTH];
std::uint8_t * pos = secret;
olm::curve25519_shared_secret(alice_identity_key_pair, one_time_key, pos);
pos += olm::KEY_LENGTH;
olm::curve25519_shared_secret(base_key, identity_key, pos);
pos += olm::KEY_LENGTH;
olm::curve25519_shared_secret(base_key, one_time_key, pos);
_olm_crypto_curve25519_shared_secret(&alice_identity_key_pair, &one_time_key, pos);
pos += CURVE25519_SHARED_SECRET_LENGTH;
_olm_crypto_curve25519_shared_secret(&base_key, &identity_key, pos);
pos += CURVE25519_SHARED_SECRET_LENGTH;
_olm_crypto_curve25519_shared_secret(&base_key, &one_time_key, pos);
ratchet.initialise_as_alice(secret, sizeof(secret), ratchet_key);
@ -119,13 +137,13 @@ static bool check_message_fields(
bool ok = true;
ok = ok && (have_their_identity_key || reader.identity_key);
if (reader.identity_key) {
ok = ok && reader.identity_key_length == olm::KEY_LENGTH;
ok = ok && reader.identity_key_length == CURVE25519_KEY_LENGTH;
}
ok = ok && reader.message;
ok = ok && reader.base_key;
ok = ok && reader.base_key_length == olm::KEY_LENGTH;
ok = ok && reader.base_key_length == CURVE25519_KEY_LENGTH;
ok = ok && reader.one_time_key;
ok = ok && reader.one_time_key_length == olm::KEY_LENGTH;
ok = ok && reader.one_time_key_length == CURVE25519_KEY_LENGTH;
return ok;
}
@ -134,7 +152,7 @@ static bool check_message_fields(
std::size_t olm::Session::new_inbound_session(
olm::Account & local_account,
olm::Curve25519PublicKey const * their_identity_key,
_olm_curve25519_public_key const * their_identity_key,
std::uint8_t const * one_time_key_message, std::size_t message_length
) {
olm::PreKeyMessageReader reader;
@ -147,16 +165,17 @@ std::size_t olm::Session::new_inbound_session(
if (reader.identity_key && their_identity_key) {
bool same = 0 == std::memcmp(
their_identity_key->public_key, reader.identity_key, olm::KEY_LENGTH
their_identity_key->public_key, reader.identity_key, CURVE25519_KEY_LENGTH
);
if (!same) {
olm_logf(OLM_LOG_INFO, LOG_CATEGORY,
"Identity key on received message is incorrect "
"(expected %s, got %s)",
their_identity_key->to_string().c_str(),
olm::bytes_to_string(reader.identity_key,
reader.identity_key + olm::KEY_LENGTH)
.c_str());
to_string(their_identity_key).c_str(),
olm::bytes_to_string(
reader.identity_key,
reader.identity_key + CURVE25519_KEY_LENGTH
).c_str());
last_error = OlmErrorCode::OLM_BAD_MESSAGE_KEY_ID;
return std::size_t(-1);
}
@ -169,9 +188,9 @@ std::size_t olm::Session::new_inbound_session(
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY,
"Creating new inbound session from sender identity IA %s, "
"sender ephemeral EA %s, our ephemeral EB %s",
alice_identity_key.to_string().c_str(),
alice_base_key.to_string().c_str(),
bob_one_time_key.to_string().c_str());
to_string(&alice_identity_key).c_str(),
to_string(&alice_base_key).c_str(),
to_string(&bob_one_time_key).c_str());
olm::MessageReader message_reader;
decode_message(
@ -180,16 +199,16 @@ std::size_t olm::Session::new_inbound_session(
);
if (!message_reader.ratchet_key
|| message_reader.ratchet_key_length != olm::KEY_LENGTH) {
|| message_reader.ratchet_key_length != CURVE25519_KEY_LENGTH) {
last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT;
return std::size_t(-1);
}
olm::Curve25519PublicKey ratchet_key;
_olm_curve25519_public_key ratchet_key;
olm::load_array(ratchet_key.public_key, message_reader.ratchet_key);
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY,
"Received ratchet key T(0) %s", ratchet_key.to_string().c_str());
"Received ratchet key T(0) %s", to_string(&ratchet_key).c_str());
olm::OneTimeKey const * our_one_time_key = local_account.lookup_key(
bob_one_time_key
@ -198,23 +217,24 @@ std::size_t olm::Session::new_inbound_session(
if (!our_one_time_key) {
olm_logf(OLM_LOG_INFO, LOG_CATEGORY,
"Session uses unknown ephemeral key %s",
bob_one_time_key.to_string().c_str());
to_string(&bob_one_time_key).c_str());
last_error = OlmErrorCode::OLM_BAD_MESSAGE_KEY_ID;
return std::size_t(-1);
}
olm::Curve25519KeyPair const & bob_identity_key = (
_olm_curve25519_key_pair const & bob_identity_key = (
local_account.identity_keys.curve25519_key
);
olm::Curve25519KeyPair const & bob_one_time_key = our_one_time_key->key;
_olm_curve25519_key_pair const & bob_one_time_key = our_one_time_key->key;
std::uint8_t secret[olm::KEY_LENGTH * 3];
// Calculate the shared secret S via triple DH
std::uint8_t secret[CURVE25519_SHARED_SECRET_LENGTH * 3];
std::uint8_t * pos = secret;
olm::curve25519_shared_secret(bob_one_time_key, alice_identity_key, pos);
pos += olm::KEY_LENGTH;
olm::curve25519_shared_secret(bob_identity_key, alice_base_key, pos);
pos += olm::KEY_LENGTH;
olm::curve25519_shared_secret(bob_one_time_key, alice_base_key, pos);
_olm_crypto_curve25519_shared_secret(&bob_one_time_key, &alice_identity_key, pos);
pos += CURVE25519_SHARED_SECRET_LENGTH;
_olm_crypto_curve25519_shared_secret(&bob_identity_key, &alice_base_key, pos);
pos += CURVE25519_SHARED_SECRET_LENGTH;
_olm_crypto_curve25519_shared_secret(&bob_one_time_key, &alice_base_key, pos);
ratchet.initialise_as_bob(secret, sizeof(secret), ratchet_key);
@ -237,7 +257,7 @@ std::size_t olm::Session::session_id(
last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
return std::size_t(-1);
}
std::uint8_t tmp[olm::KEY_LENGTH * 3];
std::uint8_t tmp[CURVE25519_KEY_LENGTH * 3];
std::uint8_t * pos = tmp;
pos = olm::store_array(pos, alice_identity_key.public_key);
pos = olm::store_array(pos, alice_base_key.public_key);
@ -248,7 +268,7 @@ std::size_t olm::Session::session_id(
bool olm::Session::matches_inbound_session(
olm::Curve25519PublicKey const * their_identity_key,
_olm_curve25519_public_key const * their_identity_key,
std::uint8_t const * one_time_key_message, std::size_t message_length
) {
olm::PreKeyMessageReader reader;
@ -261,20 +281,20 @@ bool olm::Session::matches_inbound_session(
bool same = true;
if (reader.identity_key) {
same = same && 0 == std::memcmp(
reader.identity_key, alice_identity_key.public_key, olm::KEY_LENGTH
reader.identity_key, alice_identity_key.public_key, CURVE25519_KEY_LENGTH
);
}
if (their_identity_key) {
same = same && 0 == std::memcmp(
their_identity_key->public_key, alice_identity_key.public_key,
olm::KEY_LENGTH
CURVE25519_KEY_LENGTH
);
}
same = same && 0 == std::memcmp(
reader.base_key, alice_base_key.public_key, olm::KEY_LENGTH
reader.base_key, alice_base_key.public_key, CURVE25519_KEY_LENGTH
);
same = same && 0 == std::memcmp(
reader.one_time_key, bob_one_time_key.public_key, olm::KEY_LENGTH
reader.one_time_key, bob_one_time_key.public_key, CURVE25519_KEY_LENGTH
);
return same;
}
@ -301,9 +321,9 @@ std::size_t olm::Session::encrypt_message_length(
}
return encode_one_time_key_message_length(
olm::KEY_LENGTH,
olm::KEY_LENGTH,
olm::KEY_LENGTH,
CURVE25519_KEY_LENGTH,
CURVE25519_KEY_LENGTH,
CURVE25519_KEY_LENGTH,
message_length
);
}
@ -338,9 +358,9 @@ std::size_t olm::Session::encrypt(
encode_one_time_key_message(
writer,
PROTOCOL_VERSION,
olm::KEY_LENGTH,
olm::KEY_LENGTH,
olm::KEY_LENGTH,
CURVE25519_KEY_LENGTH,
CURVE25519_KEY_LENGTH,
CURVE25519_KEY_LENGTH,
message_body_length,
message
);
@ -354,9 +374,9 @@ std::size_t olm::Session::encrypt(
"Encoded pre-key message ver=%i one_time_key[Eb]=%s "
"base_key[Ea]=%s identity_key[Ia]=%s",
PROTOCOL_VERSION,
olm::bytes_to_string(writer.one_time_key, olm::KEY_LENGTH).c_str(),
olm::bytes_to_string(writer.base_key, olm::KEY_LENGTH).c_str(),
olm::bytes_to_string(writer.identity_key, olm::KEY_LENGTH).c_str()
olm::bytes_to_string(writer.one_time_key, CURVE25519_KEY_LENGTH).c_str(),
olm::bytes_to_string(writer.base_key, CURVE25519_KEY_LENGTH).c_str(),
olm::bytes_to_string(writer.identity_key, CURVE25519_KEY_LENGTH).c_str()
);
}

View file

@ -14,7 +14,7 @@
*/
#include "olm/utility.hh"
#include "olm/crypto.hh"
#include "olm/crypto.h"
olm::Utility::Utility(
@ -41,15 +41,15 @@ size_t olm::Utility::sha256(
size_t olm::Utility::ed25519_verify(
Ed25519PublicKey const & key,
_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
) {
if (signature_length < olm::SIGNATURE_LENGTH) {
if (signature_length < ED25519_SIGNATURE_LENGTH) {
last_error = OlmErrorCode::OLM_BAD_MESSAGE_MAC;
return std::size_t(-1);
}
if (!olm::ed25519_verify(key, message, message_length, signature)) {
if (!_olm_crypto_ed25519_verify(&key, message, message_length, signature)) {
last_error = OlmErrorCode::OLM_BAD_MESSAGE_MAC;
return std::size_t(-1);
}

View file

@ -12,7 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "olm/crypto.hh"
#include "olm/crypto.h"
#include "unittest.hh"
@ -58,60 +58,31 @@ std::uint8_t expected_agreement[32] = {
0x76, 0xF0, 0x9B, 0x3C, 0x1E, 0x16, 0x17, 0x42
};
olm::Curve25519KeyPair alice_pair;
olm::curve25519_generate_key(alice_private, alice_pair);
_olm_curve25519_key_pair alice_pair;
_olm_crypto_curve25519_generate_key(alice_private, &alice_pair);
assert_equals(alice_private, alice_pair.private_key, 32);
assert_equals(alice_public, alice_pair.public_key, 32);
assert_equals(alice_private, alice_pair.private_key.private_key, 32);
assert_equals(alice_public, alice_pair.public_key.public_key, 32);
olm::Curve25519KeyPair bob_pair;
olm::curve25519_generate_key(bob_private, bob_pair);
_olm_curve25519_key_pair bob_pair;
_olm_crypto_curve25519_generate_key(bob_private, &bob_pair);
assert_equals(bob_private, bob_pair.private_key, 32);
assert_equals(bob_public, bob_pair.public_key, 32);
assert_equals(bob_private, bob_pair.private_key.private_key, 32);
assert_equals(bob_public, bob_pair.public_key.public_key, 32);
std::uint8_t actual_agreement[olm::KEY_LENGTH] = {};
std::uint8_t actual_agreement[CURVE25519_SHARED_SECRET_LENGTH] = {};
olm::curve25519_shared_secret(alice_pair, bob_pair, actual_agreement);
_olm_crypto_curve25519_shared_secret(&alice_pair, &bob_pair.public_key, actual_agreement);
assert_equals(expected_agreement, actual_agreement, 32);
olm::curve25519_shared_secret(bob_pair, alice_pair, actual_agreement);
_olm_crypto_curve25519_shared_secret(&bob_pair, &alice_pair.public_key, actual_agreement);
assert_equals(expected_agreement, actual_agreement, 32);
} /* Curve25529 Test Case 1 */
{ /* Curve25519 Signature Test Case 1 */
TestCase test_case("Curve25519 Signature Test Case 1");
std::uint8_t private_key[33] = "This key is a string of 32 bytes";
std::uint8_t message[] = "message";
std::size_t message_length = sizeof(message) - 1;
olm::Curve25519KeyPair key_pair;
olm::curve25519_generate_key(private_key, key_pair);
std::uint8_t signature[64];
olm::curve25519_sign(
key_pair, message, message_length, signature
);
bool result = olm::curve25519_verify(
key_pair, message, message_length, signature
);
assert_equals(true, result);
message[0] = 'n';
result = olm::curve25519_verify(
key_pair, message, message_length, signature
);
assert_equals(false, result);
} /* Curve25519 Signature Test Case 1 */
{
TestCase test_case("Ed25519 Signature Test Case 1");
std::uint8_t private_key[33] = "This key is a string of 32 bytes";
@ -119,22 +90,22 @@ std::uint8_t private_key[33] = "This key is a string of 32 bytes";
std::uint8_t message[] = "Hello, World";
std::size_t message_length = sizeof(message) - 1;
olm::Ed25519KeyPair key_pair;
olm::ed25519_generate_key(private_key, key_pair);
_olm_ed25519_key_pair key_pair;
_olm_crypto_ed25519_generate_key(private_key, &key_pair);
std::uint8_t signature[64];
olm::ed25519_sign(
key_pair, message, message_length, signature
_olm_crypto_ed25519_sign(
&key_pair, message, message_length, signature
);
bool result = olm::ed25519_verify(
key_pair, message, message_length, signature
bool result = _olm_crypto_ed25519_verify(
&key_pair.public_key, message, message_length, signature
);
assert_equals(true, result);
message[0] = 'n';
result = olm::ed25519_verify(
key_pair, message, message_length, signature
result = _olm_crypto_ed25519_verify(
&key_pair.public_key, message, message_length, signature
);
assert_equals(false, result);
}
@ -144,8 +115,8 @@ assert_equals(false, result);
TestCase test_case("AES Test Case 1");
olm::Aes256Key key = {};
olm::Aes256Iv iv = {};
_olm_aes256_key key = {};
_olm_aes256_iv iv = {};
std::uint8_t input[16] = {};
std::uint8_t expected[32] = {
@ -155,16 +126,16 @@ std::uint8_t expected[32] = {
0x4B, 0xAE, 0xDF, 0xFC, 0x3D, 0x21, 0x4C, 0x38
};
std::size_t length = olm::aes_encrypt_cbc_length(sizeof(input));
std::size_t length = _olm_crypto_aes_encrypt_cbc_length(sizeof(input));
assert_equals(std::size_t(32), length);
std::uint8_t actual[32] = {};
olm::aes_encrypt_cbc(key, iv, input, sizeof(input), actual);
_olm_crypto_aes_encrypt_cbc(&key, &iv, input, sizeof(input), actual);
assert_equals(expected, actual, 32);
length = olm::aes_decrypt_cbc(key, iv, expected, sizeof(expected), actual);
length = _olm_crypto_aes_decrypt_cbc(&key, &iv, expected, sizeof(expected), actual);
assert_equals(std::size_t(16), length);
assert_equals(input, actual, length);

View file

@ -80,7 +80,6 @@ int main() {
assert_equals(pickle1, pickle2, pickle_length);
}
{
TestCase test_case("Group message send/receive");
@ -89,6 +88,7 @@ int main() {
"0123456789ABDEF0123456789ABCDEF"
"0123456789ABDEF0123456789ABCDEF"
"0123456789ABDEF0123456789ABCDEF"
"0123456789ABDEF0123456789ABCDEF"
"0123456789ABDEF0123456789ABCDEF";
@ -97,7 +97,7 @@ int main() {
uint8_t memory[size];
OlmOutboundGroupSession *session = olm_outbound_group_session(memory);
assert_equals((size_t)132,
assert_equals((size_t)160,
olm_init_outbound_group_session_random_length(session));
size_t res = olm_init_outbound_group_session(
@ -109,7 +109,6 @@ int main() {
uint8_t session_key[session_key_len];
olm_outbound_group_session_key(session, session_key, session_key_len);
/* encode the message */
uint8_t plaintext[] = "Message";
size_t plaintext_length = sizeof(plaintext) - 1;
@ -131,9 +130,29 @@ int main() {
olm_inbound_group_session(inbound_session_memory);
res = olm_init_inbound_group_session(
inbound_session, 0U, session_key, session_key_len);
inbound_session, session_key, session_key_len);
assert_equals((size_t)0, res);
/* Check the session ids */
size_t out_session_id_len = olm_outbound_group_session_id_length(session);
uint8_t out_session_id[out_session_id_len];
assert_equals(out_session_id_len, olm_outbound_group_session_id(
session, out_session_id, out_session_id_len
));
size_t in_session_id_len = olm_inbound_group_session_id_length(
inbound_session
);
uint8_t in_session_id[in_session_id_len];
assert_equals(in_session_id_len, olm_inbound_group_session_id(
inbound_session, in_session_id, in_session_id_len
));
assert_equals(in_session_id_len, out_session_id_len);
assert_equals(out_session_id, in_session_id, in_session_id_len);
/* decode the message */
/* olm_group_decrypt_max_plaintext_length destroys the input so we have to
@ -148,4 +167,74 @@ int main() {
assert_equals(plaintext, plaintext_buf, res);
}
{
TestCase test_case("Invalid signature group message");
uint8_t plaintext[] = "Message";
size_t plaintext_length = sizeof(plaintext) - 1;
uint8_t session_key[] =
"AgAAAAAwMTIzNDU2Nzg5QUJERUYwMTIzNDU2Nzg5QUJDREVGMDEyMzQ1Njc4OUFCREVGM"
"DEyMzQ1Njc4OUFCQ0RFRjAxMjM0NTY3ODlBQkRFRjAxMjM0NTY3ODlBQkNERUYwMTIzND"
"U2Nzg5QUJERUYwMTIzNDU2Nzg5QUJDREVGMDEyMztqJ7zOtqQtYqOo0CpvDXNlMhV3HeJ"
"DpjrASKGLWdop4lx1cSN3Xv1TgfLPW8rhGiW+hHiMxd36nRuxscNv9k4oJA/KP+o0mi1w"
"v44StrEJ1wwx9WZHBUIWkQbaBSuBDw";
uint8_t message[] =
"AwgAEhAcbh6UpbByoyZxufQ+h2B+8XHMjhR69G8nP4pNZGl/3QMgrzCZPmP+F2aPLyKPz"
"xRPBMUkeXRJ6Iqm5NeOdx2eERgTW7P20CM+lL3Xpk+ZUOOPvsSQNaAL";
size_t msglen = sizeof(message)-1;
/* build the inbound session */
size_t size = olm_inbound_group_session_size();
uint8_t inbound_session_memory[size];
OlmInboundGroupSession *inbound_session =
olm_inbound_group_session(inbound_session_memory);
size_t res = olm_init_inbound_group_session(
inbound_session, session_key, sizeof(session_key)-1
);
assert_equals((size_t)0, res);
/* decode the message */
/* olm_group_decrypt_max_plaintext_length destroys the input so we have to
copy it. */
uint8_t msgcopy[msglen];
memcpy(msgcopy, message, msglen);
size = olm_group_decrypt_max_plaintext_length(
inbound_session, msgcopy, msglen
);
memcpy(msgcopy, message, msglen);
uint8_t plaintext_buf[size];
res = olm_group_decrypt(
inbound_session, msgcopy, msglen, plaintext_buf, size
);
assert_equals(plaintext_length, res);
assert_equals(plaintext, plaintext_buf, res);
/* now twiddle the signature */
message[msglen-1] = 'E';
memcpy(msgcopy, message, msglen);
assert_equals(
size,
olm_group_decrypt_max_plaintext_length(
inbound_session, msgcopy, msglen
)
);
memcpy(msgcopy, message, msglen);
res = olm_group_decrypt(
inbound_session, msgcopy, msglen,
plaintext_buf, size
);
assert_equals((size_t)-1, res);
assert_equals(
std::string("BAD_SIGNATURE"),
std::string(olm_inbound_group_session_last_error(inbound_session))
);
}
}

View file

@ -67,8 +67,8 @@ assert_equals(message2, output, 35);
TestCase test_case("Group message encode test");
size_t length = _olm_encode_group_message_length(200, 10, 8);
size_t expected_length = 1 + (1+2) + (2+10) + 8;
size_t length = _olm_encode_group_message_length(200, 10, 8, 64);
size_t expected_length = 1 + (1+2) + (2+10) + 8 + 64;
assert_equals(expected_length, length);
uint8_t output[50];
@ -99,9 +99,10 @@ assert_equals(message2, output, 35);
"\x03"
"\x08\xC8\x01"
"\x12\x0A" "ciphertext"
"hmacsha2";
"hmacsha2"
"ed25519signature";
_olm_decode_group_message(message, sizeof(message)-1, 8, &results);
_olm_decode_group_message(message, sizeof(message)-1, 8, 16, &results);
assert_equals(std::uint8_t(3), results.version);
assert_equals(1, results.has_message_index);
assert_equals(std::uint32_t(200), results.message_index);

View file

@ -65,6 +65,33 @@ assert_equals(pickle1, pickle2, pickle_length);
}
{
TestCase test_case("Old account unpickle test");
// this uses the old pickle format, which did not use enough space
// for the Ed25519 key. We should reject it.
std::uint8_t pickle[] =
"x3h9er86ygvq56pM1yesdAxZou4ResPQC9Rszk/fhEL9JY/umtZ2N/foL/SUgVXS"
"v0IxHHZTafYjDdzJU9xr8dQeBoOTGfV9E/lCqDGBnIlu7SZndqjEKXtzGyQr4sP4"
"K/A/8TOu9iK2hDFszy6xETiousHnHgh2ZGbRUh4pQx+YMm8ZdNZeRnwFGLnrWyf9"
"O5TmXua1FcU";
std::uint8_t account_buffer[::olm_account_size()];
::OlmAccount *account = ::olm_account(account_buffer);
assert_equals(
std::size_t(-1),
::olm_unpickle_account(
account, "", 0, pickle, sizeof(pickle)-1
)
);
assert_equals(
std::string("BAD_LEGACY_ACCOUNT_PICKLE"),
std::string(::olm_account_last_error(account))
);
}
{ /** Pickle session test */
TestCase test_case("Pickle session test");

View file

@ -32,8 +32,8 @@ _olm_cipher_aes_sha_256 cipher0 = OLM_CIPHER_INIT_AES_SHA_256(message_info);
_olm_cipher *cipher = OLM_CIPHER_BASE(&cipher0);
std::uint8_t random_bytes[] = "0123456789ABDEF0123456789ABCDEF";
olm::Curve25519KeyPair alice_key;
olm::curve25519_generate_key(random_bytes, alice_key);
_olm_curve25519_key_pair alice_key;
_olm_crypto_curve25519_generate_key(random_bytes, &alice_key);
std::uint8_t shared_secret[] = "A secret";
@ -44,7 +44,7 @@ olm::Ratchet alice(kdf_info, cipher);
olm::Ratchet bob(kdf_info, cipher);
alice.initialise_as_alice(shared_secret, sizeof(shared_secret) - 1, alice_key);
bob.initialise_as_bob(shared_secret, sizeof(shared_secret) - 1, alice_key);
bob.initialise_as_bob(shared_secret, sizeof(shared_secret) - 1, alice_key.public_key);
std::uint8_t plaintext[] = "Message";
std::size_t plaintext_length = sizeof(plaintext) - 1;
@ -113,7 +113,7 @@ olm::Ratchet alice(kdf_info, cipher);
olm::Ratchet bob(kdf_info, cipher);
alice.initialise_as_alice(shared_secret, sizeof(shared_secret) - 1, alice_key);
bob.initialise_as_bob(shared_secret, sizeof(shared_secret) - 1, alice_key);
bob.initialise_as_bob(shared_secret, sizeof(shared_secret) - 1, alice_key.public_key);
std::uint8_t plaintext_1[] = "First Message";
std::size_t plaintext_1_length = sizeof(plaintext_1) - 1;
@ -185,7 +185,7 @@ olm::Ratchet alice(kdf_info, cipher);
olm::Ratchet bob(kdf_info, cipher);
alice.initialise_as_alice(shared_secret, sizeof(shared_secret) - 1, alice_key);
bob.initialise_as_bob(shared_secret, sizeof(shared_secret) - 1, alice_key);
bob.initialise_as_bob(shared_secret, sizeof(shared_secret) - 1, alice_key.public_key);
std::uint8_t plaintext[] = "These 15 bytes";
assert_equals(std::size_t(15), sizeof(plaintext));

View file

@ -33,12 +33,12 @@ void check_session(const olm::Session &session) {
assert_equals(
decode_hex("f77a03eaa9b301fa7d2a5aa6b50286906de12cc96044f526dbbcb12839ad7003"),
session.ratchet.sender_chain[0].ratchet_key.public_key, 32
session.ratchet.sender_chain[0].ratchet_key.public_key.public_key, 32
);
assert_equals(
decode_hex("d945c6ed4c7c277117adf11fb133a7936d287afe97c0b3ac989644b4490d4f31"),
session.ratchet.sender_chain[0].ratchet_key.private_key, 32
session.ratchet.sender_chain[0].ratchet_key.private_key.private_key, 32
);
assert_equals(