Merge branch 'master' into logging_enabled
This commit is contained in:
commit
9001d3520a
46 changed files with 1175 additions and 751 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,2 +1,6 @@
|
||||||
build
|
/build
|
||||||
|
/CHANGELOG.html
|
||||||
|
/docs/olm.html
|
||||||
/olm-*.tgz
|
/olm-*.tgz
|
||||||
|
/README.html
|
||||||
|
/tracing/README.html
|
69
CHANGELOG.rst
Normal file
69
CHANGELOG.rst
Normal 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).
|
49
Makefile
49
Makefile
|
@ -1,5 +1,10 @@
|
||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
MAJOR := 1
|
||||||
|
MINOR := 3
|
||||||
|
PATCH := 0
|
||||||
|
VERSION := $(MAJOR).$(MINOR).$(PATCH)
|
||||||
|
PREFIX ?= /usr/local
|
||||||
BUILD_DIR := build
|
BUILD_DIR := build
|
||||||
RELEASE_OPTIMIZE_FLAGS ?= -g -O3
|
RELEASE_OPTIMIZE_FLAGS ?= -g -O3
|
||||||
DEBUG_OPTIMIZE_FLAGS ?= -g -O0
|
DEBUG_OPTIMIZE_FLAGS ?= -g -O0
|
||||||
|
@ -9,8 +14,9 @@ CC = gcc
|
||||||
EMCC = emcc
|
EMCC = emcc
|
||||||
AFL_CC = afl-gcc
|
AFL_CC = afl-gcc
|
||||||
AFL_CXX = afl-g++
|
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_TARGET := javascript/olm.js
|
||||||
|
|
||||||
JS_EXPORTED_FUNCTIONS := javascript/exported_functions.json
|
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 \
|
JS_POST := javascript/olm_outbound_group_session.js \
|
||||||
javascript/olm_inbound_group_session.js \
|
javascript/olm_inbound_group_session.js \
|
||||||
javascript/olm_post.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
|
# we rely on <stdint.h>, which was introduced in C99
|
||||||
CFLAGS += -Wall -Werror -std=c99 -fPIC
|
CFLAGS += -Wall -Werror -std=c99 -fPIC
|
||||||
CXXFLAGS += -Wall -Werror -std=c++11 -fPIC
|
CXXFLAGS += -Wall -Werror -std=c++11 -fPIC
|
||||||
|
@ -92,16 +105,20 @@ lib: $(RELEASE_TARGET)
|
||||||
|
|
||||||
$(RELEASE_TARGET): $(RELEASE_OBJECTS)
|
$(RELEASE_TARGET): $(RELEASE_OBJECTS)
|
||||||
$(CXX) $(LDFLAGS) --shared -fPIC \
|
$(CXX) $(LDFLAGS) --shared -fPIC \
|
||||||
|
-Wl,-soname,libolm.so.$(MAJOR) \
|
||||||
-Wl,--version-script,version_script.ver \
|
-Wl,--version-script,version_script.ver \
|
||||||
$(OUTPUT_OPTION) $(RELEASE_OBJECTS)
|
$(OUTPUT_OPTION) $(RELEASE_OBJECTS)
|
||||||
|
ln -sf libolm.so.$(VERSION) $(BUILD_DIR)/libolm.so.$(MAJOR)
|
||||||
|
|
||||||
debug: $(DEBUG_TARGET)
|
debug: $(DEBUG_TARGET)
|
||||||
.PHONY: debug
|
.PHONY: debug
|
||||||
|
|
||||||
$(DEBUG_TARGET): $(DEBUG_OBJECTS)
|
$(DEBUG_TARGET): $(DEBUG_OBJECTS)
|
||||||
$(CXX) $(LDFLAGS) --shared -fPIC \
|
$(CXX) $(LDFLAGS) --shared -fPIC \
|
||||||
|
-Wl,-soname,libolm_debug.so.$(MAJOR) \
|
||||||
-Wl,--version-script,version_script.ver \
|
-Wl,--version-script,version_script.ver \
|
||||||
$(OUTPUT_OPTION) $(DEBUG_OBJECTS)
|
$(OUTPUT_OPTION) $(DEBUG_OBJECTS)
|
||||||
|
ln -sf libolm_debug.so.$(VERSION) $(BUILD_DIR)/libolm_debug.so.$(MAJOR)
|
||||||
|
|
||||||
js: $(JS_TARGET)
|
js: $(JS_TARGET)
|
||||||
.PHONY: js
|
.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
|
perl -MJSON -ne '$$f{"_$$1"}=1 if /(olm_[^( ]*)\(/; END { @f=sort keys %f; print encode_json \@f }' $^ > $@.tmp
|
||||||
mv $@.tmp $@
|
mv $@.tmp $@
|
||||||
|
|
||||||
all: test js lib debug
|
all: test js lib debug doc
|
||||||
.PHONY: all
|
.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:;
|
clean:;
|
||||||
rm -rf $(BUILD_DIR)
|
rm -rf $(BUILD_DIR) $(DOCS)
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
||||||
|
doc: $(DOCS)
|
||||||
|
.PHONY: doc
|
||||||
|
|
||||||
### rules for building objects
|
### rules for building objects
|
||||||
$(BUILD_DIR)/release/%.o: %.c
|
$(BUILD_DIR)/release/%.o: %.c
|
||||||
mkdir -p $(dir $@)
|
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)
|
$(BUILD_DIR)/fuzzers/debug_%: fuzzers/fuzz_%.cpp $(DEBUG_OBJECTS)
|
||||||
$(LINK.cc) $< $(DEBUG_OBJECTS) $(LOADLIBES) $(LDLIBS) -o $@
|
$(LINK.cc) $< $(DEBUG_OBJECTS) $(LOADLIBES) $(LDLIBS) -o $@
|
||||||
|
|
||||||
|
%.html: %.rst
|
||||||
|
rst2html $< $@
|
||||||
|
|
||||||
### dependencies
|
### dependencies
|
||||||
|
|
||||||
-include $(RELEASE_OBJECTS:.o=.d)
|
-include $(RELEASE_OBJECTS:.o=.d)
|
||||||
|
|
24
README.rst
24
README.rst
|
@ -1,8 +1,9 @@
|
||||||
Olm
|
Olm
|
||||||
===
|
===
|
||||||
|
|
||||||
An implementation of the cryptographic ratchet described by
|
An implementation of the Double Ratchet cryptographic ratchet described by
|
||||||
https://github.com/trevp/axolotl/wiki, written in C++11 and exposed as a C API
|
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
|
The specification of the Olm ratchet can be found in docs/olm.rst or
|
||||||
https://matrix.org/docs/spec/olm.html
|
https://matrix.org/docs/spec/olm.html
|
||||||
|
@ -27,15 +28,28 @@ To build the javascript bindings, install emscripten from http://kripken.github.
|
||||||
.. code:: bash
|
.. code:: bash
|
||||||
|
|
||||||
make js
|
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
|
.. 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
|
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
|
Design
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#define OLM_ACCOUNT_HH_
|
#define OLM_ACCOUNT_HH_
|
||||||
|
|
||||||
#include "olm/list.hh"
|
#include "olm/list.hh"
|
||||||
#include "olm/crypto.hh"
|
#include "olm/crypto.h"
|
||||||
#include "olm/error.h"
|
#include "olm/error.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
@ -25,14 +25,14 @@ namespace olm {
|
||||||
|
|
||||||
|
|
||||||
struct IdentityKeys {
|
struct IdentityKeys {
|
||||||
Ed25519KeyPair ed25519_key;
|
_olm_ed25519_key_pair ed25519_key;
|
||||||
Curve25519KeyPair curve25519_key;
|
_olm_curve25519_key_pair curve25519_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OneTimeKey {
|
struct OneTimeKey {
|
||||||
std::uint32_t id;
|
std::uint32_t id;
|
||||||
bool published;
|
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 */
|
/** Lookup a one time key with the given public key */
|
||||||
OneTimeKey const * lookup_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 */
|
/** Remove a one time key with the given public key */
|
||||||
std::size_t remove_key(
|
std::size_t remove_key(
|
||||||
Curve25519PublicKey const & public_key
|
_olm_curve25519_public_key const & public_key
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,100 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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
|
/** length of a public or private Curve25519 key */
|
||||||
* bytes long. */
|
#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(
|
void _olm_crypto_sha256(
|
||||||
uint8_t const * input, size_t input_length,
|
uint8_t const * input, size_t input_length,
|
||||||
uint8_t * output
|
uint8_t * output
|
||||||
|
@ -39,7 +129,7 @@ void _olm_crypto_sha256(
|
||||||
/** HMAC: Keyed-Hashing for Message Authentication
|
/** HMAC: Keyed-Hashing for Message Authentication
|
||||||
* http://tools.ietf.org/html/rfc2104
|
* http://tools.ietf.org/html/rfc2104
|
||||||
* Computes HMAC-SHA-256 of the input for the key. The output buffer must
|
* 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(
|
void _olm_crypto_hmac_sha256(
|
||||||
uint8_t const * key, size_t key_length,
|
uint8_t const * key, size_t key_length,
|
||||||
uint8_t const * input, size_t input_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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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_ */
|
|
|
@ -39,6 +39,18 @@ enum OlmErrorCode {
|
||||||
* known session key.
|
* 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
|
/* remember to update the list of string constants in error.c when updating
|
||||||
* this list. */
|
* this list. */
|
||||||
};
|
};
|
||||||
|
|
|
@ -95,9 +95,7 @@ size_t olm_unpickle_inbound_group_session(
|
||||||
*/
|
*/
|
||||||
size_t olm_init_inbound_group_session(
|
size_t olm_init_inbound_group_session(
|
||||||
OlmInboundGroupSession *session,
|
OlmInboundGroupSession *session,
|
||||||
uint32_t message_index,
|
/* base64-encoded keys */
|
||||||
|
|
||||||
/* base64-encoded key */
|
|
||||||
uint8_t const * session_key, size_t session_key_length
|
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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,7 +37,8 @@ extern "C" {
|
||||||
size_t _olm_encode_group_message_length(
|
size_t _olm_encode_group_message_length(
|
||||||
uint32_t chain_index,
|
uint32_t chain_index,
|
||||||
size_t ciphertext_length,
|
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
|
* output: where to write the output. Should be at least
|
||||||
* olm_encode_group_message_length() bytes long.
|
* olm_encode_group_message_length() bytes long.
|
||||||
* ciphertext_ptr: returns the address that the ciphertext
|
* 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.
|
* Returns the size of the message, up to the MAC.
|
||||||
*/
|
*/
|
||||||
|
@ -76,7 +78,7 @@ struct _OlmDecodeGroupMessageResults {
|
||||||
*/
|
*/
|
||||||
void _olm_decode_group_message(
|
void _olm_decode_group_message(
|
||||||
const uint8_t *input, size_t input_length,
|
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 */
|
/* output structure: updated with results */
|
||||||
struct _OlmDecodeGroupMessageResults *results
|
struct _OlmDecodeGroupMessageResults *results
|
||||||
|
|
|
@ -33,6 +33,11 @@ typedef struct OlmAccount OlmAccount;
|
||||||
typedef struct OlmSession OlmSession;
|
typedef struct OlmSession OlmSession;
|
||||||
typedef struct OlmUtility OlmUtility;
|
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 */
|
/** The size of an account object in bytes */
|
||||||
size_t olm_account_size();
|
size_t olm_account_size();
|
||||||
|
|
||||||
|
@ -295,6 +300,10 @@ size_t olm_session_id(
|
||||||
void * id, size_t id_length
|
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
|
/** 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
|
* if multiple messages are sent to this account before this account sends a
|
||||||
* message in reply. Returns olm_error() on failure. If the base64
|
* message in reply. Returns olm_error() on failure. If the base64
|
||||||
|
|
|
@ -160,7 +160,7 @@ size_t olm_outbound_group_session_key_length(
|
||||||
/**
|
/**
|
||||||
* Get the base64-encoded current ratchet key for this session.
|
* 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.
|
* ratchet key that will be used for the next message.
|
||||||
*
|
*
|
||||||
* Returns the length of the ratchet key on success or olm_error() on
|
* Returns the length of the ratchet key on success or olm_error() on
|
||||||
|
|
|
@ -21,6 +21,10 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct _olm_ed25519_public_key;
|
||||||
|
struct _olm_ed25519_key_pair;
|
||||||
|
|
||||||
|
|
||||||
#define _olm_pickle_uint32_length(value) 4
|
#define _olm_pickle_uint32_length(value) 4
|
||||||
uint8_t * _olm_pickle_uint32(uint8_t * pos, uint32_t value);
|
uint8_t * _olm_pickle_uint32(uint8_t * pos, uint32_t value);
|
||||||
uint8_t const * _olm_unpickle_uint32(
|
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);
|
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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#define OLM_PICKLE_HH_
|
#define OLM_PICKLE_HH_
|
||||||
|
|
||||||
#include "olm/list.hh"
|
#include "olm/list.hh"
|
||||||
#include "olm/crypto.hh"
|
#include "olm/crypto.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
@ -109,70 +109,36 @@ std::uint8_t const * unpickle_bytes(
|
||||||
|
|
||||||
|
|
||||||
std::size_t pickle_length(
|
std::size_t pickle_length(
|
||||||
const Curve25519PublicKey & value
|
const _olm_curve25519_public_key & value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
std::uint8_t * pickle(
|
std::uint8_t * pickle(
|
||||||
std::uint8_t * pos,
|
std::uint8_t * pos,
|
||||||
const Curve25519PublicKey & value
|
const _olm_curve25519_public_key & value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
std::uint8_t const * unpickle(
|
std::uint8_t const * unpickle(
|
||||||
std::uint8_t const * pos, std::uint8_t const * end,
|
std::uint8_t const * pos, std::uint8_t const * end,
|
||||||
Curve25519PublicKey & value
|
_olm_curve25519_public_key & value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
std::size_t pickle_length(
|
std::size_t pickle_length(
|
||||||
const Curve25519KeyPair & value
|
const _olm_curve25519_key_pair & value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
std::uint8_t * pickle(
|
std::uint8_t * pickle(
|
||||||
std::uint8_t * pos,
|
std::uint8_t * pos,
|
||||||
const Curve25519KeyPair & value
|
const _olm_curve25519_key_pair & value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
std::uint8_t const * unpickle(
|
std::uint8_t const * unpickle(
|
||||||
std::uint8_t const * pos, std::uint8_t const * end,
|
std::uint8_t const * pos, std::uint8_t const * end,
|
||||||
Curve25519KeyPair & value
|
_olm_curve25519_key_pair & 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
|
|
||||||
);
|
);
|
||||||
|
|
||||||
} // namespace olm
|
} // namespace olm
|
||||||
|
|
|
@ -13,7 +13,9 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "olm/crypto.hh"
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "olm/crypto.h"
|
||||||
#include "olm/list.hh"
|
#include "olm/list.hh"
|
||||||
#include "olm/error.h"
|
#include "olm/error.h"
|
||||||
|
|
||||||
|
@ -21,8 +23,13 @@ struct _olm_cipher;
|
||||||
|
|
||||||
namespace olm {
|
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 {
|
struct ChainKey {
|
||||||
std::uint32_t index;
|
std::uint32_t index;
|
||||||
|
@ -36,19 +43,19 @@ struct MessageKey {
|
||||||
|
|
||||||
|
|
||||||
struct SenderChain {
|
struct SenderChain {
|
||||||
Curve25519KeyPair ratchet_key;
|
_olm_curve25519_key_pair ratchet_key;
|
||||||
ChainKey chain_key;
|
ChainKey chain_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct ReceiverChain {
|
struct ReceiverChain {
|
||||||
Curve25519PublicKey ratchet_key;
|
_olm_curve25519_public_key ratchet_key;
|
||||||
ChainKey chain_key;
|
ChainKey chain_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct SkippedMessageKey {
|
struct SkippedMessageKey {
|
||||||
Curve25519PublicKey ratchet_key;
|
_olm_curve25519_public_key ratchet_key;
|
||||||
MessageKey message_key;
|
MessageKey message_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -113,14 +120,14 @@ struct Ratchet {
|
||||||
* remote's first ratchet key */
|
* remote's first ratchet key */
|
||||||
void initialise_as_bob(
|
void initialise_as_bob(
|
||||||
std::uint8_t const * shared_secret, std::size_t shared_secret_length,
|
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
|
/** Initialise the session using a shared secret and the public/private key
|
||||||
* pair for the first ratchet key */
|
* pair for the first ratchet key */
|
||||||
void initialise_as_alice(
|
void initialise_as_alice(
|
||||||
std::uint8_t const * shared_secret, std::size_t shared_secret_length,
|
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
|
/** The number of bytes of output the encrypt method will write for
|
||||||
|
|
|
@ -35,9 +35,9 @@ struct Session {
|
||||||
|
|
||||||
bool received_message;
|
bool received_message;
|
||||||
|
|
||||||
Curve25519PublicKey alice_identity_key;
|
_olm_curve25519_public_key alice_identity_key;
|
||||||
Curve25519PublicKey alice_base_key;
|
_olm_curve25519_public_key alice_base_key;
|
||||||
Curve25519PublicKey bob_one_time_key;
|
_olm_curve25519_public_key bob_one_time_key;
|
||||||
|
|
||||||
/** The number of random bytes that are needed to create a new outbound
|
/** 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. */
|
* 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. */
|
* NOT_ENOUGH_RANDOM if the number of random bytes was too small. */
|
||||||
std::size_t new_outbound_session(
|
std::size_t new_outbound_session(
|
||||||
Account const & local_account,
|
Account const & local_account,
|
||||||
Curve25519PublicKey const & identity_key,
|
_olm_curve25519_public_key const & identity_key,
|
||||||
Curve25519PublicKey const & one_time_key,
|
_olm_curve25519_public_key const & one_time_key,
|
||||||
std::uint8_t const * random, std::size_t random_length
|
std::uint8_t const * random, std::size_t random_length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ struct Session {
|
||||||
* the message headers could not be decoded. */
|
* the message headers could not be decoded. */
|
||||||
std::size_t new_inbound_session(
|
std::size_t new_inbound_session(
|
||||||
Account & local_account,
|
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
|
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.
|
* session does not match or the pre-key message could not be decoded.
|
||||||
*/
|
*/
|
||||||
bool matches_inbound_session(
|
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
|
std::uint8_t const * pre_key_message, std::size_t message_length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,9 @@
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace olm {
|
struct _olm_ed25519_public_key;
|
||||||
|
|
||||||
struct Ed25519PublicKey;
|
namespace olm {
|
||||||
|
|
||||||
struct Utility {
|
struct Utility {
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ struct Utility {
|
||||||
* last_error will be set with an error code. If the signature was too short
|
* 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. */
|
* or was not a valid signature then last_error will be BAD_MESSAGE_MAC. */
|
||||||
std::size_t ed25519_verify(
|
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 * message, std::size_t message_length,
|
||||||
std::uint8_t const * signature, std::size_t signature_length
|
std::uint8_t const * signature, std::size_t signature_length
|
||||||
);
|
);
|
||||||
|
|
|
@ -261,7 +261,7 @@ DemoUser.prototype.receiveOneToOne = function(jsonpacket) {
|
||||||
if (!self.peerGroupSessions[sender] ||
|
if (!self.peerGroupSessions[sender] ||
|
||||||
!self.peerGroupSessions[sender][body.session_id]) {
|
!self.peerGroupSessions[sender][body.session_id]) {
|
||||||
self.createInboundSession(
|
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
|
* add a task to create an inbound group session
|
||||||
*/
|
*/
|
||||||
DemoUser.prototype.createInboundSession = function(
|
DemoUser.prototype.createInboundSession = function(
|
||||||
peer_id, session_id, message_index, session_key, callback
|
peer_id, session_id, session_key, callback
|
||||||
) {
|
) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.addTask("init inbound session", function(done) {
|
this.addTask("init inbound session", function(done) {
|
||||||
session = new Olm.InboundGroupSession();
|
session = new Olm.InboundGroupSession();
|
||||||
session.create(message_index, session_key);
|
session.create(session_key);
|
||||||
if (!self.peerGroupSessions[peer_id]) {
|
if (!self.peerGroupSessions[peer_id]) {
|
||||||
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;
|
self.peerGroupSessions[peer_id][session_id] = session;
|
||||||
done(session);
|
done(session);
|
||||||
}, callback);
|
}, callback);
|
||||||
|
|
|
@ -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() {
|
function InboundGroupSession() {
|
||||||
var size = Module['_olm_inbound_group_session_size']();
|
var size = Module['_olm_inbound_group_session_size']();
|
||||||
this.buf = malloc(size);
|
this.buf = malloc(size);
|
||||||
|
@ -28,11 +34,11 @@ InboundGroupSession.prototype['pickle'] = restore_stack(function(key) {
|
||||||
Module['_olm_pickle_inbound_group_session_length']
|
Module['_olm_pickle_inbound_group_session_length']
|
||||||
)(this.ptr);
|
)(this.ptr);
|
||||||
var key_buffer = stack(key_array);
|
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'])(
|
inbound_group_session_method(Module['_olm_pickle_inbound_group_session'])(
|
||||||
this.ptr, key_buffer, key_array.length, pickle_buffer, pickle_length
|
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) {
|
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_array = array_from_string(session_key);
|
||||||
var key_buffer = stack(key_array);
|
var key_buffer = stack(key_array);
|
||||||
|
|
||||||
inbound_group_session_method(Module['_olm_init_inbound_group_session'])(
|
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_array = array_from_string(message);
|
||||||
var message_buffer = stack(message_array);
|
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']
|
Module['_olm_group_decrypt_max_plaintext_length']
|
||||||
)(this.ptr, message_buffer, message_array.length);
|
)(this.ptr, message_buffer, message_array.length);
|
||||||
// caculating the length destroys the input buffer.
|
// caculating the length destroys the input buffer.
|
||||||
// So we copy the array to a new buffer
|
// So we copy the array to a new buffer
|
||||||
var message_buffer = stack(message_array);
|
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_group_decrypt"])(
|
var plaintext_length = inbound_group_session_method(Module["_olm_group_decrypt"])(
|
||||||
this.ptr,
|
this.ptr,
|
||||||
message_buffer, message_array.length,
|
message_buffer, message_array.length,
|
||||||
plaintext_buffer, max_plaintext_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;
|
olm_exports['InboundGroupSession'] = InboundGroupSession;
|
||||||
|
|
|
@ -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() {
|
function OutboundGroupSession() {
|
||||||
var size = Module['_olm_outbound_group_session_size']();
|
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']
|
Module['_olm_pickle_outbound_group_session_length']
|
||||||
)(this.ptr);
|
)(this.ptr);
|
||||||
var key_buffer = stack(key_array);
|
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'])(
|
outbound_group_session_method(Module['_olm_pickle_outbound_group_session'])(
|
||||||
this.ptr, key_buffer, key_array.length, pickle_buffer, pickle_length
|
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) {
|
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) {
|
OutboundGroupSession.prototype['create'] = restore_stack(function() {
|
||||||
var random_length = session_method(
|
var random_length = outbound_group_session_method(
|
||||||
Module['_olm_init_outbound_group_session_random_length']
|
Module['_olm_init_outbound_group_session_random_length']
|
||||||
)(this.ptr);
|
)(this.ptr);
|
||||||
var random = random_stack(random_length);
|
var random = random_stack(random_length);
|
||||||
|
@ -63,35 +69,35 @@ OutboundGroupSession.prototype['encrypt'] = restore_stack(function(plaintext) {
|
||||||
Module['_olm_group_encrypt_message_length']
|
Module['_olm_group_encrypt_message_length']
|
||||||
)(this.ptr, plaintext_array.length);
|
)(this.ptr, plaintext_array.length);
|
||||||
var plaintext_buffer = stack(plaintext_array);
|
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'])(
|
outbound_group_session_method(Module['_olm_group_encrypt'])(
|
||||||
this.ptr,
|
this.ptr,
|
||||||
plaintext_buffer, plaintext_array.length,
|
plaintext_buffer, plaintext_array.length,
|
||||||
message_buffer, message_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(
|
var length = outbound_group_session_method(
|
||||||
Module['_olm_outbound_group_session_id_length']
|
Module['_olm_outbound_group_session_id_length']
|
||||||
)(this.ptr);
|
)(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'])(
|
outbound_group_session_method(Module['_olm_outbound_group_session_id'])(
|
||||||
this.ptr, session_id, length
|
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(
|
var key_length = outbound_group_session_method(
|
||||||
Module['_olm_outbound_group_session_key_length']
|
Module['_olm_outbound_group_session_key_length']
|
||||||
)(this.ptr);
|
)(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'])(
|
outbound_group_session_method(Module['_olm_outbound_group_session_key'])(
|
||||||
this.ptr, key, key_length
|
this.ptr, key, key_length
|
||||||
);
|
);
|
||||||
return Pointer_stringify(key, key_length);
|
return Pointer_stringify(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
OutboundGroupSession.prototype['message_index'] = function() {
|
OutboundGroupSession.prototype['message_index'] = function() {
|
||||||
|
|
|
@ -4,6 +4,16 @@ var free = Module['_free'];
|
||||||
var Pointer_stringify = Module['Pointer_stringify'];
|
var Pointer_stringify = Module['Pointer_stringify'];
|
||||||
var OLM_ERROR = Module['_olm_error']();
|
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) {
|
function stack(size_or_array) {
|
||||||
return Module['allocate'](size_or_array, 'i8', Module['ALLOC_STACK']);
|
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(
|
var keys_length = account_method(
|
||||||
Module['_olm_account_identity_keys_length']
|
Module['_olm_account_identity_keys_length']
|
||||||
)(this.ptr);
|
)(this.ptr);
|
||||||
var keys = stack(keys_length);
|
var keys = stack(keys_length + NULL_BYTE_PADDING_LENGTH);
|
||||||
account_method(Module['_olm_account_identity_keys'])(
|
account_method(Module['_olm_account_identity_keys'])(
|
||||||
this.ptr, keys, keys_length
|
this.ptr, keys, keys_length
|
||||||
);
|
);
|
||||||
return Pointer_stringify(keys, keys_length);
|
return Pointer_stringify(keys);
|
||||||
});
|
});
|
||||||
|
|
||||||
Account.prototype['sign'] = restore_stack(function(message) {
|
Account.prototype['sign'] = restore_stack(function(message) {
|
||||||
|
@ -81,24 +91,24 @@ Account.prototype['sign'] = restore_stack(function(message) {
|
||||||
)(this.ptr);
|
)(this.ptr);
|
||||||
var message_array = array_from_string(message);
|
var message_array = array_from_string(message);
|
||||||
var message_buffer = stack(message_array);
|
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'])(
|
account_method(Module['_olm_account_sign'])(
|
||||||
this.ptr,
|
this.ptr,
|
||||||
message_buffer, message_array.length,
|
message_buffer, message_array.length,
|
||||||
signature_buffer, signature_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() {
|
Account.prototype['one_time_keys'] = restore_stack(function() {
|
||||||
var keys_length = account_method(
|
var keys_length = account_method(
|
||||||
Module['_olm_account_one_time_keys_length']
|
Module['_olm_account_one_time_keys_length']
|
||||||
)(this.ptr);
|
)(this.ptr);
|
||||||
var keys = stack(keys_length);
|
var keys = stack(keys_length + NULL_BYTE_PADDING_LENGTH);
|
||||||
account_method(Module['_olm_account_one_time_keys'])(
|
account_method(Module['_olm_account_one_time_keys'])(
|
||||||
this.ptr, keys, keys_length
|
this.ptr, keys, keys_length
|
||||||
);
|
);
|
||||||
return Pointer_stringify(keys, keys_length);
|
return Pointer_stringify(keys);
|
||||||
});
|
});
|
||||||
|
|
||||||
Account.prototype['mark_keys_as_published'] = restore_stack(function() {
|
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']
|
Module['_olm_pickle_account_length']
|
||||||
)(this.ptr);
|
)(this.ptr);
|
||||||
var key_buffer = stack(key_array);
|
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'])(
|
account_method(Module['_olm_pickle_account'])(
|
||||||
this.ptr, key_buffer, key_array.length, pickle_buffer, pickle_length
|
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) {
|
Account.prototype['unpickle'] = restore_stack(function(key, pickle) {
|
||||||
|
@ -183,11 +193,11 @@ Session.prototype['pickle'] = restore_stack(function(key) {
|
||||||
Module['_olm_pickle_session_length']
|
Module['_olm_pickle_session_length']
|
||||||
)(this.ptr);
|
)(this.ptr);
|
||||||
var key_buffer = stack(key_array);
|
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'])(
|
session_method(Module['_olm_pickle_session'])(
|
||||||
this.ptr, key_buffer, key_array.length, pickle_buffer, pickle_length
|
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) {
|
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() {
|
Session.prototype['session_id'] = restore_stack(function() {
|
||||||
var id_length = session_method(Module['_olm_session_id_length'])(this.ptr);
|
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'])(
|
session_method(Module['_olm_session_id'])(
|
||||||
this.ptr, id_buffer, id_length
|
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(
|
Session.prototype['matches_inbound'] = restore_stack(function(
|
||||||
one_time_key_message
|
one_time_key_message
|
||||||
) {
|
) {
|
||||||
|
@ -292,7 +309,7 @@ Session.prototype['encrypt'] = restore_stack(function(
|
||||||
)(this.ptr, plaintext_array.length);
|
)(this.ptr, plaintext_array.length);
|
||||||
var random = random_stack(random_length);
|
var random = random_stack(random_length);
|
||||||
var plaintext_buffer = stack(plaintext_array);
|
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'])(
|
session_method(Module['_olm_encrypt'])(
|
||||||
this.ptr,
|
this.ptr,
|
||||||
plaintext_buffer, plaintext_array.length,
|
plaintext_buffer, plaintext_array.length,
|
||||||
|
@ -301,7 +318,7 @@ Session.prototype['encrypt'] = restore_stack(function(
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
"type": message_type,
|
"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.
|
// caculating the length destroys the input buffer.
|
||||||
// So we copy the array to a new buffer
|
// So we copy the array to a new buffer
|
||||||
var message_buffer = stack(message_array);
|
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"])(
|
var plaintext_length = session_method(Module["_olm_decrypt"])(
|
||||||
this.ptr, message_type,
|
this.ptr, message_type,
|
||||||
message_buffer, message.length,
|
message_buffer, message.length,
|
||||||
plaintext_buffer, max_plaintext_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() {
|
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 output_length = utility_method(Module['_olm_sha256_length'])(this.ptr);
|
||||||
var input_array = array_from_string(input);
|
var input_array = array_from_string(input);
|
||||||
var input_buffer = stack(input_array);
|
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'])(
|
utility_method(Module['_olm_sha2516'])(
|
||||||
this.ptr,
|
this.ptr,
|
||||||
input_buffer, input_array.length(),
|
input_buffer, input_array.length(),
|
||||||
output_buffer, output_length
|
output_buffer, output_length
|
||||||
);
|
);
|
||||||
return Pointer_stringify(output_buffer, output_length);
|
return Pointer_stringify(output_buffer);
|
||||||
});
|
});
|
||||||
|
|
||||||
Utility.prototype['ed25519_verify'] = restore_stack(function(
|
Utility.prototype['ed25519_verify'] = restore_stack(function(
|
||||||
|
@ -384,4 +411,14 @@ olm_exports["Session"] = Session;
|
||||||
olm_exports["Utility"] = Utility;
|
olm_exports["Utility"] = Utility;
|
||||||
|
|
||||||
olm_exports['set_log_level'] = Module['_olm_set_log_level'];
|
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'),
|
||||||
|
];
|
||||||
|
});
|
||||||
}();
|
}();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "olm",
|
"name": "olm",
|
||||||
"version": "0.1.0",
|
"version": "1.3.0",
|
||||||
"description": "An implementation of a well known cryptographic ratchet",
|
"description": "An implementation of the Double Ratchet cryptographic ratchet",
|
||||||
"main": "olm.js",
|
"main": "olm.js",
|
||||||
"files": [
|
"files": [
|
||||||
"olm.js",
|
"olm.js",
|
||||||
|
|
|
@ -3,7 +3,12 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
make clean
|
make clean
|
||||||
|
rm olm-*.tgz
|
||||||
|
|
||||||
make lib
|
make lib
|
||||||
make test
|
make test
|
||||||
|
|
||||||
./python/test_olm.sh
|
./python/test_olm.sh
|
||||||
|
|
||||||
|
. ~/.emsdk_set_env.sh
|
||||||
|
make js
|
||||||
|
npm pack javascript
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -7,7 +7,7 @@ def read_random(n):
|
||||||
return f.read(n)
|
return f.read(n)
|
||||||
|
|
||||||
lib = cdll.LoadLibrary(os.path.join(
|
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 = []
|
lib.olm_error.argtypes = []
|
||||||
|
|
|
@ -33,7 +33,7 @@ inbound_group_session_function(
|
||||||
)
|
)
|
||||||
|
|
||||||
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(
|
inbound_group_session_function(
|
||||||
|
@ -45,6 +45,9 @@ inbound_group_session_function(
|
||||||
c_void_p, c_size_t, # plaintext
|
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):
|
class InboundGroupSession(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.buf = create_string_buffer(lib.olm_inbound_group_session_size())
|
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)
|
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)
|
key_buffer = create_string_buffer(session_key)
|
||||||
lib.olm_init_inbound_group_session(
|
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):
|
def decrypt(self, message):
|
||||||
|
@ -84,3 +87,9 @@ class InboundGroupSession(object):
|
||||||
plaintext_buffer, max_plaintext_length
|
plaintext_buffer, max_plaintext_length
|
||||||
)
|
)
|
||||||
return plaintext_buffer.raw[: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
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "olm/account.hh"
|
#include "olm/account.hh"
|
||||||
#include "olm/base64.hh"
|
#include "olm/base64.hh"
|
||||||
#include "olm/logging.h"
|
#include "olm/logging.h"
|
||||||
|
#include "olm/pickle.h"
|
||||||
#include "olm/pickle.hh"
|
#include "olm/pickle.hh"
|
||||||
#include "olm/memory.hh"
|
#include "olm/memory.hh"
|
||||||
|
|
||||||
|
@ -27,10 +28,10 @@ olm::Account::Account(
|
||||||
|
|
||||||
|
|
||||||
olm::OneTimeKey const * olm::Account::lookup_key(
|
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) {
|
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;
|
return &key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,11 +39,11 @@ olm::OneTimeKey const * olm::Account::lookup_key(
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t olm::Account::remove_key(
|
std::size_t olm::Account::remove_key(
|
||||||
olm::Curve25519PublicKey const & public_key
|
_olm_curve25519_public_key const & public_key
|
||||||
) {
|
) {
|
||||||
OneTimeKey * i;
|
OneTimeKey * i;
|
||||||
for (i = one_time_keys.begin(); i != one_time_keys.end(); ++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;
|
std::uint32_t id = i->id;
|
||||||
one_time_keys.erase(i);
|
one_time_keys.erase(i);
|
||||||
olm_logf(OLM_LOG_INFO, LOG_CATEGORY, "removed key id %i", id);
|
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() {
|
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(
|
std::size_t olm::Account::new_account(
|
||||||
|
@ -65,9 +66,9 @@ std::size_t olm::Account::new_account(
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
olm::ed25519_generate_key(random, identity_keys.ed25519_key);
|
_olm_crypto_ed25519_generate_key(random, &identity_keys.ed25519_key);
|
||||||
random += KEY_LENGTH;
|
random += ED25519_RANDOM_LENGTH;
|
||||||
olm::curve25519_generate_key(random, identity_keys.curve25519_key);
|
_olm_crypto_curve25519_generate_key(random, &identity_keys.curve25519_key);
|
||||||
|
|
||||||
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY, "Created new account");
|
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 = write_string(pos, KEY_JSON_CURVE25519);
|
||||||
*(pos++) = '\"';
|
*(pos++) = '\"';
|
||||||
pos = olm::encode_base64(
|
pos = olm::encode_base64(
|
||||||
identity_keys.curve25519_key.public_key,
|
identity_keys.curve25519_key.public_key.public_key,
|
||||||
sizeof(identity_keys.curve25519_key.public_key),
|
sizeof(identity_keys.curve25519_key.public_key.public_key),
|
||||||
pos
|
pos
|
||||||
);
|
);
|
||||||
*(pos++) = '\"'; *(pos++) = ',';
|
*(pos++) = '\"'; *(pos++) = ',';
|
||||||
pos = write_string(pos, KEY_JSON_ED25519);
|
pos = write_string(pos, KEY_JSON_ED25519);
|
||||||
*(pos++) = '\"';
|
*(pos++) = '\"';
|
||||||
pos = olm::encode_base64(
|
pos = olm::encode_base64(
|
||||||
identity_keys.ed25519_key.public_key,
|
identity_keys.ed25519_key.public_key.public_key,
|
||||||
sizeof(identity_keys.ed25519_key.public_key),
|
sizeof(identity_keys.ed25519_key.public_key.public_key),
|
||||||
pos
|
pos
|
||||||
);
|
);
|
||||||
*(pos++) = '\"'; *(pos++) = '}';
|
*(pos++) = '\"'; *(pos++) = '}';
|
||||||
|
@ -144,7 +145,7 @@ std::size_t olm::Account::get_identity_json(
|
||||||
|
|
||||||
std::size_t olm::Account::signature_length(
|
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;
|
last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
olm::ed25519_sign(
|
_olm_crypto_ed25519_sign(
|
||||||
identity_keys.ed25519_key, message, message_length, signature
|
&identity_keys.ed25519_key, message, message_length, signature
|
||||||
);
|
);
|
||||||
return this->signature_length();
|
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 = olm::encode_base64(key_id, sizeof(key_id), pos);
|
||||||
*(pos++) = '\"'; *(pos++) = ':'; *(pos++) = '\"';
|
*(pos++) = '\"'; *(pos++) = ':'; *(pos++) = '\"';
|
||||||
pos = olm::encode_base64(
|
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++) = '\"';
|
*(pos++) = '\"';
|
||||||
sep = ',';
|
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 olm::Account::generate_one_time_keys_random_length(
|
||||||
std::size_t number_of_keys
|
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(
|
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());
|
OneTimeKey & key = *one_time_keys.insert(one_time_keys.begin());
|
||||||
key.id = ++next_one_time_key_id;
|
key.id = ++next_one_time_key_id;
|
||||||
key.published = false;
|
key.published = false;
|
||||||
olm::curve25519_generate_key(random, key.key);
|
_olm_crypto_curve25519_generate_key(random, &key.key);
|
||||||
random += olm::KEY_LENGTH;
|
random += CURVE25519_RANDOM_LENGTH;
|
||||||
}
|
}
|
||||||
return number_of_keys;
|
return number_of_keys;
|
||||||
}
|
}
|
||||||
|
@ -272,7 +273,7 @@ static std::size_t pickle_length(
|
||||||
olm::IdentityKeys const & value
|
olm::IdentityKeys const & value
|
||||||
) {
|
) {
|
||||||
size_t length = 0;
|
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);
|
length += olm::pickle_length(value.curve25519_key);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
@ -282,7 +283,7 @@ static std::uint8_t * pickle(
|
||||||
std::uint8_t * pos,
|
std::uint8_t * pos,
|
||||||
olm::IdentityKeys const & value
|
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);
|
pos = olm::pickle(pos, value.curve25519_key);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
@ -292,7 +293,7 @@ static std::uint8_t const * unpickle(
|
||||||
std::uint8_t const * pos, std::uint8_t const * end,
|
std::uint8_t const * pos, std::uint8_t const * end,
|
||||||
olm::IdentityKeys & value
|
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);
|
pos = olm::unpickle(pos, end, value.curve25519_key);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
@ -333,7 +334,9 @@ static std::uint8_t const * unpickle(
|
||||||
} // namespace olm
|
} // namespace olm
|
||||||
|
|
||||||
namespace {
|
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,7 +370,13 @@ std::uint8_t const * olm::unpickle(
|
||||||
) {
|
) {
|
||||||
uint32_t pickle_version;
|
uint32_t pickle_version;
|
||||||
pos = olm::unpickle(pos, end, pickle_version);
|
pos = olm::unpickle(pos, end, pickle_version);
|
||||||
if (pickle_version != ACCOUNT_PICKLE_VERSION) {
|
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;
|
value.last_error = OlmErrorCode::OLM_UNKNOWN_PICKLE_VERSION;
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,16 +13,18 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
#include "olm/cipher.h"
|
#include "olm/cipher.h"
|
||||||
#include "olm/crypto.hh"
|
#include "olm/crypto.h"
|
||||||
#include "olm/memory.hh"
|
#include "olm/memory.hh"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
const std::size_t HMAC_KEY_LENGTH = 32;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct DerivedKeys {
|
struct DerivedKeys {
|
||||||
olm::Aes256Key aes_key;
|
_olm_aes256_key aes_key;
|
||||||
std::uint8_t mac_key[olm::KEY_LENGTH];
|
std::uint8_t mac_key[HMAC_KEY_LENGTH];
|
||||||
olm::Aes256Iv aes_iv;
|
_olm_aes256_iv aes_iv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,7 +33,9 @@ static void derive_keys(
|
||||||
std::uint8_t const * key, std::size_t key_length,
|
std::uint8_t const * key, std::size_t key_length,
|
||||||
DerivedKeys & keys
|
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(
|
_olm_crypto_hkdf_sha256(
|
||||||
key, key_length,
|
key, key_length,
|
||||||
nullptr, 0,
|
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(
|
size_t aes_sha_256_cipher_encrypt_ciphertext_length(
|
||||||
const struct _olm_cipher *cipher, size_t plaintext_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(
|
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);
|
derive_keys(c->kdf_info, c->kdf_info_length, key, key_length, keys);
|
||||||
|
|
||||||
olm::aes_encrypt_cbc(
|
_olm_crypto_aes_encrypt_cbc(
|
||||||
keys.aes_key, keys.aes_iv, plaintext, plaintext_length, ciphertext
|
&keys.aes_key, &keys.aes_iv, plaintext, plaintext_length, ciphertext
|
||||||
);
|
);
|
||||||
|
|
||||||
_olm_crypto_hmac_sha256(
|
_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);
|
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);
|
derive_keys(c->kdf_info, c->kdf_info_length, key, key_length, keys);
|
||||||
|
|
||||||
_olm_crypto_hmac_sha256(
|
_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;
|
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);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t plaintext_length = olm::aes_decrypt_cbc(
|
std::size_t plaintext_length = _olm_crypto_aes_decrypt_cbc(
|
||||||
keys.aes_key, keys.aes_iv, ciphertext, ciphertext_length, plaintext
|
&keys.aes_key, &keys.aes_iv, ciphertext, ciphertext_length, plaintext
|
||||||
);
|
);
|
||||||
|
|
||||||
olm::unset(keys);
|
olm::unset(keys);
|
||||||
|
|
114
src/crypto.cpp
114
src/crypto.cpp
|
@ -12,7 +12,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
#include "olm/crypto.hh"
|
#include "olm/crypto.h"
|
||||||
#include "olm/memory.hh"
|
#include "olm/memory.hh"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -25,14 +25,13 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "ed25519/src/ed25519.h"
|
#include "ed25519/src/ed25519.h"
|
||||||
#include "ed25519_additions.h"
|
|
||||||
#include "curve25519-donna.h"
|
#include "curve25519-donna.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static const std::uint8_t CURVE25519_BASEPOINT[32] = {9};
|
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_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 AES_BLOCK_LENGTH = 16;
|
||||||
static const std::size_t SHA256_BLOCK_LENGTH = 64;
|
static const std::size_t SHA256_BLOCK_LENGTH = 64;
|
||||||
static const std::uint8_t HKDF_DEFAULT_SALT[32] = {};
|
static const std::uint8_t HKDF_DEFAULT_SALT[32] = {};
|
||||||
|
@ -101,119 +100,86 @@ inline static void hmac_sha256_final(
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::string olm::Curve25519PublicKey::to_string() const {
|
void _olm_crypto_curve25519_generate_key(
|
||||||
return olm::bytes_to_string(std::begin(public_key),
|
uint8_t const * random_32_bytes,
|
||||||
std::end(public_key));
|
struct _olm_curve25519_key_pair *key_pair
|
||||||
};
|
|
||||||
|
|
||||||
void olm::curve25519_generate_key(
|
|
||||||
std::uint8_t const * random_32_bytes,
|
|
||||||
olm::Curve25519KeyPair & key_pair
|
|
||||||
) {
|
) {
|
||||||
std::memcpy(key_pair.private_key, random_32_bytes, KEY_LENGTH);
|
std::memcpy(
|
||||||
|
key_pair->private_key.private_key, random_32_bytes,
|
||||||
|
CURVE25519_KEY_LENGTH
|
||||||
|
);
|
||||||
::curve25519_donna(
|
::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(
|
void _olm_crypto_curve25519_shared_secret(
|
||||||
olm::Curve25519KeyPair const & our_key,
|
const struct _olm_curve25519_key_pair *our_key,
|
||||||
olm::Curve25519PublicKey const & their_key,
|
const struct _olm_curve25519_public_key * their_key,
|
||||||
std::uint8_t * output
|
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(
|
void _olm_crypto_ed25519_generate_key(
|
||||||
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(
|
|
||||||
std::uint8_t const * random_32_bytes,
|
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_create_keypair(
|
||||||
::ed25519_keypair(key_pair.private_key, key_pair.public_key);
|
key_pair->public_key.public_key, key_pair->private_key.private_key,
|
||||||
|
random_32_bytes
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void olm::ed25519_sign(
|
void _olm_crypto_ed25519_sign(
|
||||||
olm::Ed25519KeyPair const & our_key,
|
const struct _olm_ed25519_key_pair *our_key,
|
||||||
std::uint8_t const * message, std::size_t message_length,
|
std::uint8_t const * message, std::size_t message_length,
|
||||||
std::uint8_t * output
|
std::uint8_t * output
|
||||||
) {
|
) {
|
||||||
::ed25519_sign(
|
::ed25519_sign(
|
||||||
output,
|
output,
|
||||||
message, message_length,
|
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(
|
int _olm_crypto_ed25519_verify(
|
||||||
olm::Ed25519PublicKey const & their_key,
|
const struct _olm_ed25519_public_key *their_key,
|
||||||
std::uint8_t const * message, std::size_t message_length,
|
std::uint8_t const * message, std::size_t message_length,
|
||||||
std::uint8_t const * signature
|
std::uint8_t const * signature
|
||||||
) {
|
) {
|
||||||
return 0 != ::ed25519_verify(
|
return 0 != ::ed25519_verify(
|
||||||
signature,
|
signature,
|
||||||
message, message_length,
|
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
|
std::size_t input_length
|
||||||
) {
|
) {
|
||||||
return input_length + AES_BLOCK_LENGTH - input_length % AES_BLOCK_LENGTH;
|
return input_length + AES_BLOCK_LENGTH - input_length % AES_BLOCK_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void olm::aes_encrypt_cbc(
|
void _olm_crypto_aes_encrypt_cbc(
|
||||||
olm::Aes256Key const & key,
|
_olm_aes256_key const *key,
|
||||||
olm::Aes256Iv const & iv,
|
_olm_aes256_iv const *iv,
|
||||||
std::uint8_t const * input, std::size_t input_length,
|
std::uint8_t const * input, std::size_t input_length,
|
||||||
std::uint8_t * output
|
std::uint8_t * output
|
||||||
) {
|
) {
|
||||||
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
|
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::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) {
|
while (input_length >= AES_BLOCK_LENGTH) {
|
||||||
xor_block<AES_BLOCK_LENGTH>(input_block, input);
|
xor_block<AES_BLOCK_LENGTH>(input_block, input);
|
||||||
::aes_encrypt(input_block, output, key_schedule, AES_KEY_BITS);
|
::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(
|
std::size_t _olm_crypto_aes_decrypt_cbc(
|
||||||
olm::Aes256Key const & key,
|
_olm_aes256_key const *key,
|
||||||
olm::Aes256Iv const & iv,
|
_olm_aes256_iv const *iv,
|
||||||
std::uint8_t const * input, std::size_t input_length,
|
std::uint8_t const * input, std::size_t input_length,
|
||||||
std::uint8_t * output
|
std::uint8_t * output
|
||||||
) {
|
) {
|
||||||
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
|
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 block1[AES_BLOCK_LENGTH];
|
||||||
std::uint8_t block2[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) {
|
for (std::size_t i = 0; i < input_length; i += AES_BLOCK_LENGTH) {
|
||||||
std::memcpy(block2, &input[i], AES_BLOCK_LENGTH);
|
std::memcpy(block2, &input[i], AES_BLOCK_LENGTH);
|
||||||
::aes_decrypt(&input[i], &output[i], key_schedule, AES_KEY_BITS);
|
::aes_decrypt(&input[i], &output[i], key_schedule, AES_KEY_BITS);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "ed25519/src/fe.c"
|
#include "ed25519/src/fe.c"
|
||||||
#include "ed25519/src/sc.c"
|
#include "ed25519/src/sc.c"
|
||||||
#include "ed25519/src/ge.c"
|
#include "ed25519/src/ge.c"
|
||||||
|
#include "ed25519/src/keypair.c"
|
||||||
#include "ed25519/src/sha512.c"
|
#include "ed25519/src/sha512.c"
|
||||||
#include "ed25519/src/verify.c"
|
#include "ed25519/src/verify.c"
|
||||||
#include "ed25519/src/sign.c"
|
#include "ed25519/src/sign.c"
|
||||||
#include "ed25519_additions.c"
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ static const char * ERRORS[] = {
|
||||||
"CORRUPTED_PICKLE",
|
"CORRUPTED_PICKLE",
|
||||||
"BAD_SESSION_KEY",
|
"BAD_SESSION_KEY",
|
||||||
"UNKNOWN_MESSAGE_INDEX",
|
"UNKNOWN_MESSAGE_INDEX",
|
||||||
|
"BAD_LEGACY_ACCOUNT_PICKLE",
|
||||||
|
"BAD_SIGNATURE",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char * _olm_error_to_string(enum OlmErrorCode error)
|
const char * _olm_error_to_string(enum OlmErrorCode error)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "olm/base64.h"
|
#include "olm/base64.h"
|
||||||
#include "olm/cipher.h"
|
#include "olm/cipher.h"
|
||||||
|
#include "olm/crypto.h"
|
||||||
#include "olm/error.h"
|
#include "olm/error.h"
|
||||||
#include "olm/megolm.h"
|
#include "olm/megolm.h"
|
||||||
#include "olm/memory.h"
|
#include "olm/memory.h"
|
||||||
|
@ -28,7 +29,9 @@
|
||||||
|
|
||||||
|
|
||||||
#define OLM_PROTOCOL_VERSION 3
|
#define OLM_PROTOCOL_VERSION 3
|
||||||
|
#define GROUP_SESSION_ID_LENGTH ED25519_PUBLIC_KEY_LENGTH
|
||||||
#define PICKLE_VERSION 1
|
#define PICKLE_VERSION 1
|
||||||
|
#define SESSION_KEY_VERSION 2
|
||||||
|
|
||||||
struct OlmInboundGroupSession {
|
struct OlmInboundGroupSession {
|
||||||
/** our earliest known ratchet value */
|
/** our earliest known ratchet value */
|
||||||
|
@ -37,6 +40,9 @@ struct OlmInboundGroupSession {
|
||||||
/** The most recent ratchet value */
|
/** The most recent ratchet value */
|
||||||
Megolm latest_ratchet;
|
Megolm latest_ratchet;
|
||||||
|
|
||||||
|
/** The ed25519 signing key */
|
||||||
|
struct _olm_ed25519_public_key signing_key;
|
||||||
|
|
||||||
enum OlmErrorCode last_error;
|
enum OlmErrorCode last_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,30 +71,69 @@ size_t olm_clear_inbound_group_session(
|
||||||
return sizeof(OlmInboundGroupSession);
|
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(
|
size_t olm_init_inbound_group_session(
|
||||||
OlmInboundGroupSession *session,
|
OlmInboundGroupSession *session,
|
||||||
uint32_t message_index,
|
|
||||||
const uint8_t * session_key, size_t session_key_length
|
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 raw_length = _olm_decode_base64_length(session_key_length);
|
||||||
|
size_t result;
|
||||||
|
|
||||||
if (raw_length == (size_t)-1) {
|
if (raw_length == (size_t)-1) {
|
||||||
session->last_error = OLM_INVALID_BASE64;
|
session->last_error = OLM_INVALID_BASE64;
|
||||||
return (size_t)-1;
|
return (size_t)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raw_length != MEGOLM_RATCHET_LENGTH) {
|
if (raw_length != SESSION_KEY_RAW_LENGTH) {
|
||||||
session->last_error = OLM_BAD_SESSION_KEY;
|
session->last_error = OLM_BAD_SESSION_KEY;
|
||||||
return (size_t)-1;
|
return (size_t)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_olm_decode_base64(session_key, session_key_length, key_buf);
|
_olm_decode_base64(session_key, session_key_length, key_buf);
|
||||||
megolm_init(&session->initial_ratchet, key_buf, message_index);
|
result = _init_group_session_keys(session, key_buf);
|
||||||
megolm_init(&session->latest_ratchet, key_buf, message_index);
|
_olm_unset(key_buf, SESSION_KEY_RAW_LENGTH);
|
||||||
_olm_unset(key_buf, MEGOLM_RATCHET_LENGTH);
|
return result;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t raw_pickle_length(
|
static size_t raw_pickle_length(
|
||||||
|
@ -98,6 +143,7 @@ static size_t raw_pickle_length(
|
||||||
length += _olm_pickle_uint32_length(PICKLE_VERSION);
|
length += _olm_pickle_uint32_length(PICKLE_VERSION);
|
||||||
length += megolm_pickle_length(&session->initial_ratchet);
|
length += megolm_pickle_length(&session->initial_ratchet);
|
||||||
length += megolm_pickle_length(&session->latest_ratchet);
|
length += megolm_pickle_length(&session->latest_ratchet);
|
||||||
|
length += _olm_pickle_ed25519_public_key_length(&session->signing_key);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +170,7 @@ size_t olm_pickle_inbound_group_session(
|
||||||
pos = _olm_pickle_uint32(pos, PICKLE_VERSION);
|
pos = _olm_pickle_uint32(pos, PICKLE_VERSION);
|
||||||
pos = megolm_pickle(&session->initial_ratchet, pos);
|
pos = megolm_pickle(&session->initial_ratchet, pos);
|
||||||
pos = megolm_pickle(&session->latest_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);
|
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->initial_ratchet, pos, end);
|
||||||
pos = megolm_unpickle(&session->latest_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) {
|
if (end != pos) {
|
||||||
/* We had the wrong number of bytes in the input. */
|
/* 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(
|
_olm_decode_group_message(
|
||||||
message, message_length,
|
message, message_length,
|
||||||
megolm_cipher->ops->mac_length(megolm_cipher),
|
megolm_cipher->ops->mac_length(megolm_cipher),
|
||||||
|
ED25519_SIGNATURE_LENGTH,
|
||||||
&decoded_results);
|
&decoded_results);
|
||||||
|
|
||||||
if (decoded_results.version != OLM_PROTOCOL_VERSION) {
|
if (decoded_results.version != OLM_PROTOCOL_VERSION) {
|
||||||
|
@ -224,6 +273,7 @@ static size_t _decrypt(
|
||||||
_olm_decode_group_message(
|
_olm_decode_group_message(
|
||||||
message, message_length,
|
message, message_length,
|
||||||
megolm_cipher->ops->mac_length(megolm_cipher),
|
megolm_cipher->ops->mac_length(megolm_cipher),
|
||||||
|
ED25519_SIGNATURE_LENGTH,
|
||||||
&decoded_results);
|
&decoded_results);
|
||||||
|
|
||||||
if (decoded_results.version != OLM_PROTOCOL_VERSION) {
|
if (decoded_results.version != OLM_PROTOCOL_VERSION) {
|
||||||
|
@ -231,11 +281,27 @@ static size_t _decrypt(
|
||||||
return (size_t)-1;
|
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;
|
session->last_error = OLM_BAD_MESSAGE_FORMAT;
|
||||||
return (size_t)-1;
|
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(
|
max_length = megolm_cipher->ops->decrypt_max_plaintext_length(
|
||||||
megolm_cipher,
|
megolm_cipher,
|
||||||
decoded_results.ciphertext_length
|
decoded_results.ciphertext_length
|
||||||
|
@ -298,3 +364,23 @@ size_t olm_group_decrypt(
|
||||||
plaintext, max_plaintext_length
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -354,12 +354,14 @@ static const std::uint8_t GROUP_CIPHERTEXT_TAG = 022;
|
||||||
size_t _olm_encode_group_message_length(
|
size_t _olm_encode_group_message_length(
|
||||||
uint32_t message_index,
|
uint32_t message_index,
|
||||||
size_t ciphertext_length,
|
size_t ciphertext_length,
|
||||||
size_t mac_length
|
size_t mac_length,
|
||||||
|
size_t signature_length
|
||||||
) {
|
) {
|
||||||
size_t length = VERSION_LENGTH;
|
size_t length = VERSION_LENGTH;
|
||||||
length += 1 + varint_length(message_index);
|
length += 1 + varint_length(message_index);
|
||||||
length += 1 + varstring_length(ciphertext_length);
|
length += 1 + varstring_length(ciphertext_length);
|
||||||
length += mac_length;
|
length += mac_length;
|
||||||
|
length += signature_length;
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,11 +383,12 @@ size_t _olm_encode_group_message(
|
||||||
|
|
||||||
void _olm_decode_group_message(
|
void _olm_decode_group_message(
|
||||||
const uint8_t *input, size_t input_length,
|
const uint8_t *input, size_t input_length,
|
||||||
size_t mac_length,
|
size_t mac_length, size_t signature_length,
|
||||||
struct _OlmDecodeGroupMessageResults *results
|
struct _OlmDecodeGroupMessageResults *results
|
||||||
) {
|
) {
|
||||||
std::uint8_t const * pos = input;
|
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;
|
std::uint8_t const * unknown = nullptr;
|
||||||
|
|
||||||
bool has_message_index = false;
|
bool has_message_index = false;
|
||||||
|
@ -393,8 +396,7 @@ void _olm_decode_group_message(
|
||||||
results->ciphertext = nullptr;
|
results->ciphertext = nullptr;
|
||||||
results->ciphertext_length = 0;
|
results->ciphertext_length = 0;
|
||||||
|
|
||||||
if (pos == end) return;
|
if (input_length < trailer_length) return;
|
||||||
if (input_length < mac_length) return;
|
|
||||||
results->version = *(pos++);
|
results->version = *(pos++);
|
||||||
|
|
||||||
while (pos != end) {
|
while (pos != end) {
|
||||||
|
|
31
src/olm.cpp
31
src/olm.cpp
|
@ -99,6 +99,11 @@ std::size_t b64_input(
|
||||||
|
|
||||||
extern "C" {
|
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() {
|
size_t olm_error() {
|
||||||
return std::size_t(-1);
|
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 id_key_length = their_identity_key_length;
|
||||||
std::size_t ot_key_length = their_one_time_key_length;
|
std::size_t ot_key_length = their_one_time_key_length;
|
||||||
|
|
||||||
if (olm::decode_base64_length(id_key_length) != olm::KEY_LENGTH
|
if (olm::decode_base64_length(id_key_length) != CURVE25519_KEY_LENGTH
|
||||||
|| olm::decode_base64_length(ot_key_length) != olm::KEY_LENGTH
|
|| olm::decode_base64_length(ot_key_length) != CURVE25519_KEY_LENGTH
|
||||||
) {
|
) {
|
||||||
from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
|
from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
olm::Curve25519PublicKey identity_key;
|
_olm_curve25519_public_key identity_key;
|
||||||
olm::Curve25519PublicKey one_time_key;
|
_olm_curve25519_public_key one_time_key;
|
||||||
|
|
||||||
olm::decode_base64(id_key, id_key_length, identity_key.public_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);
|
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::uint8_t const * id_key = from_c(their_identity_key);
|
||||||
std::size_t id_key_length = their_identity_key_length;
|
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;
|
from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
|
||||||
return std::size_t(-1);
|
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);
|
olm::decode_base64(id_key, id_key_length, identity_key.public_key);
|
||||||
|
|
||||||
std::size_t raw_length = b64_input(
|
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(
|
size_t olm_matches_inbound_session(
|
||||||
OlmSession * session,
|
OlmSession * session,
|
||||||
void * one_time_key_message, size_t message_length
|
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::uint8_t const * id_key = from_c(their_identity_key);
|
||||||
std::size_t id_key_length = their_identity_key_length;
|
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;
|
from_c(session)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
|
||||||
return std::size_t(-1);
|
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);
|
olm::decode_base64(id_key, id_key_length, identity_key.public_key);
|
||||||
|
|
||||||
std::size_t raw_length = b64_input(
|
std::size_t raw_length = b64_input(
|
||||||
|
@ -706,11 +717,11 @@ size_t olm_ed25519_verify(
|
||||||
void const * message, size_t message_length,
|
void const * message, size_t message_length,
|
||||||
void * signature, size_t signature_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;
|
from_c(utility)->last_error = OlmErrorCode::OLM_INVALID_BASE64;
|
||||||
return std::size_t(-1);
|
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);
|
olm::decode_base64(from_c(key), key_length, verify_key.public_key);
|
||||||
std::size_t raw_signature_length = b64_input(
|
std::size_t raw_signature_length = b64_input(
|
||||||
from_c(signature), signature_length, from_c(utility)->last_error
|
from_c(signature), signature_length, from_c(utility)->last_error
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "olm/base64.h"
|
#include "olm/base64.h"
|
||||||
#include "olm/cipher.h"
|
#include "olm/cipher.h"
|
||||||
|
#include "olm/crypto.h"
|
||||||
#include "olm/error.h"
|
#include "olm/error.h"
|
||||||
#include "olm/megolm.h"
|
#include "olm/megolm.h"
|
||||||
#include "olm/memory.h"
|
#include "olm/memory.h"
|
||||||
|
@ -28,16 +29,16 @@
|
||||||
#include "olm/pickle_encoding.h"
|
#include "olm/pickle_encoding.h"
|
||||||
|
|
||||||
#define OLM_PROTOCOL_VERSION 3
|
#define OLM_PROTOCOL_VERSION 3
|
||||||
#define SESSION_ID_RANDOM_BYTES 4
|
#define GROUP_SESSION_ID_LENGTH ED25519_PUBLIC_KEY_LENGTH
|
||||||
#define GROUP_SESSION_ID_LENGTH (sizeof(struct timeval) + SESSION_ID_RANDOM_BYTES)
|
|
||||||
#define PICKLE_VERSION 1
|
#define PICKLE_VERSION 1
|
||||||
|
#define SESSION_KEY_VERSION 2
|
||||||
|
|
||||||
struct OlmOutboundGroupSession {
|
struct OlmOutboundGroupSession {
|
||||||
/** the Megolm ratchet providing the encryption keys */
|
/** the Megolm ratchet providing the encryption keys */
|
||||||
Megolm ratchet;
|
Megolm ratchet;
|
||||||
|
|
||||||
/** unique identifier for this session */
|
/** The ed25519 keypair used for signing the messages */
|
||||||
uint8_t session_id[GROUP_SESSION_ID_LENGTH];
|
struct _olm_ed25519_key_pair signing_key;
|
||||||
|
|
||||||
enum OlmErrorCode last_error;
|
enum OlmErrorCode last_error;
|
||||||
};
|
};
|
||||||
|
@ -74,8 +75,7 @@ static size_t raw_pickle_length(
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
length += _olm_pickle_uint32_length(PICKLE_VERSION);
|
length += _olm_pickle_uint32_length(PICKLE_VERSION);
|
||||||
length += megolm_pickle_length(&(session->ratchet));
|
length += megolm_pickle_length(&(session->ratchet));
|
||||||
length += _olm_pickle_bytes_length(session->session_id,
|
length += _olm_pickle_ed25519_key_pair_length(&(session->signing_key));
|
||||||
GROUP_SESSION_ID_LENGTH);
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ size_t olm_pickle_outbound_group_session(
|
||||||
pos = _olm_enc_output_pos(pickled, raw_length);
|
pos = _olm_enc_output_pos(pickled, raw_length);
|
||||||
pos = _olm_pickle_uint32(pos, PICKLE_VERSION);
|
pos = _olm_pickle_uint32(pos, PICKLE_VERSION);
|
||||||
pos = megolm_pickle(&(session->ratchet), pos);
|
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);
|
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;
|
return (size_t)-1;
|
||||||
}
|
}
|
||||||
pos = megolm_unpickle(&(session->ratchet), pos, end);
|
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) {
|
if (end != pos) {
|
||||||
/* We had the wrong number of bytes in the input. */
|
/* 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
|
/* we need data to initialize the megolm ratchet, plus some more for the
|
||||||
* session id.
|
* session id.
|
||||||
*/
|
*/
|
||||||
return MEGOLM_RATCHET_LENGTH + SESSION_ID_RANDOM_BYTES;
|
return MEGOLM_RATCHET_LENGTH +
|
||||||
|
ED25519_RANDOM_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t olm_init_outbound_group_session(
|
size_t olm_init_outbound_group_session(
|
||||||
|
@ -164,12 +165,8 @@ size_t olm_init_outbound_group_session(
|
||||||
megolm_init(&(session->ratchet), random, 0);
|
megolm_init(&(session->ratchet), random, 0);
|
||||||
random += MEGOLM_RATCHET_LENGTH;
|
random += MEGOLM_RATCHET_LENGTH;
|
||||||
|
|
||||||
/* initialise the session id. This just has to be unique. We use the
|
_olm_crypto_ed25519_generate_key(random, &(session->signing_key));
|
||||||
* current time plus some random data.
|
random += ED25519_RANDOM_LENGTH;
|
||||||
*/
|
|
||||||
gettimeofday((struct timeval *)(session->session_id), NULL);
|
|
||||||
memcpy((session->session_id) + sizeof(struct timeval),
|
|
||||||
random, SESSION_ID_RANDOM_BYTES);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -188,7 +185,8 @@ static size_t raw_message_length(
|
||||||
|
|
||||||
return _olm_encode_group_message_length(
|
return _olm_encode_group_message_length(
|
||||||
session->ratchet.counter,
|
session->ratchet.counter,
|
||||||
ciphertext_length, mac_length);
|
ciphertext_length, mac_length, ED25519_SIGNATURE_LENGTH
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t olm_group_encrypt_message_length(
|
size_t olm_group_encrypt_message_length(
|
||||||
|
@ -241,6 +239,13 @@ static size_t _encrypt(
|
||||||
|
|
||||||
megolm_advance(&(session->ratchet));
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +298,9 @@ size_t olm_outbound_group_session_id(
|
||||||
return (size_t)-1;
|
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(
|
uint32_t olm_outbound_group_session_message_index(
|
||||||
|
@ -302,23 +309,53 @@ uint32_t olm_outbound_group_session_message_index(
|
||||||
return session->ratchet.counter;
|
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(
|
size_t olm_outbound_group_session_key_length(
|
||||||
const OlmOutboundGroupSession *session
|
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(
|
size_t olm_outbound_group_session_key(
|
||||||
OlmOutboundGroupSession *session,
|
OlmOutboundGroupSession *session,
|
||||||
uint8_t * key, size_t key_length
|
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;
|
session->last_error = OLM_OUTPUT_BUFFER_TOO_SMALL;
|
||||||
return (size_t)-1;
|
return (size_t)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _olm_encode_base64(
|
/* put the raw data at the end of the output buffer. */
|
||||||
megolm_get_data(&session->ratchet),
|
raw = ptr = key + encoded_length - SESSION_KEY_RAW_LENGTH;
|
||||||
MEGOLM_RATCHET_LENGTH, key
|
*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);
|
||||||
}
|
}
|
||||||
|
|
159
src/pickle.cpp
159
src/pickle.cpp
|
@ -71,7 +71,7 @@ std::uint8_t const * olm::unpickle_bytes(
|
||||||
|
|
||||||
|
|
||||||
std::size_t olm::pickle_length(
|
std::size_t olm::pickle_length(
|
||||||
const olm::Curve25519PublicKey & value
|
const _olm_curve25519_public_key & value
|
||||||
) {
|
) {
|
||||||
return sizeof(value.public_key);
|
return sizeof(value.public_key);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ std::size_t olm::pickle_length(
|
||||||
|
|
||||||
std::uint8_t * olm::pickle(
|
std::uint8_t * olm::pickle(
|
||||||
std::uint8_t * pos,
|
std::uint8_t * pos,
|
||||||
const olm::Curve25519PublicKey & value
|
const _olm_curve25519_public_key & value
|
||||||
) {
|
) {
|
||||||
pos = olm::pickle_bytes(
|
pos = olm::pickle_bytes(
|
||||||
pos, value.public_key, sizeof(value.public_key)
|
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 * olm::unpickle(
|
||||||
std::uint8_t const * pos, std::uint8_t const * end,
|
std::uint8_t const * pos, std::uint8_t const * end,
|
||||||
olm::Curve25519PublicKey & value
|
_olm_curve25519_public_key & value
|
||||||
) {
|
) {
|
||||||
pos = olm::unpickle_bytes(
|
pos = olm::unpickle_bytes(
|
||||||
pos, end, value.public_key, sizeof(value.public_key)
|
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(
|
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 * olm::pickle(
|
||||||
std::uint8_t * pos,
|
std::uint8_t * pos,
|
||||||
const olm::Curve25519KeyPair & value
|
const _olm_curve25519_key_pair & value
|
||||||
) {
|
) {
|
||||||
pos = olm::pickle_bytes(
|
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 = 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;
|
return pos;
|
||||||
}
|
}
|
||||||
|
@ -123,83 +126,89 @@ std::uint8_t * olm::pickle(
|
||||||
|
|
||||||
std::uint8_t const * olm::unpickle(
|
std::uint8_t const * olm::unpickle(
|
||||||
std::uint8_t const * pos, std::uint8_t const * end,
|
std::uint8_t const * pos, std::uint8_t const * end,
|
||||||
olm::Curve25519KeyPair & value
|
_olm_curve25519_key_pair & value
|
||||||
) {
|
) {
|
||||||
pos = olm::unpickle_bytes(
|
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 = 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
);
|
);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
////// pickle.h implementations
|
////// 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) {
|
uint8_t * _olm_pickle_uint32(uint8_t * pos, uint32_t value) {
|
||||||
return olm::pickle(pos, value);
|
return olm::pickle(pos, value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,15 +44,15 @@ static const std::size_t MAX_MESSAGE_GAP = 2000;
|
||||||
*/
|
*/
|
||||||
static void create_chain_key(
|
static void create_chain_key(
|
||||||
olm::SharedKey const & root_key,
|
olm::SharedKey const & root_key,
|
||||||
olm::Curve25519KeyPair const & our_key,
|
_olm_curve25519_key_pair const & our_key,
|
||||||
olm::Curve25519PublicKey const & their_key,
|
_olm_curve25519_public_key const & their_key,
|
||||||
olm::KdfInfo const & info,
|
olm::KdfInfo const & info,
|
||||||
olm::SharedKey & new_root_key,
|
olm::SharedKey & new_root_key,
|
||||||
olm::ChainKey & new_chain_key
|
olm::ChainKey & new_chain_key
|
||||||
) {
|
) {
|
||||||
olm::SharedKey secret;
|
olm::SharedKey secret;
|
||||||
olm::curve25519_shared_secret(our_key, their_key, secret);
|
_olm_crypto_curve25519_shared_secret(&our_key, &their_key, secret);
|
||||||
std::uint8_t derived_secrets[2 * olm::KEY_LENGTH];
|
std::uint8_t derived_secrets[2 * olm::OLM_SHARED_KEY_LENGTH];
|
||||||
_olm_crypto_hkdf_sha256(
|
_olm_crypto_hkdf_sha256(
|
||||||
secret, sizeof(secret),
|
secret, sizeof(secret),
|
||||||
root_key, sizeof(root_key),
|
root_key, sizeof(root_key),
|
||||||
|
@ -203,9 +203,9 @@ olm::Ratchet::Ratchet(
|
||||||
|
|
||||||
void olm::Ratchet::initialise_as_bob(
|
void olm::Ratchet::initialise_as_bob(
|
||||||
std::uint8_t const * shared_secret, std::size_t shared_secret_length,
|
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(
|
_olm_crypto_hkdf_sha256(
|
||||||
shared_secret, shared_secret_length,
|
shared_secret, shared_secret_length,
|
||||||
nullptr, 0,
|
nullptr, 0,
|
||||||
|
@ -226,9 +226,9 @@ void olm::Ratchet::initialise_as_bob(
|
||||||
|
|
||||||
void olm::Ratchet::initialise_as_alice(
|
void olm::Ratchet::initialise_as_alice(
|
||||||
std::uint8_t const * shared_secret, std::size_t shared_secret_length,
|
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(
|
_olm_crypto_hkdf_sha256(
|
||||||
shared_secret, shared_secret_length,
|
shared_secret, shared_secret_length,
|
||||||
nullptr, 0,
|
nullptr, 0,
|
||||||
|
@ -252,7 +252,7 @@ namespace olm {
|
||||||
static std::size_t pickle_length(
|
static std::size_t pickle_length(
|
||||||
const olm::SharedKey & value
|
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,
|
std::uint8_t * pos,
|
||||||
const olm::SharedKey & value
|
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,
|
std::uint8_t const * pos, std::uint8_t const * end,
|
||||||
olm::SharedKey & value
|
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
|
olm::Ratchet const & value
|
||||||
) {
|
) {
|
||||||
std::size_t length = 0;
|
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.sender_chain);
|
||||||
length += olm::pickle_length(value.receiver_chains);
|
length += olm::pickle_length(value.receiver_chains);
|
||||||
length += olm::pickle_length(value.skipped_message_keys);
|
length += olm::pickle_length(value.skipped_message_keys);
|
||||||
|
@ -428,13 +428,13 @@ std::size_t olm::Ratchet::encrypt_output_length(
|
||||||
plaintext_length
|
plaintext_length
|
||||||
);
|
);
|
||||||
return olm::encode_message_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() {
|
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()) {
|
if (sender_chain.empty()) {
|
||||||
sender_chain.insert();
|
sender_chain.insert();
|
||||||
olm::curve25519_generate_key(random, sender_chain[0].ratchet_key);
|
_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",
|
olm_logf(
|
||||||
|
OLM_LOG_DEBUG, LOG_CATEGORY, "Created new ratchet key T(%i) %s",
|
||||||
chain_index + 1,
|
chain_index + 1,
|
||||||
sender_chain[0].ratchet_key.to_string().c_str());
|
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(
|
create_chain_key(
|
||||||
root_key,
|
root_key,
|
||||||
sender_chain[0].ratchet_key,
|
sender_chain[0].ratchet_key,
|
||||||
|
@ -481,12 +486,14 @@ std::size_t olm::Ratchet::encrypt(
|
||||||
plaintext_length
|
plaintext_length
|
||||||
);
|
);
|
||||||
std::uint32_t counter = keys.index;
|
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::MessageWriter writer;
|
||||||
|
|
||||||
olm::encode_message(
|
olm::encode_message(
|
||||||
writer, PROTOCOL_VERSION, counter, olm::KEY_LENGTH, ciphertext_length,
|
writer, PROTOCOL_VERSION, counter, CURVE25519_KEY_LENGTH,
|
||||||
|
ciphertext_length,
|
||||||
output
|
output
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -500,10 +507,11 @@ std::size_t olm::Ratchet::encrypt(
|
||||||
output, output_length
|
output, output_length
|
||||||
);
|
);
|
||||||
|
|
||||||
olm_logf(OLM_LOG_TRACE, LOG_CATEGORY,
|
olm_logf(
|
||||||
|
OLM_LOG_TRACE, LOG_CATEGORY,
|
||||||
"Encoded message ver=%i ratchet_key=%s chain_idx=%i ciphertext=%s",
|
"Encoded message ver=%i ratchet_key=%s chain_idx=%i ciphertext=%s",
|
||||||
PROTOCOL_VERSION,
|
PROTOCOL_VERSION,
|
||||||
olm::bytes_to_string(writer.ratchet_key, olm::KEY_LENGTH).c_str(),
|
olm::bytes_to_string(writer.ratchet_key, CURVE25519_KEY_LENGTH).c_str(),
|
||||||
counter,
|
counter,
|
||||||
olm::bytes_to_string(writer.ciphertext, ciphertext_length).c_str()
|
olm::bytes_to_string(writer.ciphertext, ciphertext_length).c_str()
|
||||||
);
|
);
|
||||||
|
@ -566,7 +574,7 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
return std::size_t(-1);
|
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;
|
last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
@ -582,7 +590,7 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
for (olm::ReceiverChain & receiver_chain : receiver_chains) {
|
for (olm::ReceiverChain & receiver_chain : receiver_chains) {
|
||||||
if (0 == std::memcmp(
|
if (0 == std::memcmp(
|
||||||
receiver_chain.ratchet_key.public_key, reader.ratchet_key,
|
receiver_chain.ratchet_key.public_key, reader.ratchet_key,
|
||||||
olm::KEY_LENGTH
|
CURVE25519_KEY_LENGTH
|
||||||
)) {
|
)) {
|
||||||
chain = &receiver_chain;
|
chain = &receiver_chain;
|
||||||
break;
|
break;
|
||||||
|
@ -605,7 +613,7 @@ std::size_t olm::Ratchet::decrypt(
|
||||||
if (reader.counter == skipped.message_key.index
|
if (reader.counter == skipped.message_key.index
|
||||||
&& 0 == std::memcmp(
|
&& 0 == std::memcmp(
|
||||||
skipped.ratchet_key.public_key, reader.ratchet_key,
|
skipped.ratchet_key.public_key, reader.ratchet_key,
|
||||||
olm::KEY_LENGTH
|
CURVE25519_KEY_LENGTH
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
/* Found the key for this message. Check the MAC. */
|
/* Found the key for this message. Check the MAC. */
|
||||||
|
|
140
src/session.cpp
140
src/session.cpp
|
@ -14,7 +14,7 @@
|
||||||
*/
|
*/
|
||||||
#include "olm/session.hh"
|
#include "olm/session.hh"
|
||||||
#include "olm/cipher.h"
|
#include "olm/cipher.h"
|
||||||
#include "olm/crypto.hh"
|
#include "olm/crypto.h"
|
||||||
#include "olm/account.hh"
|
#include "olm/account.hh"
|
||||||
#include "olm/logging.h"
|
#include "olm/logging.h"
|
||||||
#include "olm/memory.hh"
|
#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 =
|
static const struct _olm_cipher_aes_sha_256 OLM_CIPHER =
|
||||||
OLM_CIPHER_INIT_AES_SHA_256(CIPHER_KDF_INFO);
|
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
|
} // namespace
|
||||||
|
|
||||||
olm::Session::Session(
|
olm::Session::Session(
|
||||||
|
@ -52,14 +69,14 @@ olm::Session::Session(
|
||||||
|
|
||||||
|
|
||||||
std::size_t olm::Session::new_outbound_session_random_length() {
|
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(
|
std::size_t olm::Session::new_outbound_session(
|
||||||
olm::Account const & local_account,
|
olm::Account const & local_account,
|
||||||
olm::Curve25519PublicKey const & identity_key,
|
_olm_curve25519_public_key const & identity_key,
|
||||||
olm::Curve25519PublicKey const & one_time_key,
|
_olm_curve25519_public_key const & one_time_key,
|
||||||
std::uint8_t const * random, std::size_t random_length
|
std::uint8_t const * random, std::size_t random_length
|
||||||
) {
|
) {
|
||||||
if (random_length < new_outbound_session_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,
|
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY,
|
||||||
"Creating new outbound session to receiver identity IB %s, "
|
"Creating new outbound session to receiver identity IB %s, "
|
||||||
"receiver ephemeral EB %s", identity_key.to_string().c_str(),
|
"receiver ephemeral EB %s", to_string(&identity_key).c_str(),
|
||||||
one_time_key.to_string().c_str()
|
to_string(&one_time_key).c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
olm::Curve25519KeyPair base_key;
|
_olm_curve25519_key_pair base_key;
|
||||||
olm::curve25519_generate_key(random, base_key);
|
_olm_crypto_curve25519_generate_key(random, &base_key);
|
||||||
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY, "Created new ephemeral key EA %s",
|
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_key_pair ratchet_key;
|
||||||
olm::curve25519_generate_key(random + olm::KEY_LENGTH, 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",
|
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
|
local_account.identity_keys.curve25519_key
|
||||||
);
|
);
|
||||||
|
|
||||||
received_message = false;
|
received_message = false;
|
||||||
alice_identity_key = alice_identity_key_pair;
|
alice_identity_key = alice_identity_key_pair.public_key;
|
||||||
alice_base_key = base_key;
|
alice_base_key = base_key.public_key;
|
||||||
bob_one_time_key = one_time_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;
|
std::uint8_t * pos = secret;
|
||||||
|
|
||||||
olm::curve25519_shared_secret(alice_identity_key_pair, one_time_key, pos);
|
_olm_crypto_curve25519_shared_secret(&alice_identity_key_pair, &one_time_key, pos);
|
||||||
pos += olm::KEY_LENGTH;
|
pos += CURVE25519_SHARED_SECRET_LENGTH;
|
||||||
olm::curve25519_shared_secret(base_key, identity_key, pos);
|
_olm_crypto_curve25519_shared_secret(&base_key, &identity_key, pos);
|
||||||
pos += olm::KEY_LENGTH;
|
pos += CURVE25519_SHARED_SECRET_LENGTH;
|
||||||
olm::curve25519_shared_secret(base_key, one_time_key, pos);
|
_olm_crypto_curve25519_shared_secret(&base_key, &one_time_key, pos);
|
||||||
|
|
||||||
ratchet.initialise_as_alice(secret, sizeof(secret), ratchet_key);
|
ratchet.initialise_as_alice(secret, sizeof(secret), ratchet_key);
|
||||||
|
|
||||||
|
@ -119,13 +137,13 @@ static bool check_message_fields(
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
ok = ok && (have_their_identity_key || reader.identity_key);
|
ok = ok && (have_their_identity_key || reader.identity_key);
|
||||||
if (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.message;
|
||||||
ok = ok && reader.base_key;
|
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;
|
||||||
ok = ok && reader.one_time_key_length == olm::KEY_LENGTH;
|
ok = ok && reader.one_time_key_length == CURVE25519_KEY_LENGTH;
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +152,7 @@ static bool check_message_fields(
|
||||||
|
|
||||||
std::size_t olm::Session::new_inbound_session(
|
std::size_t olm::Session::new_inbound_session(
|
||||||
olm::Account & local_account,
|
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
|
std::uint8_t const * one_time_key_message, std::size_t message_length
|
||||||
) {
|
) {
|
||||||
olm::PreKeyMessageReader reader;
|
olm::PreKeyMessageReader reader;
|
||||||
|
@ -147,16 +165,17 @@ std::size_t olm::Session::new_inbound_session(
|
||||||
|
|
||||||
if (reader.identity_key && their_identity_key) {
|
if (reader.identity_key && their_identity_key) {
|
||||||
bool same = 0 == std::memcmp(
|
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) {
|
if (!same) {
|
||||||
olm_logf(OLM_LOG_INFO, LOG_CATEGORY,
|
olm_logf(OLM_LOG_INFO, LOG_CATEGORY,
|
||||||
"Identity key on received message is incorrect "
|
"Identity key on received message is incorrect "
|
||||||
"(expected %s, got %s)",
|
"(expected %s, got %s)",
|
||||||
their_identity_key->to_string().c_str(),
|
to_string(their_identity_key).c_str(),
|
||||||
olm::bytes_to_string(reader.identity_key,
|
olm::bytes_to_string(
|
||||||
reader.identity_key + olm::KEY_LENGTH)
|
reader.identity_key,
|
||||||
.c_str());
|
reader.identity_key + CURVE25519_KEY_LENGTH
|
||||||
|
).c_str());
|
||||||
last_error = OlmErrorCode::OLM_BAD_MESSAGE_KEY_ID;
|
last_error = OlmErrorCode::OLM_BAD_MESSAGE_KEY_ID;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
@ -169,9 +188,9 @@ std::size_t olm::Session::new_inbound_session(
|
||||||
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY,
|
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY,
|
||||||
"Creating new inbound session from sender identity IA %s, "
|
"Creating new inbound session from sender identity IA %s, "
|
||||||
"sender ephemeral EA %s, our ephemeral EB %s",
|
"sender ephemeral EA %s, our ephemeral EB %s",
|
||||||
alice_identity_key.to_string().c_str(),
|
to_string(&alice_identity_key).c_str(),
|
||||||
alice_base_key.to_string().c_str(),
|
to_string(&alice_base_key).c_str(),
|
||||||
bob_one_time_key.to_string().c_str());
|
to_string(&bob_one_time_key).c_str());
|
||||||
|
|
||||||
olm::MessageReader message_reader;
|
olm::MessageReader message_reader;
|
||||||
decode_message(
|
decode_message(
|
||||||
|
@ -180,16 +199,16 @@ std::size_t olm::Session::new_inbound_session(
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!message_reader.ratchet_key
|
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;
|
last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT;
|
||||||
return std::size_t(-1);
|
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::load_array(ratchet_key.public_key, message_reader.ratchet_key);
|
||||||
|
|
||||||
olm_logf(OLM_LOG_DEBUG, LOG_CATEGORY,
|
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(
|
olm::OneTimeKey const * our_one_time_key = local_account.lookup_key(
|
||||||
bob_one_time_key
|
bob_one_time_key
|
||||||
|
@ -198,23 +217,24 @@ std::size_t olm::Session::new_inbound_session(
|
||||||
if (!our_one_time_key) {
|
if (!our_one_time_key) {
|
||||||
olm_logf(OLM_LOG_INFO, LOG_CATEGORY,
|
olm_logf(OLM_LOG_INFO, LOG_CATEGORY,
|
||||||
"Session uses unknown ephemeral key %s",
|
"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;
|
last_error = OlmErrorCode::OLM_BAD_MESSAGE_KEY_ID;
|
||||||
return std::size_t(-1);
|
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
|
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;
|
std::uint8_t * pos = secret;
|
||||||
olm::curve25519_shared_secret(bob_one_time_key, alice_identity_key, pos);
|
_olm_crypto_curve25519_shared_secret(&bob_one_time_key, &alice_identity_key, pos);
|
||||||
pos += olm::KEY_LENGTH;
|
pos += CURVE25519_SHARED_SECRET_LENGTH;
|
||||||
olm::curve25519_shared_secret(bob_identity_key, alice_base_key, pos);
|
_olm_crypto_curve25519_shared_secret(&bob_identity_key, &alice_base_key, pos);
|
||||||
pos += olm::KEY_LENGTH;
|
pos += CURVE25519_SHARED_SECRET_LENGTH;
|
||||||
olm::curve25519_shared_secret(bob_one_time_key, alice_base_key, pos);
|
_olm_crypto_curve25519_shared_secret(&bob_one_time_key, &alice_base_key, pos);
|
||||||
|
|
||||||
ratchet.initialise_as_bob(secret, sizeof(secret), ratchet_key);
|
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;
|
last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
|
||||||
return std::size_t(-1);
|
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;
|
std::uint8_t * pos = tmp;
|
||||||
pos = olm::store_array(pos, alice_identity_key.public_key);
|
pos = olm::store_array(pos, alice_identity_key.public_key);
|
||||||
pos = olm::store_array(pos, alice_base_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(
|
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
|
std::uint8_t const * one_time_key_message, std::size_t message_length
|
||||||
) {
|
) {
|
||||||
olm::PreKeyMessageReader reader;
|
olm::PreKeyMessageReader reader;
|
||||||
|
@ -261,20 +281,20 @@ bool olm::Session::matches_inbound_session(
|
||||||
bool same = true;
|
bool same = true;
|
||||||
if (reader.identity_key) {
|
if (reader.identity_key) {
|
||||||
same = same && 0 == std::memcmp(
|
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) {
|
if (their_identity_key) {
|
||||||
same = same && 0 == std::memcmp(
|
same = same && 0 == std::memcmp(
|
||||||
their_identity_key->public_key, alice_identity_key.public_key,
|
their_identity_key->public_key, alice_identity_key.public_key,
|
||||||
olm::KEY_LENGTH
|
CURVE25519_KEY_LENGTH
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
same = same && 0 == std::memcmp(
|
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(
|
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;
|
return same;
|
||||||
}
|
}
|
||||||
|
@ -301,9 +321,9 @@ std::size_t olm::Session::encrypt_message_length(
|
||||||
}
|
}
|
||||||
|
|
||||||
return encode_one_time_key_message_length(
|
return encode_one_time_key_message_length(
|
||||||
olm::KEY_LENGTH,
|
CURVE25519_KEY_LENGTH,
|
||||||
olm::KEY_LENGTH,
|
CURVE25519_KEY_LENGTH,
|
||||||
olm::KEY_LENGTH,
|
CURVE25519_KEY_LENGTH,
|
||||||
message_length
|
message_length
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -338,9 +358,9 @@ std::size_t olm::Session::encrypt(
|
||||||
encode_one_time_key_message(
|
encode_one_time_key_message(
|
||||||
writer,
|
writer,
|
||||||
PROTOCOL_VERSION,
|
PROTOCOL_VERSION,
|
||||||
olm::KEY_LENGTH,
|
CURVE25519_KEY_LENGTH,
|
||||||
olm::KEY_LENGTH,
|
CURVE25519_KEY_LENGTH,
|
||||||
olm::KEY_LENGTH,
|
CURVE25519_KEY_LENGTH,
|
||||||
message_body_length,
|
message_body_length,
|
||||||
message
|
message
|
||||||
);
|
);
|
||||||
|
@ -354,9 +374,9 @@ std::size_t olm::Session::encrypt(
|
||||||
"Encoded pre-key message ver=%i one_time_key[Eb]=%s "
|
"Encoded pre-key message ver=%i one_time_key[Eb]=%s "
|
||||||
"base_key[Ea]=%s identity_key[Ia]=%s",
|
"base_key[Ea]=%s identity_key[Ia]=%s",
|
||||||
PROTOCOL_VERSION,
|
PROTOCOL_VERSION,
|
||||||
olm::bytes_to_string(writer.one_time_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, olm::KEY_LENGTH).c_str(),
|
olm::bytes_to_string(writer.base_key, CURVE25519_KEY_LENGTH).c_str(),
|
||||||
olm::bytes_to_string(writer.identity_key, olm::KEY_LENGTH).c_str()
|
olm::bytes_to_string(writer.identity_key, CURVE25519_KEY_LENGTH).c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "olm/utility.hh"
|
#include "olm/utility.hh"
|
||||||
#include "olm/crypto.hh"
|
#include "olm/crypto.h"
|
||||||
|
|
||||||
|
|
||||||
olm::Utility::Utility(
|
olm::Utility::Utility(
|
||||||
|
@ -41,15 +41,15 @@ size_t olm::Utility::sha256(
|
||||||
|
|
||||||
|
|
||||||
size_t olm::Utility::ed25519_verify(
|
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 * message, std::size_t message_length,
|
||||||
std::uint8_t const * signature, std::size_t signature_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;
|
last_error = OlmErrorCode::OLM_BAD_MESSAGE_MAC;
|
||||||
return std::size_t(-1);
|
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;
|
last_error = OlmErrorCode::OLM_BAD_MESSAGE_MAC;
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
#include "olm/crypto.hh"
|
#include "olm/crypto.h"
|
||||||
|
|
||||||
#include "unittest.hh"
|
#include "unittest.hh"
|
||||||
|
|
||||||
|
@ -58,60 +58,31 @@ std::uint8_t expected_agreement[32] = {
|
||||||
0x76, 0xF0, 0x9B, 0x3C, 0x1E, 0x16, 0x17, 0x42
|
0x76, 0xF0, 0x9B, 0x3C, 0x1E, 0x16, 0x17, 0x42
|
||||||
};
|
};
|
||||||
|
|
||||||
olm::Curve25519KeyPair alice_pair;
|
_olm_curve25519_key_pair alice_pair;
|
||||||
olm::curve25519_generate_key(alice_private, alice_pair);
|
_olm_crypto_curve25519_generate_key(alice_private, &alice_pair);
|
||||||
|
|
||||||
assert_equals(alice_private, alice_pair.private_key, 32);
|
assert_equals(alice_private, alice_pair.private_key.private_key, 32);
|
||||||
assert_equals(alice_public, alice_pair.public_key, 32);
|
assert_equals(alice_public, alice_pair.public_key.public_key, 32);
|
||||||
|
|
||||||
olm::Curve25519KeyPair bob_pair;
|
_olm_curve25519_key_pair bob_pair;
|
||||||
olm::curve25519_generate_key(bob_private, bob_pair);
|
_olm_crypto_curve25519_generate_key(bob_private, &bob_pair);
|
||||||
|
|
||||||
assert_equals(bob_private, bob_pair.private_key, 32);
|
assert_equals(bob_private, bob_pair.private_key.private_key, 32);
|
||||||
assert_equals(bob_public, bob_pair.public_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);
|
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);
|
assert_equals(expected_agreement, actual_agreement, 32);
|
||||||
|
|
||||||
} /* Curve25529 Test Case 1 */
|
} /* 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");
|
TestCase test_case("Ed25519 Signature Test Case 1");
|
||||||
std::uint8_t private_key[33] = "This key is a string of 32 bytes";
|
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::uint8_t message[] = "Hello, World";
|
||||||
std::size_t message_length = sizeof(message) - 1;
|
std::size_t message_length = sizeof(message) - 1;
|
||||||
|
|
||||||
olm::Ed25519KeyPair key_pair;
|
_olm_ed25519_key_pair key_pair;
|
||||||
olm::ed25519_generate_key(private_key, key_pair);
|
_olm_crypto_ed25519_generate_key(private_key, &key_pair);
|
||||||
|
|
||||||
std::uint8_t signature[64];
|
std::uint8_t signature[64];
|
||||||
olm::ed25519_sign(
|
_olm_crypto_ed25519_sign(
|
||||||
key_pair, message, message_length, signature
|
&key_pair, message, message_length, signature
|
||||||
);
|
);
|
||||||
|
|
||||||
bool result = olm::ed25519_verify(
|
bool result = _olm_crypto_ed25519_verify(
|
||||||
key_pair, message, message_length, signature
|
&key_pair.public_key, message, message_length, signature
|
||||||
);
|
);
|
||||||
assert_equals(true, result);
|
assert_equals(true, result);
|
||||||
|
|
||||||
message[0] = 'n';
|
message[0] = 'n';
|
||||||
result = olm::ed25519_verify(
|
result = _olm_crypto_ed25519_verify(
|
||||||
key_pair, message, message_length, signature
|
&key_pair.public_key, message, message_length, signature
|
||||||
);
|
);
|
||||||
assert_equals(false, result);
|
assert_equals(false, result);
|
||||||
}
|
}
|
||||||
|
@ -144,8 +115,8 @@ assert_equals(false, result);
|
||||||
|
|
||||||
TestCase test_case("AES Test Case 1");
|
TestCase test_case("AES Test Case 1");
|
||||||
|
|
||||||
olm::Aes256Key key = {};
|
_olm_aes256_key key = {};
|
||||||
olm::Aes256Iv iv = {};
|
_olm_aes256_iv iv = {};
|
||||||
std::uint8_t input[16] = {};
|
std::uint8_t input[16] = {};
|
||||||
|
|
||||||
std::uint8_t expected[32] = {
|
std::uint8_t expected[32] = {
|
||||||
|
@ -155,16 +126,16 @@ std::uint8_t expected[32] = {
|
||||||
0x4B, 0xAE, 0xDF, 0xFC, 0x3D, 0x21, 0x4C, 0x38
|
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);
|
assert_equals(std::size_t(32), length);
|
||||||
|
|
||||||
|
|
||||||
std::uint8_t actual[32] = {};
|
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);
|
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(std::size_t(16), length);
|
||||||
assert_equals(input, actual, length);
|
assert_equals(input, actual, length);
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,6 @@ int main() {
|
||||||
assert_equals(pickle1, pickle2, pickle_length);
|
assert_equals(pickle1, pickle2, pickle_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
TestCase test_case("Group message send/receive");
|
TestCase test_case("Group message send/receive");
|
||||||
|
|
||||||
|
@ -89,6 +88,7 @@ int main() {
|
||||||
"0123456789ABDEF0123456789ABCDEF"
|
"0123456789ABDEF0123456789ABCDEF"
|
||||||
"0123456789ABDEF0123456789ABCDEF"
|
"0123456789ABDEF0123456789ABCDEF"
|
||||||
"0123456789ABDEF0123456789ABCDEF"
|
"0123456789ABDEF0123456789ABCDEF"
|
||||||
|
"0123456789ABDEF0123456789ABCDEF"
|
||||||
"0123456789ABDEF0123456789ABCDEF";
|
"0123456789ABDEF0123456789ABCDEF";
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ int main() {
|
||||||
uint8_t memory[size];
|
uint8_t memory[size];
|
||||||
OlmOutboundGroupSession *session = olm_outbound_group_session(memory);
|
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));
|
olm_init_outbound_group_session_random_length(session));
|
||||||
|
|
||||||
size_t res = olm_init_outbound_group_session(
|
size_t res = olm_init_outbound_group_session(
|
||||||
|
@ -109,7 +109,6 @@ int main() {
|
||||||
uint8_t session_key[session_key_len];
|
uint8_t session_key[session_key_len];
|
||||||
olm_outbound_group_session_key(session, session_key, session_key_len);
|
olm_outbound_group_session_key(session, session_key, session_key_len);
|
||||||
|
|
||||||
|
|
||||||
/* encode the message */
|
/* encode the message */
|
||||||
uint8_t plaintext[] = "Message";
|
uint8_t plaintext[] = "Message";
|
||||||
size_t plaintext_length = sizeof(plaintext) - 1;
|
size_t plaintext_length = sizeof(plaintext) - 1;
|
||||||
|
@ -131,9 +130,29 @@ int main() {
|
||||||
olm_inbound_group_session(inbound_session_memory);
|
olm_inbound_group_session(inbound_session_memory);
|
||||||
|
|
||||||
res = olm_init_inbound_group_session(
|
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);
|
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 */
|
/* decode the message */
|
||||||
|
|
||||||
/* olm_group_decrypt_max_plaintext_length destroys the input so we have to
|
/* 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);
|
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))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,8 +67,8 @@ assert_equals(message2, output, 35);
|
||||||
|
|
||||||
TestCase test_case("Group message encode test");
|
TestCase test_case("Group message encode test");
|
||||||
|
|
||||||
size_t length = _olm_encode_group_message_length(200, 10, 8);
|
size_t length = _olm_encode_group_message_length(200, 10, 8, 64);
|
||||||
size_t expected_length = 1 + (1+2) + (2+10) + 8;
|
size_t expected_length = 1 + (1+2) + (2+10) + 8 + 64;
|
||||||
assert_equals(expected_length, length);
|
assert_equals(expected_length, length);
|
||||||
|
|
||||||
uint8_t output[50];
|
uint8_t output[50];
|
||||||
|
@ -99,9 +99,10 @@ assert_equals(message2, output, 35);
|
||||||
"\x03"
|
"\x03"
|
||||||
"\x08\xC8\x01"
|
"\x08\xC8\x01"
|
||||||
"\x12\x0A" "ciphertext"
|
"\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(std::uint8_t(3), results.version);
|
||||||
assert_equals(1, results.has_message_index);
|
assert_equals(1, results.has_message_index);
|
||||||
assert_equals(std::uint32_t(200), results.message_index);
|
assert_equals(std::uint32_t(200), results.message_index);
|
||||||
|
|
|
@ -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 */
|
{ /** Pickle session test */
|
||||||
|
|
||||||
TestCase test_case("Pickle session test");
|
TestCase test_case("Pickle session test");
|
||||||
|
|
|
@ -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);
|
_olm_cipher *cipher = OLM_CIPHER_BASE(&cipher0);
|
||||||
|
|
||||||
std::uint8_t random_bytes[] = "0123456789ABDEF0123456789ABCDEF";
|
std::uint8_t random_bytes[] = "0123456789ABDEF0123456789ABCDEF";
|
||||||
olm::Curve25519KeyPair alice_key;
|
_olm_curve25519_key_pair alice_key;
|
||||||
olm::curve25519_generate_key(random_bytes, alice_key);
|
_olm_crypto_curve25519_generate_key(random_bytes, &alice_key);
|
||||||
|
|
||||||
std::uint8_t shared_secret[] = "A secret";
|
std::uint8_t shared_secret[] = "A secret";
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ olm::Ratchet alice(kdf_info, cipher);
|
||||||
olm::Ratchet bob(kdf_info, cipher);
|
olm::Ratchet bob(kdf_info, cipher);
|
||||||
|
|
||||||
alice.initialise_as_alice(shared_secret, sizeof(shared_secret) - 1, alice_key);
|
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::uint8_t plaintext[] = "Message";
|
||||||
std::size_t plaintext_length = sizeof(plaintext) - 1;
|
std::size_t plaintext_length = sizeof(plaintext) - 1;
|
||||||
|
@ -113,7 +113,7 @@ olm::Ratchet alice(kdf_info, cipher);
|
||||||
olm::Ratchet bob(kdf_info, cipher);
|
olm::Ratchet bob(kdf_info, cipher);
|
||||||
|
|
||||||
alice.initialise_as_alice(shared_secret, sizeof(shared_secret) - 1, alice_key);
|
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::uint8_t plaintext_1[] = "First Message";
|
||||||
std::size_t plaintext_1_length = sizeof(plaintext_1) - 1;
|
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);
|
olm::Ratchet bob(kdf_info, cipher);
|
||||||
|
|
||||||
alice.initialise_as_alice(shared_secret, sizeof(shared_secret) - 1, alice_key);
|
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";
|
std::uint8_t plaintext[] = "These 15 bytes";
|
||||||
assert_equals(std::size_t(15), sizeof(plaintext));
|
assert_equals(std::size_t(15), sizeof(plaintext));
|
||||||
|
|
|
@ -33,12 +33,12 @@ void check_session(const olm::Session &session) {
|
||||||
|
|
||||||
assert_equals(
|
assert_equals(
|
||||||
decode_hex("f77a03eaa9b301fa7d2a5aa6b50286906de12cc96044f526dbbcb12839ad7003"),
|
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(
|
assert_equals(
|
||||||
decode_hex("d945c6ed4c7c277117adf11fb133a7936d287afe97c0b3ac989644b4490d4f31"),
|
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(
|
assert_equals(
|
||||||
|
|
Loading…
Reference in a new issue