aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHubert Chathi <hubert@uhoreg.ca>2018-10-12 17:02:51 -0400
committerHubert Chathi <hubert@uhoreg.ca>2018-10-12 17:02:51 -0400
commit5cf074d3372f1e189fe410a075013adefabb1aa5 (patch)
treea72a96fafab69e62b5083cbe1933b4e34e9a72d5
parentac071d9c0d69e4330a06f171e3bddc713ecd97d6 (diff)
parentaf86a9a8b899eeb3c1c464cb0c54218acd788fa6 (diff)
Merge branch 'master' into poljar
-rw-r--r--.circleci/config.yml27
-rw-r--r--CHANGELOG.rst12
-rw-r--r--Makefile99
-rw-r--r--README.rst3
-rw-r--r--android/olm-sdk/src/main/java/org/matrix/olm/OlmInboundGroupSession.java5
-rw-r--r--android/olm-sdk/src/main/java/org/matrix/olm/OlmOutboundGroupSession.java6
-rw-r--r--android/olm-sdk/src/main/java/org/matrix/olm/OlmPkDecryption.java7
-rw-r--r--android/olm-sdk/src/main/java/org/matrix/olm/OlmPkEncryption.java6
-rw-r--r--android/olm-sdk/src/main/java/org/matrix/olm/OlmSession.java11
-rw-r--r--android/olm-sdk/src/main/jni/olm_outbound_group_session.cpp7
-rw-r--r--android/olm-sdk/src/main/jni/olm_pk.cpp63
-rw-r--r--android/olm-sdk/src/main/jni/olm_session.cpp12
-rw-r--r--docs/olm.rst4
-rw-r--r--docs/signing.rst2
-rwxr-xr-xexports.py18
-rw-r--r--include/olm/error.h7
-rw-r--r--include/olm/pk.h70
-rw-r--r--javascript/.gitignore1
-rw-r--r--javascript/externs.js4
-rw-r--r--javascript/olm_inbound_group_session.js14
-rw-r--r--javascript/olm_outbound_group_session.js15
-rw-r--r--javascript/olm_pk.js62
-rw-r--r--javascript/olm_post.js53
-rw-r--r--javascript/olm_pre.js44
-rw-r--r--javascript/olm_prefix.js3
-rw-r--r--javascript/olm_suffix.js32
-rw-r--r--javascript/package.json1
-rw-r--r--javascript/test/megolm.spec.js11
-rw-r--r--javascript/test/olm.spec.js18
-rw-r--r--javascript/test/pk.spec.js32
-rw-r--r--src/error.c1
-rw-r--r--src/pk.cpp101
-rw-r--r--tests/test_pk.cpp13
33 files changed, 558 insertions, 206 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..0a891db
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,27 @@
+version: 2
+jobs:
+ build:
+ docker:
+ - image: trzeci/emscripten
+
+ working_directory: ~/repo
+
+ steps:
+ - checkout
+ - run:
+ name: Native Compile
+ command: make
+ - run:
+ name: Native Tests
+ command: make test
+ - run:
+ name: JS Compile
+ command: make js
+ - run:
+ name: Install JS Deps
+ working_directory: ~/repo/javascript
+ command: npm install
+ - run:
+ name: JS Tests
+ working_directory: ~/repo/javascript
+ command: npm run test
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index fa1eccb..6b450b4 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,3 +1,15 @@
+Changes in latest release
+
+BREAKING CHANGE: Olm now uses WebAssembly which means it needs
+to load the wasm file asynchronously, and therefore needs to be
+started up asynchronously. The imported module now has an init()
+method which returns a promise. The library cannot be used until
+this promise resolves. It will reject if the library fails to start.
+
+olm_pk_generate_key() and olm_pk_generate_key_random_length() have
+been removed: to generate a random key, use olm_pk_key_from_private()
+with random bytes as the private key.
+
Changes in `2.3.0 <http://matrix.org/git/olm/commit/?h=2.3.0>`_
This release includes the following changes since 2.2.2:
diff --git a/Makefile b/Makefile
index be50a8f..a354e19 100644
--- a/Makefile
+++ b/Makefile
@@ -14,12 +14,25 @@ AFL_CC = afl-gcc
AFL_CXX = afl-g++
AR = ar
-RELEASE_TARGET := $(BUILD_DIR)/libolm.so.$(VERSION)
+UNAME := $(shell uname)
+ifeq ($(UNAME),Darwin)
+ SO := dylib
+ OLM_LDFLAGS :=
+else
+ SO := so
+ OLM_LDFLAGS := -Wl,-soname,libolm.so.$(MAJOR) \
+ -Wl,--version-script,version_script.ver
+endif
+
+RELEASE_TARGET := $(BUILD_DIR)/libolm.$(SO).$(VERSION)
STATIC_RELEASE_TARGET := $(BUILD_DIR)/libolm.a
-DEBUG_TARGET := $(BUILD_DIR)/libolm_debug.so.$(VERSION)
-JS_TARGET := javascript/olm.js
+DEBUG_TARGET := $(BUILD_DIR)/libolm_debug.$(SO).$(VERSION)
+JS_WASM_TARGET := javascript/olm.js
+JS_ASMJS_TARGET := javascript/olm_legacy.js
JS_EXPORTED_FUNCTIONS := javascript/exported_functions.json
+JS_EXTRA_EXPORTED_RUNTIME_METHODS := ALLOC_STACK
+JS_EXTERNS := javascript/externs.js
PUBLIC_HEADERS := include/olm/olm.h include/olm/outbound_group_session.h include/olm/inbound_group_session.h include/olm/pk.h
@@ -39,11 +52,22 @@ FUZZER_BINARIES := $(addprefix $(BUILD_DIR)/,$(basename $(FUZZER_SOURCES)))
FUZZER_DEBUG_BINARIES := $(patsubst $(BUILD_DIR)/fuzzers/fuzz_%,$(BUILD_DIR)/fuzzers/debug_%,$(FUZZER_BINARIES))
TEST_BINARIES := $(patsubst tests/%,$(BUILD_DIR)/tests/%,$(basename $(TEST_SOURCES)))
JS_OBJECTS := $(addprefix $(BUILD_DIR)/javascript/,$(OBJECTS))
+
+# pre & post are the js-pre/js-post options to emcc.
+# They are injected inside the modularised code and
+# processed by the optimiser.
JS_PRE := $(wildcard javascript/*pre.js)
JS_POST := javascript/olm_outbound_group_session.js \
javascript/olm_inbound_group_session.js \
javascript/olm_pk.js \
javascript/olm_post.js
+
+# The prefix & suffix are just added onto the start & end
+# of what comes out emcc, so are outside of the modularised
+# code and not seen by the opimiser.
+JS_PREFIX := javascript/olm_prefix.js
+JS_SUFFIX := javascript/olm_suffix.js
+
DOCS := tracing/README.html \
docs/megolm.html \
docs/olm.html \
@@ -60,11 +84,23 @@ CFLAGS += -Wall -Werror -std=c99 -fPIC
CXXFLAGS += -Wall -Werror -std=c++11 -fPIC
LDFLAGS += -Wall -Werror
-EMCCFLAGS = --closure 1 --memory-init-file 0 -s NO_FILESYSTEM=1 -s INVOKE_RUN=0
+EMCCFLAGS = --closure 1 --memory-init-file 0 -s NO_FILESYSTEM=1 -s INVOKE_RUN=0 -s MODULARIZE=1
# NO_BROWSER is kept for compatibility with emscripten 1.35.24, but is no
# longer needed.
EMCCFLAGS += -s NO_BROWSER=1
+# Olm generally doesn't need a lot of memory to encrypt / decrypt its usual
+# payloads (ie. Matrix messages), but we do need about 128K of heap to encrypt
+# a 64K event (enough to store the ciphertext and the plaintext, bearing in
+# mind that the plaintext can only be 48K because base64). We also have about
+# 36K of statics. So let's have 256K of memory.
+# (This can't be changed by the app with wasm since it's baked into the wasm).
+# (emscripten also mandates at least 16MB of memory for asm.js now, so
+# we don't use this for the legacy build.)
+EMCCFLAGS_WASM += -s TOTAL_STACK=65536 -s TOTAL_MEMORY=262144
+
+EMCCFLAGS_ASMJS += -s WASM=0
+
EMCC.c = $(EMCC) $(CFLAGS) $(CPPFLAGS) -c
EMCC.cc = $(EMCC) $(CXXFLAGS) $(CPPFLAGS) -c
EMCC_LINK = $(EMCC) $(LDFLAGS) $(EMCCFLAGS)
@@ -99,7 +135,8 @@ $(FUZZER_DEBUG_BINARIES): LDFLAGS += $(DEBUG_OPTIMIZE_FLAGS)
$(JS_OBJECTS): CFLAGS += $(JS_OPTIMIZE_FLAGS)
$(JS_OBJECTS): CXXFLAGS += $(JS_OPTIMIZE_FLAGS)
-$(JS_TARGET): LDFLAGS += $(JS_OPTIMIZE_FLAGS)
+$(JS_WASM_TARGET): LDFLAGS += $(JS_OPTIMIZE_FLAGS)
+$(JS_ASMJS_TARGET): LDFLAGS += $(JS_OPTIMIZE_FLAGS)
### Fix to make mkdir work on windows and linux
ifeq ($(shell echo "check_quotes"),"check_quotes")
@@ -121,21 +158,19 @@ lib: $(RELEASE_TARGET)
$(RELEASE_TARGET): $(RELEASE_OBJECTS)
$(CXX) $(LDFLAGS) --shared -fPIC \
- -Wl,-soname,libolm.so.$(MAJOR) \
- -Wl,--version-script,version_script.ver \
+ $(OLM_LDFLAGS) \
$(OUTPUT_OPTION) $(RELEASE_OBJECTS)
- ln -sf libolm.so.$(VERSION) $(BUILD_DIR)/libolm.so.$(MAJOR)
- ln -sf libolm.so.$(VERSION) $(BUILD_DIR)/libolm.so
+ ln -sf libolm.$(SO).$(VERSION) $(BUILD_DIR)/libolm.$(SO).$(MAJOR)
+ ln -sf libolm.$(SO).$(VERSION) $(BUILD_DIR)/libolm.$(SO)
debug: $(DEBUG_TARGET)
.PHONY: debug
$(DEBUG_TARGET): $(DEBUG_OBJECTS)
$(CXX) $(LDFLAGS) --shared -fPIC \
- -Wl,-soname,libolm_debug.so.$(MAJOR) \
- -Wl,--version-script,version_script.ver \
+ $(OLM_LDFLAGS) \
$(OUTPUT_OPTION) $(DEBUG_OBJECTS)
- ln -sf libolm_debug.so.$(VERSION) $(BUILD_DIR)/libolm_debug.so.$(MAJOR)
+ ln -sf libolm_debug.$(SO).$(VERSION) $(BUILD_DIR)/libolm_debug.$(SO).$(MAJOR)
static: $(STATIC_RELEASE_TARGET)
.PHONY: static
@@ -143,15 +178,35 @@ static: $(STATIC_RELEASE_TARGET)
$(STATIC_RELEASE_TARGET): $(RELEASE_OBJECTS)
$(AR) rcs $@ $^
-js: $(JS_TARGET)
+js: $(JS_WASM_TARGET) $(JS_ASMJS_TARGET)
.PHONY: js
-$(JS_TARGET): $(JS_OBJECTS) $(JS_PRE) $(JS_POST) $(JS_EXPORTED_FUNCTIONS)
- $(EMCC_LINK) \
+# Note that the output file we give to emcc determines the name of the
+# wasm file baked into the js, hence messing around outputting to olm.js
+# and then renaming it.
+$(JS_WASM_TARGET): $(JS_OBJECTS) $(JS_PRE) $(JS_POST) $(JS_EXPORTED_FUNCTIONS) $(JS_PREFIX) $(JS_SUFFIX)
+ EMCC_CLOSURE_ARGS="--externs $(JS_EXTERNS)" $(EMCC_LINK) \
+ $(EMCCFLAGS_WASM) \
+ $(foreach f,$(JS_PRE),--pre-js $(f)) \
+ $(foreach f,$(JS_POST),--post-js $(f)) \
+ -s "EXPORTED_FUNCTIONS=@$(JS_EXPORTED_FUNCTIONS)" \
+ -s "EXTRA_EXPORTED_RUNTIME_METHODS=$(JS_EXTRA_EXPORTED_RUNTIME_METHODS)" \
+ $(JS_OBJECTS) -o $@
+ mv $@ javascript/olmtmp.js
+ cat $(JS_PREFIX) javascript/olmtmp.js $(JS_SUFFIX) > $@
+ rm javascript/olmtmp.js
+
+$(JS_ASMJS_TARGET): $(JS_OBJECTS) $(JS_PRE) $(JS_POST) $(JS_EXPORTED_FUNCTIONS) $(JS_PREFIX) $(JS_SUFFIX)
+ EMCC_CLOSURE_ARGS="--externs $(JS_EXTERNS)" $(EMCC_LINK) \
+ $(EMCCFLAGS_ASMJS) \
$(foreach f,$(JS_PRE),--pre-js $(f)) \
$(foreach f,$(JS_POST),--post-js $(f)) \
-s "EXPORTED_FUNCTIONS=@$(JS_EXPORTED_FUNCTIONS)" \
+ -s "EXTRA_EXPORTED_RUNTIME_METHODS=$(JS_EXTRA_EXPORTED_RUNTIME_METHODS)" \
$(JS_OBJECTS) -o $@
+ mv $@ javascript/olmtmp.js
+ cat $(JS_PREFIX) javascript/olmtmp.js $(JS_SUFFIX) > $@
+ rm javascript/olmtmp.js
build_tests: $(TEST_BINARIES)
@@ -165,7 +220,7 @@ fuzzers: $(FUZZER_BINARIES) $(FUZZER_DEBUG_BINARIES)
.PHONY: fuzzers
$(JS_EXPORTED_FUNCTIONS): $(PUBLIC_HEADERS)
- perl -MJSON -ne '$$f{"_$$1"}=1 if /(olm_[^( ]*)\(/; END { @f=sort keys %f; print encode_json \@f }' $^ > $@.tmp
+ ./exports.py $^ > $@.tmp
mv $@.tmp $@
all: test js lib debug doc
@@ -178,16 +233,16 @@ install-headers: $(PUBLIC_HEADERS)
install-debug: debug install-headers
test -d $(DESTDIR)$(PREFIX)/lib || $(call 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
+ 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 install-headers
test -d $(DESTDIR)$(PREFIX)/lib || $(call 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
+ 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:;
diff --git a/README.rst b/README.rst
index 4f33c00..5a5413e 100644
--- a/README.rst
+++ b/README.rst
@@ -31,6 +31,9 @@ To build the javascript bindings, install emscripten from http://kripken.github.
make js
+Note that if you run emscripten in a docker container, you need to pass through
+the EMCC_CLOSURE_ARGS environment variable.
+
To build the android project for Android bindings, run:
.. code:: bash
diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmInboundGroupSession.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmInboundGroupSession.java
index 8c2d7b0..b41c67a 100644
--- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmInboundGroupSession.java
+++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmInboundGroupSession.java
@@ -25,6 +25,8 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.util.Arrays;
+
/**
* Class used to create an inbound <a href="http://matrix.org/docs/guides/e2e_implementation.html#handling-an-m-room-key-event">Megolm session</a>.<br>
* Counter part of the outbound group session {@link OlmOutboundGroupSession}, this class decrypts the messages sent by the outbound side.
@@ -236,7 +238,7 @@ public class OlmInboundGroupSession extends CommonSerializeUtils implements Seri
* In case of error, null is returned and an error message description is provided in aErrorMsg.
* @param aEncryptedMsg the message to be decrypted
* @return the decrypted message information
- * @exception OlmException teh failure reason
+ * @exception OlmException the failure reason
*/
public DecryptMessageResult decryptMessage(String aEncryptedMsg) throws OlmException {
DecryptMessageResult result = new DecryptMessageResult();
@@ -246,6 +248,7 @@ public class OlmInboundGroupSession extends CommonSerializeUtils implements Seri
if (null != decryptedMessageBuffer) {
result.mDecryptedMessage = new String(decryptedMessageBuffer, "UTF-8");
+ Arrays.fill(decryptedMessageBuffer, (byte) 0);
}
} catch (Exception e) {
Log.e(LOG_TAG, "## decryptMessage() failed " + e.getMessage());
diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmOutboundGroupSession.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmOutboundGroupSession.java
index 0481824..e4d4a44 100644
--- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmOutboundGroupSession.java
+++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmOutboundGroupSession.java
@@ -26,6 +26,8 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.util.Arrays;
+
/**
* Class used to create an outbound a <a href="http://matrix.org/docs/guides/e2e_implementation.html#starting-a-megolm-session">Megolm session</a>.<br>
* To send a first message in an encrypted room, the client should start a new outbound Megolm session.
@@ -166,7 +168,9 @@ public class OlmOutboundGroupSession extends CommonSerializeUtils implements Ser
if (!TextUtils.isEmpty(aClearMsg)) {
try {
- byte[] encryptedBuffer = encryptMessageJni(aClearMsg.getBytes("UTF-8"));
+ byte[] clearMsgBuffer = aClearMsg.getBytes("UTF-8");
+ byte[] encryptedBuffer = encryptMessageJni(clearMsgBuffer);
+ Arrays.fill(clearMsgBuffer, (byte) 0);
if (null != encryptedBuffer) {
retValue = new String(encryptedBuffer , "UTF-8");
diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkDecryption.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkDecryption.java
index 03d055a..ea838f1 100644
--- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkDecryption.java
+++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkDecryption.java
@@ -18,6 +18,8 @@ package org.matrix.olm;
import android.util.Log;
+import java.util.Arrays;
+
public class OlmPkDecryption {
private static final String LOG_TAG = "OlmPkDecryption";
@@ -67,7 +69,10 @@ public class OlmPkDecryption {
}
try {
- return new String(decryptJni(aMessage), "UTF-8");
+ byte[] plaintextBuffer = decryptJni(aMessage);
+ String plaintext = new String(plaintextBuffer, "UTF-8");
+ Arrays.fill(plaintextBuffer, (byte) 0);
+ return plaintext;
} catch (Exception e) {
Log.e(LOG_TAG, "## pkDecrypt(): failed " + e.getMessage());
throw new OlmException(OlmException.EXCEPTION_CODE_PK_DECRYPTION_DECRYPT, e.getMessage());
diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkEncryption.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkEncryption.java
index 9bd429d..a2ccf2e 100644
--- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkEncryption.java
+++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkEncryption.java
@@ -18,6 +18,8 @@ package org.matrix.olm;
import android.util.Log;
+import java.util.Arrays;
+
public class OlmPkEncryption {
private static final String LOG_TAG = "OlmPkEncryption";
@@ -72,7 +74,9 @@ public class OlmPkEncryption {
OlmPkMessage encryptedMsgRetValue = new OlmPkMessage();
try {
- byte[] ciphertextBuffer = encryptJni(aPlaintext.getBytes("UTF-8"), encryptedMsgRetValue);
+ byte[] plaintextBuffer = aPlaintext.getBytes("UTF-8");
+ byte[] ciphertextBuffer = encryptJni(plaintextBuffer, encryptedMsgRetValue);
+ Arrays.fill(plaintextBuffer, (byte) 0);
if (null != ciphertextBuffer) {
encryptedMsgRetValue.mCipherText = new String(ciphertextBuffer, "UTF-8");
diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmSession.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmSession.java
index da2e963..3c5ce49 100644
--- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmSession.java
+++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmSession.java
@@ -25,6 +25,8 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.util.Arrays;
+
/**
* Session class used to create Olm sessions in conjunction with {@link OlmAccount} class.<br>
* Olm session is used to encrypt data between devices, especially to create Olm group sessions (see {@link OlmOutboundGroupSession} and {@link OlmInboundGroupSession}).<br>
@@ -295,7 +297,9 @@ public class OlmSession extends CommonSerializeUtils implements Serializable {
OlmMessage encryptedMsgRetValue = new OlmMessage();
try {
- byte[] encryptedMessageBuffer = encryptMessageJni(aClearMsg.getBytes("UTF-8"), encryptedMsgRetValue);
+ byte[] clearMsgBuffer = aClearMsg.getBytes("UTF-8");
+ byte[] encryptedMessageBuffer = encryptMessageJni(clearMsgBuffer, encryptedMsgRetValue);
+ Arrays.fill(clearMsgBuffer, (byte) 0);
if (null != encryptedMessageBuffer) {
encryptedMsgRetValue.mCipherText = new String(encryptedMessageBuffer, "UTF-8");
@@ -330,7 +334,10 @@ public class OlmSession extends CommonSerializeUtils implements Serializable {
}
try {
- return new String(decryptMessageJni(aEncryptedMsg), "UTF-8");
+ byte[] plaintextBuffer = decryptMessageJni(aEncryptedMsg);
+ String plaintext = new String(plaintextBuffer, "UTF-8");
+ Arrays.fill(plaintextBuffer, (byte) 0);
+ return plaintext;
} catch (Exception e) {
Log.e(LOG_TAG, "## decryptMessage(): failed " + e.getMessage());
throw new OlmException(OlmException.EXCEPTION_CODE_SESSION_DECRYPT_MESSAGE, e.getMessage());
diff --git a/android/olm-sdk/src/main/jni/olm_outbound_group_session.cpp b/android/olm-sdk/src/main/jni/olm_outbound_group_session.cpp
index a821709..b11c474 100644
--- a/android/olm-sdk/src/main/jni/olm_outbound_group_session.cpp
+++ b/android/olm-sdk/src/main/jni/olm_outbound_group_session.cpp
@@ -297,6 +297,7 @@ JNIEXPORT jbyteArray OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(encryptMessageJni)(JNIE
OlmOutboundGroupSession *sessionPtr = NULL;
jbyte* clearMsgPtr = NULL;
+ jboolean clearMsgIsCopied = JNI_FALSE;
if (!(sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz)))
{
@@ -308,7 +309,7 @@ JNIEXPORT jbyteArray OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(encryptMessageJni)(JNIE
LOGE(" ## encryptMessageJni(): failure - invalid clear message");
errorMessage = "invalid clear message";
}
- else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, NULL)))
+ else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, &clearMsgIsCopied)))
{
LOGE(" ## encryptMessageJni(): failure - clear message JNI allocation OOM");
errorMessage = "clear message JNI allocation OOM";
@@ -359,6 +360,10 @@ JNIEXPORT jbyteArray OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(encryptMessageJni)(JNIE
// free alloc
if (clearMsgPtr)
{
+ if (clearMsgIsCopied)
+ {
+ memset(clearMsgPtr, 0, (size_t)env->GetArrayLength(aClearMsgBuffer));
+ }
env->ReleaseByteArrayElements(aClearMsgBuffer, clearMsgPtr, JNI_ABORT);
}
diff --git a/android/olm-sdk/src/main/jni/olm_pk.cpp b/android/olm-sdk/src/main/jni/olm_pk.cpp
index 2e936c6..12528de 100644
--- a/android/olm-sdk/src/main/jni/olm_pk.cpp
+++ b/android/olm-sdk/src/main/jni/olm_pk.cpp
@@ -29,7 +29,10 @@ OlmPkEncryption * initializePkEncryptionMemory()
{
// init encryption object
encryptionPtr = olm_pk_encryption(encryptionPtr);
- LOGD("## initializePkEncryptionMemory(): success - OLM encryption size=%lu",static_cast<long unsigned int>(encryptionSize));
+ LOGD(
+ "## initializePkEncryptionMemory(): success - OLM encryption size=%lu",
+ static_cast<long unsigned int>(encryptionSize)
+ );
}
else
{
@@ -53,7 +56,10 @@ JNIEXPORT jlong OLM_PK_ENCRYPTION_FUNC_DEF(createNewPkEncryptionJni)(JNIEnv *env
else
{
LOGD("## createNewPkEncryptionJni(): success - OLM encryption created");
- LOGD("## createNewPkEncryptionJni(): encryptionPtr=%p (jlong)(intptr_t)encryptionPtr=%lld", encryptionPtr, (jlong)(intptr_t)encryptionPtr);
+ LOGD(
+ "## createNewPkEncryptionJni(): encryptionPtr=%p (jlong)(intptr_t)encryptionPtr=%lld",
+ encryptionPtr, (jlong)(intptr_t)encryptionPtr
+ );
}
if (errorMessage)
@@ -93,8 +99,9 @@ JNIEXPORT void OLM_PK_ENCRYPTION_FUNC_DEF(releasePkEncryptionJni)(JNIEnv *env, j
}
}
-JNIEXPORT void OLM_PK_ENCRYPTION_FUNC_DEF(setRecipientKeyJni)(JNIEnv *env, jobject thiz, jbyteArray aKeyBuffer)
-{
+JNIEXPORT void OLM_PK_ENCRYPTION_FUNC_DEF(setRecipientKeyJni)(
+ JNIEnv *env, jobject thiz, jbyteArray aKeyBuffer
+) {
const char *errorMessage = NULL;
jbyte *keyPtr = NULL;
@@ -116,10 +123,13 @@ JNIEXPORT void OLM_PK_ENCRYPTION_FUNC_DEF(setRecipientKeyJni)(JNIEnv *env, jobje
}
else
{
- if(olm_pk_encryption_set_recipient_key(encryptionPtr, keyPtr, (size_t)env->GetArrayLength(aKeyBuffer)) == olm_error())
+ if (olm_pk_encryption_set_recipient_key(encryptionPtr, keyPtr, (size_t)env->GetArrayLength(aKeyBuffer)) == olm_error())
{
errorMessage = olm_pk_encryption_last_error(encryptionPtr);
- LOGE(" ## pkSetRecipientKeyJni(): failure - olm_pk_encryption_set_recipient_key Msg=%s", errorMessage);
+ LOGE(
+ " ## pkSetRecipientKeyJni(): failure - olm_pk_encryption_set_recipient_key Msg=%s",
+ errorMessage
+ );
}
}
@@ -134,11 +144,13 @@ JNIEXPORT void OLM_PK_ENCRYPTION_FUNC_DEF(setRecipientKeyJni)(JNIEnv *env, jobje
}
}
-JNIEXPORT jbyteArray OLM_PK_ENCRYPTION_FUNC_DEF(encryptJni)(JNIEnv *env, jobject thiz, jbyteArray aPlaintextBuffer, jobject aEncryptedMsg)
-{
+JNIEXPORT jbyteArray OLM_PK_ENCRYPTION_FUNC_DEF(encryptJni)(
+ JNIEnv *env, jobject thiz, jbyteArray aPlaintextBuffer, jobject aEncryptedMsg
+) {
jbyteArray encryptedMsgRet = 0;
const char* errorMessage = NULL;
jbyte *plaintextPtr = NULL;
+ jboolean plaintextIsCopied = JNI_FALSE;
OlmPkEncryption *encryptionPtr = getPkEncryptionInstanceId(env, thiz);
jclass encryptedMsgJClass = 0;
@@ -154,15 +166,15 @@ JNIEXPORT jbyteArray OLM_PK_ENCRYPTION_FUNC_DEF(encryptJni)(JNIEnv *env, jobject
LOGE(" ## pkEncryptJni(): failure - invalid clear message");
errorMessage = "invalid clear message";
}
- else if (!(plaintextPtr = env->GetByteArrayElements(aPlaintextBuffer, 0)))
+ else if (!(plaintextPtr = env->GetByteArrayElements(aPlaintextBuffer, &plaintextIsCopied)))
{
LOGE(" ## pkEncryptJni(): failure - plaintext JNI allocation OOM");
errorMessage = "plaintext JNI allocation OOM";
}
else if (!(encryptedMsgJClass = env->GetObjectClass(aEncryptedMsg)))
{
- LOGE(" ## pkEncryptJni(): failure - unable to get crypted message class");
- errorMessage = "unable to get crypted message class";
+ LOGE(" ## pkEncryptJni(): failure - unable to get encrypted message class");
+ errorMessage = "unable to get encrypted message class";
}
else if (!(macFieldId = env->GetFieldID(encryptedMsgJClass, "mMac", "Ljava/lang/String;")))
{
@@ -226,7 +238,9 @@ JNIEXPORT jbyteArray OLM_PK_ENCRYPTION_FUNC_DEF(encryptJni)(JNIEnv *env, jobject
else
{
encryptedMsgRet = env->NewByteArray(ciphertextLength);
- env->SetByteArrayRegion(encryptedMsgRet, 0, ciphertextLength, (jbyte*)ciphertextPtr);
+ env->SetByteArrayRegion(
+ encryptedMsgRet, 0, ciphertextLength, (jbyte*)ciphertextPtr
+ );
jstring macStr = env->NewStringUTF((char*)macPtr);
env->SetObjectField(aEncryptedMsg, macFieldId, macStr);
@@ -256,6 +270,10 @@ JNIEXPORT jbyteArray OLM_PK_ENCRYPTION_FUNC_DEF(encryptJni)(JNIEnv *env, jobject
if (plaintextPtr)
{
+ if (plaintextIsCopied)
+ {
+ memset(plaintextPtr, 0, (size_t)env->GetArrayLength(aPlaintextBuffer));
+ }
env->ReleaseByteArrayElements(aPlaintextBuffer, plaintextPtr, JNI_ABORT);
}
@@ -276,7 +294,10 @@ OlmPkDecryption * initializePkDecryptionMemory()
{
// init decryption object
decryptionPtr = olm_pk_decryption(decryptionPtr);
- LOGD("## initializePkDecryptionMemory(): success - OLM decryption size=%lu",static_cast<long unsigned int>(decryptionSize));
+ LOGD(
+ "## initializePkDecryptionMemory(): success - OLM decryption size=%lu",
+ static_cast<long unsigned int>(decryptionSize)
+ );
}
else
{
@@ -300,7 +321,10 @@ JNIEXPORT jlong OLM_PK_DECRYPTION_FUNC_DEF(createNewPkDecryptionJni)(JNIEnv *env
else
{
LOGD("## createNewPkDecryptionJni(): success - OLM decryption created");
- LOGD("## createNewPkDecryptionJni(): decryptionPtr=%p (jlong)(intptr_t)decryptionPtr=%lld", decryptionPtr, (jlong)(intptr_t)decryptionPtr);
+ LOGD(
+ "## createNewPkDecryptionJni(): decryptionPtr=%p (jlong)(intptr_t)decryptionPtr=%lld",
+ decryptionPtr, (jlong)(intptr_t)decryptionPtr
+ );
}
if (errorMessage)
@@ -402,8 +426,9 @@ JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(generateKeyJni)(JNIEnv *env, job
return publicKeyRet;
}
-JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(decryptJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg)
-{
+JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(decryptJni)(
+ JNIEnv *env, jobject thiz, jobject aEncryptedMsg
+) {
const char* errorMessage = NULL;
OlmPkDecryption *decryptionPtr = getPkDecryptionInstanceId(env, thiz);
@@ -528,7 +553,10 @@ JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(decryptJni)(JNIEnv *env, jobject
{
decryptedMsgRet = env->NewByteArray(plaintextLength);
env->SetByteArrayRegion(decryptedMsgRet, 0, plaintextLength, (jbyte*)plaintextPtr);
- LOGD("## pkDecryptJni(): success returnedLg=%lu OK", static_cast<long unsigned int>(plaintextLength));
+ LOGD(
+ "## pkDecryptJni(): success returnedLg=%lu OK",
+ static_cast<long unsigned int>(plaintextLength)
+ );
}
}
@@ -538,6 +566,7 @@ JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(decryptJni)(JNIEnv *env, jobject
}
if (plaintextPtr)
{
+ memset(plaintextPtr, 0, maxPlaintextLength);
free(plaintextPtr);
}
}
diff --git a/android/olm-sdk/src/main/jni/olm_session.cpp b/android/olm-sdk/src/main/jni/olm_session.cpp
index 5ca49db..b9db286 100644
--- a/android/olm-sdk/src/main/jni/olm_session.cpp
+++ b/android/olm-sdk/src/main/jni/olm_session.cpp
@@ -472,6 +472,7 @@ JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobjec
OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
jbyte *clearMsgPtr = NULL;
+ jboolean clearMsgIsCopied = JNI_FALSE;
jclass encryptedMsgJClass = 0;
jfieldID typeMsgFieldId;
@@ -490,8 +491,9 @@ JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobjec
else if (!aEncryptedMsg)
{
LOGE("## encryptMessageJni(): failure - invalid encrypted message");
+ errorMessage = "invalid encrypted message";
}
- else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, 0)))
+ else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, &clearMsgIsCopied)))
{
LOGE("## encryptMessageJni(): failure - clear message JNI allocation OOM");
errorMessage = "clear message JNI allocation OOM";
@@ -580,6 +582,10 @@ JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobjec
// free alloc
if (clearMsgPtr)
{
+ if (clearMsgIsCopied)
+ {
+ memset(clearMsgPtr, 0, (size_t)env->GetArrayLength(aClearMsgBuffer));
+ }
env->ReleaseByteArrayElements(aClearMsgBuffer, clearMsgPtr, JNI_ABORT);
}
@@ -702,6 +708,8 @@ JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobjec
LOGD(" ## decryptMessageJni(): UTF-8 Conversion - decrypted returnedLg=%lu OK",static_cast<long unsigned int>(plaintextLength));
}
+
+ memset(plainTextMsgPtr, 0, maxPlainTextLength);
}
}
@@ -958,4 +966,4 @@ JNIEXPORT jlong OLM_SESSION_FUNC_DEF(deserializeJni)(JNIEnv *env, jobject thiz,
}
return (jlong)(intptr_t)sessionPtr;
-} \ No newline at end of file
+}
diff --git a/docs/olm.rst b/docs/olm.rst
index a18662d..9c13478 100644
--- a/docs/olm.rst
+++ b/docs/olm.rst
@@ -72,7 +72,7 @@ info.
Advancing the chain key
~~~~~~~~~~~~~~~~~~~~~~~
-Advancing a chain key takes the previous chain key, :math:`C_{i,j-i}`. The next
+Advancing a chain key takes the previous chain key, :math:`C_{i,j-1}`. The next
chain key, :math:`C_{i,j}`, is the HMAC-SHA-256_ of ``"\x02"`` using the
previous chain key as the key.
@@ -338,7 +338,7 @@ The Olm specification (this document) is hereby placed in the public domain.
Feedback
--------
-Can be sent to mark at matrix.org.
+Can be sent to olm at matrix.org.
Acknowledgements
----------------
diff --git a/docs/signing.rst b/docs/signing.rst
index 7387794..05c55eb 100644
--- a/docs/signing.rst
+++ b/docs/signing.rst
@@ -113,6 +113,6 @@ This document is licensed under the `Apache License, Version 2.0
Feedback
--------
-Questions and feedback can be sent to richard at matrix.org.
+Questions and feedback can be sent to olm at matrix.org.
.. _`Ed25519`: http://ed25519.cr.yp.to/
diff --git a/exports.py b/exports.py
new file mode 100755
index 0000000..b37cbbb
--- /dev/null
+++ b/exports.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+import sys
+import re
+import json
+
+expr = re.compile(r"(olm_[^( ]*)\(")
+
+exports = set()
+
+for f in sys.argv[1:]:
+ with open(f) as fp:
+ for line in fp:
+ matches = expr.search(line)
+ if matches is not None:
+ exports.add('_%s' % (matches.group(1),))
+
+json.dump(sorted(exports), sys.stdout)
diff --git a/include/olm/error.h b/include/olm/error.h
index 9d44a94..ee2187c 100644
--- a/include/olm/error.h
+++ b/include/olm/error.h
@@ -51,6 +51,13 @@ enum OlmErrorCode {
*/
OLM_BAD_SIGNATURE = 14,
+ OLM_INPUT_BUFFER_TOO_SMALL = 15,
+
+ // Not an error code, just here to pad out the enum past 16 because
+ // otherwise the compiler warns about a redunant check. If you're
+ // adding an error code, replace this one!
+ OLM_ERROR_NOT_INVENTED_YET = 16,
+
/* remember to update the list of string constants in error.c when updating
* this list. */
};
diff --git a/include/olm/pk.h b/include/olm/pk.h
index 1f3f9ff..4278fca 100644
--- a/include/olm/pk.h
+++ b/include/olm/pk.h
@@ -72,11 +72,15 @@ size_t olm_pk_encrypt_random_length(
);
/** Encrypt a plaintext for the recipient set using
- * olm_pk_encryption_set_recipient_key. Returns olm_error() on failure. If the
- * ciphertext, mac, or ephemeral_key buffers were too small then
- * olm_pk_encryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". If there
- * weren't enough random bytes then olm_pk_encryption_last_error() will be
- * "NOT_ENOUGH_RANDOM". */
+ * olm_pk_encryption_set_recipient_key. Writes to the ciphertext, mac, and
+ * ephemeral_key buffers, whose values should be sent to the recipient. mac is
+ * a Message Authentication Code to ensure that the data is received and
+ * decrypted properly. ephemeral_key is the public part of the ephemeral key
+ * used (together with the recipient's key) to generate a symmetric encryption
+ * key. Returns olm_error() on failure. If the ciphertext, mac, or
+ * ephemeral_key buffers were too small then olm_pk_encryption_last_error()
+ * will be "OUTPUT_BUFFER_TOO_SMALL". If there weren't enough random bytes then
+ * olm_pk_encryption_last_error() will be "OLM_INPUT_BUFFER_TOO_SMALL". */
size_t olm_pk_encrypt(
OlmPkEncryption *encryption,
void const * plaintext, size_t plaintext_length,
@@ -108,18 +112,36 @@ size_t olm_clear_pk_decryption(
OlmPkDecryption *decryption
);
-/** The number of random bytes needed to generate a new key. */
+/** Get the number of bytes required to store an olm private key
+ */
+size_t olm_pk_private_key_length();
+
+/** DEPRECATED: Use olm_pk_private_key_length()
+ */
size_t olm_pk_generate_key_random_length(void);
-/** Generate a new key to use for decrypting messages. The associated public
- * key will be written to the pubkey buffer. Returns olm_error() on failure. If
- * the pubkey buffer is too small then olm_pk_decryption_last_error() will be
- * "OUTPUT_BUFFER_TOO_SMALL". If there weren't enough random bytes then
- * olm_pk_decryption_last_error() will be "NOT_ENOUGH_RANDOM". */
+/** Initialise the key from the private part of a key as returned by
+ * olm_pk_get_private_key(). The associated public key will be written to the
+ * pubkey buffer. Returns olm_error() on failure. If the pubkey buffer is too
+ * small then olm_pk_decryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL".
+ * If the private key was not long enough then olm_pk_decryption_last_error()
+ * will be "OLM_INPUT_BUFFER_TOO_SMALL".
+ *
+ * Note that the pubkey is a base64 encoded string, but the private key is
+ * an unencoded byte array
+ */
+size_t olm_pk_key_from_private(
+ OlmPkDecryption * decryption,
+ void * pubkey, size_t pubkey_length,
+ void * privkey, size_t privkey_length
+);
+
+/** DEPRECATED: Use olm_pk_key_from_private
+ */
size_t olm_pk_generate_key(
OlmPkDecryption * decryption,
void * pubkey, size_t pubkey_length,
- void * random, size_t random_length
+ void * privkey, size_t privkey_length
);
/** Returns the number of bytes needed to store a decryption object. */
@@ -159,18 +181,32 @@ size_t olm_pk_max_plaintext_length(
size_t ciphertext_length
);
-/** Decrypt a ciphertext. The input ciphertext buffer is destroyed. Returns
- * the length of the plaintext on success. Returns olm_error() on failure. If
- * the plaintext buffer is too small then olm_pk_encryption_last_error() will
- * be "OUTPUT_BUFFER_TOO_SMALL". */
+/** Decrypt a ciphertext. The input ciphertext buffer is destroyed. See the
+ * olm_pk_encrypt function for descriptions of the ephemeral_key and mac
+ * arguments. Returns the length of the plaintext on success. Returns
+ * olm_error() on failure. If the plaintext buffer is too small then
+ * olm_pk_encryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". */
size_t olm_pk_decrypt(
- OlmPkDecryption * decrytion,
+ OlmPkDecryption * decryption,
void const * ephemeral_key, size_t ephemeral_key_length,
void const * mac, size_t mac_length,
void * ciphertext, size_t ciphertext_length,
void * plaintext, size_t max_plaintext_length
);
+/**
+ * Get the private key for an OlmDecryption object as an unencoded byte array
+ * private_key must be a pointer to a buffer of at least
+ * olm_pk_private_key_length() bytes and this length must be passed in
+ * private_key_length. If the given buffer is too small, returns olm_error()
+ * and olm_pk_encryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL".
+ * Returns the number of bytes written.
+ */
+size_t olm_pk_get_private_key(
+ OlmPkDecryption * decryption,
+ void *private_key, size_t private_key_length
+);
+
#ifdef __cplusplus
}
#endif
diff --git a/javascript/.gitignore b/javascript/.gitignore
index ec22345..3437f73 100644
--- a/javascript/.gitignore
+++ b/javascript/.gitignore
@@ -2,4 +2,5 @@
/node_modules
/npm-debug.log
/olm.js
+/olm.wasm
/reports
diff --git a/javascript/externs.js b/javascript/externs.js
new file mode 100644
index 0000000..752e937
--- /dev/null
+++ b/javascript/externs.js
@@ -0,0 +1,4 @@
+var OLM_OPTIONS;
+var olm_exports;
+var onInitSuccess;
+var onInitFail;
diff --git a/javascript/olm_inbound_group_session.js b/javascript/olm_inbound_group_session.js
index 6bc745d..7d9e401 100644
--- a/javascript/olm_inbound_group_session.js
+++ b/javascript/olm_inbound_group_session.js
@@ -1,9 +1,3 @@
-/* The 'length' argument to Pointer_stringify doesn't work if the input includes
- * characters >= 128; we therefore need to add a NULL character to all of our
- * strings. This acts as a symbolic constant to help show what we're doing.
- */
-var NULL_BYTE_PADDING_LENGTH = 1;
-
function InboundGroupSession() {
var size = Module['_olm_inbound_group_session_size']();
this.buf = malloc(size);
@@ -77,14 +71,14 @@ InboundGroupSession.prototype['decrypt'] = restore_stack(function(
try {
message_buffer = malloc(message.length);
- Module['writeAsciiToMemory'](message, message_buffer, true);
+ writeAsciiToMemory(message, message_buffer, true);
var max_plaintext_length = inbound_group_session_method(
Module['_olm_group_decrypt_max_plaintext_length']
)(this.ptr, message_buffer, message.length);
// caculating the length destroys the input buffer, so we need to re-copy it.
- Module['writeAsciiToMemory'](message, message_buffer, true);
+ writeAsciiToMemory(message, message_buffer, true);
plaintext_buffer = malloc(max_plaintext_length + NULL_BYTE_PADDING_LENGTH);
var message_index = stack(4);
@@ -100,14 +94,14 @@ InboundGroupSession.prototype['decrypt'] = restore_stack(function(
// UTF8ToString requires a null-terminated argument, so add the
// null terminator.
- Module['setValue'](
+ setValue(
plaintext_buffer+plaintext_length,
0, "i8"
);
return {
"plaintext": UTF8ToString(plaintext_buffer),
- "message_index": Module['getValue'](message_index, "i32")
+ "message_index": getValue(message_index, "i32")
}
} finally {
if (message_buffer !== undefined) {
diff --git a/javascript/olm_outbound_group_session.js b/javascript/olm_outbound_group_session.js
index 24ea644..e232883 100644
--- a/javascript/olm_outbound_group_session.js
+++ b/javascript/olm_outbound_group_session.js
@@ -1,10 +1,3 @@
-/* The 'length' argument to Pointer_stringify doesn't work if the input includes
- * characters >= 128; we therefore need to add a NULL character to all of our
- * strings. This acts as a symbolic constant to help show what we're doing.
- */
-var NULL_BYTE_PADDING_LENGTH = 1;
-
-
function OutboundGroupSession() {
var size = Module['_olm_outbound_group_session_size']();
this.buf = malloc(size);
@@ -66,7 +59,7 @@ OutboundGroupSession.prototype['create'] = restore_stack(function() {
OutboundGroupSession.prototype['encrypt'] = function(plaintext) {
var plaintext_buffer, message_buffer, plaintext_length;
try {
- plaintext_length = Module['lengthBytesUTF8'](plaintext);
+ plaintext_length = lengthBytesUTF8(plaintext);
var message_length = outbound_group_session_method(
Module['_olm_group_encrypt_message_length']
@@ -75,7 +68,7 @@ OutboundGroupSession.prototype['encrypt'] = function(plaintext) {
// need to allow space for the terminator (which stringToUTF8 always
// writes), hence + 1.
plaintext_buffer = malloc(plaintext_length + 1);
- Module['stringToUTF8'](plaintext, plaintext_buffer, plaintext_length + 1);
+ stringToUTF8(plaintext, plaintext_buffer, plaintext_length + 1);
message_buffer = malloc(message_length + NULL_BYTE_PADDING_LENGTH);
outbound_group_session_method(Module['_olm_group_encrypt'])(
@@ -86,12 +79,12 @@ OutboundGroupSession.prototype['encrypt'] = function(plaintext) {
// UTF8ToString requires a null-terminated argument, so add the
// null terminator.
- Module['setValue'](
+ setValue(
message_buffer+message_length,
0, "i8"
);
- return Module['UTF8ToString'](message_buffer);
+ return UTF8ToString(message_buffer);
} finally {
if (plaintext_buffer !== undefined) {
// don't leave a copy of the plaintext in the heap.
diff --git a/javascript/olm_pk.js b/javascript/olm_pk.js
index 2542707..4f730dd 100644
--- a/javascript/olm_pk.js
+++ b/javascript/olm_pk.js
@@ -35,9 +35,9 @@ PkEncryption.prototype['encrypt'] = restore_stack(function(
) {
var plaintext_buffer, ciphertext_buffer, plaintext_length;
try {
- plaintext_length = Module['lengthBytesUTF8'](plaintext)
+ plaintext_length = lengthBytesUTF8(plaintext)
plaintext_buffer = malloc(plaintext_length + 1);
- Module['stringToUTF8'](plaintext, plaintext_buffer, plaintext_length + 1);
+ stringToUTF8(plaintext, plaintext_buffer, plaintext_length + 1);
var random_length = pk_encryption_method(
Module['_olm_pk_encrypt_random_length']
)();
@@ -50,16 +50,16 @@ PkEncryption.prototype['encrypt'] = restore_stack(function(
Module['_olm_pk_mac_length']
)(this.ptr);
var mac_buffer = stack(mac_length + NULL_BYTE_PADDING_LENGTH);
- Module['setValue'](
- mac_buffer+mac_length,
+ setValue(
+ mac_buffer + mac_length,
0, "i8"
);
var ephemeral_length = pk_encryption_method(
Module['_olm_pk_key_length']
)();
var ephemeral_buffer = stack(ephemeral_length + NULL_BYTE_PADDING_LENGTH);
- Module['setValue'](
- ephemeral_buffer+ephemeral_length,
+ setValue(
+ ephemeral_buffer + ephemeral_length,
0, "i8"
);
pk_encryption_method(Module['_olm_pk_encrypt'])(
@@ -72,12 +72,12 @@ PkEncryption.prototype['encrypt'] = restore_stack(function(
);
// UTF8ToString requires a null-terminated argument, so add the
// null terminator.
- Module['setValue'](
- ciphertext_buffer+ciphertext_length,
+ setValue(
+ ciphertext_buffer + ciphertext_length,
0, "i8"
);
return {
- "ciphertext": Module['UTF8ToString'](ciphertext_buffer),
+ "ciphertext": UTF8ToString(ciphertext_buffer),
"mac": Pointer_stringify(mac_buffer),
"ephemeral": Pointer_stringify(ephemeral_buffer)
};
@@ -118,16 +118,32 @@ PkDecryption.prototype['free'] = function() {
free(this.ptr);
}
+PkDecryption.prototype['init_with_private_key'] = restore_stack(function (private_key) {
+ var private_key_buffer = stack(private_key.length);
+ Module['HEAPU8'].set(private_key, private_key_buffer);
+
+ var pubkey_length = pk_decryption_method(
+ Module['_olm_pk_key_length']
+ )();
+ var pubkey_buffer = stack(pubkey_length + NULL_BYTE_PADDING_LENGTH);
+ pk_decryption_method(Module['_olm_pk_key_from_private'])(
+ this.ptr,
+ pubkey_buffer, pubkey_length,
+ private_key_buffer, private_key.length
+ );
+ return Pointer_stringify(pubkey_buffer);
+});
+
PkDecryption.prototype['generate_key'] = restore_stack(function () {
var random_length = pk_decryption_method(
- Module['_olm_pk_generate_key_random_length']
+ Module['_olm_pk_private_key_length']
)();
var random_buffer = random_stack(random_length);
- var pubkey_length = pk_encryption_method(
+ var pubkey_length = pk_decryption_method(
Module['_olm_pk_key_length']
)();
var pubkey_buffer = stack(pubkey_length + NULL_BYTE_PADDING_LENGTH);
- pk_decryption_method(Module['_olm_pk_generate_key'])(
+ pk_decryption_method(Module['_olm_pk_key_from_private'])(
this.ptr,
pubkey_buffer, pubkey_length,
random_buffer, random_length
@@ -135,6 +151,18 @@ PkDecryption.prototype['generate_key'] = restore_stack(function () {
return Pointer_stringify(pubkey_buffer);
});
+PkDecryption.prototype['get_private_key'] = restore_stack(function () {
+ var privkey_length = pk_encryption_method(
+ Module['_olm_pk_private_key_length']
+ )();
+ var privkey_buffer = stack(privkey_length);
+ pk_decryption_method(Module['_olm_pk_get_private_key'])(
+ this.ptr,
+ privkey_buffer, privkey_length
+ );
+ return new Uint8Array(Module['HEAPU8'].buffer, privkey_buffer, privkey_length);
+});
+
PkDecryption.prototype['pickle'] = restore_stack(function (key) {
var key_array = array_from_string(key);
var pickle_length = pk_decryption_method(
@@ -169,9 +197,9 @@ PkDecryption.prototype['decrypt'] = restore_stack(function (
) {
var plaintext_buffer, ciphertext_buffer, plaintext_max_length;
try {
- ciphertext_length = Module['lengthBytesUTF8'](ciphertext)
+ var ciphertext_length = lengthBytesUTF8(ciphertext)
ciphertext_buffer = malloc(ciphertext_length + 1);
- Module['stringToUTF8'](ciphertext, ciphertext_buffer, ciphertext_length + 1);
+ stringToUTF8(ciphertext, ciphertext_buffer, ciphertext_length + 1);
var ephemeralkey_array = array_from_string(ephemeral_key);
var ephemeralkey_buffer = stack(ephemeralkey_array);
var mac_array = array_from_string(mac);
@@ -190,11 +218,11 @@ PkDecryption.prototype['decrypt'] = restore_stack(function (
);
// UTF8ToString requires a null-terminated argument, so add the
// null terminator.
- Module['setValue'](
- plaintext_buffer+plaintext_length,
+ setValue(
+ plaintext_buffer + plaintext_length,
0, "i8"
);
- return Module['UTF8ToString'](plaintext_buffer);
+ return UTF8ToString(plaintext_buffer);
} finally {
if (plaintext_buffer !== undefined) {
// don't leave a copy of the plaintext in the heap.
diff --git a/javascript/olm_post.js b/javascript/olm_post.js
index 7a1d284..21ea890 100644
--- a/javascript/olm_post.js
+++ b/javascript/olm_post.js
@@ -1,27 +1,17 @@
-var runtime = Module['Runtime'];
var malloc = Module['_malloc'];
var free = Module['_free'];
-var Pointer_stringify = Module['Pointer_stringify'];
-var OLM_ERROR = Module['_olm_error']();
-
-/* The 'length' argument to Pointer_stringify doesn't work if the input
- * includes characters >= 128, which makes Pointer_stringify unreliable. We
- * could use it on strings which are known to be ascii, but that seems
- * dangerous. Instead we add a NULL character to all of our strings and just
- * use UTF8ToString.
- */
-var NULL_BYTE_PADDING_LENGTH = 1;
+var OLM_ERROR;
/* allocate a number of bytes of storage on the stack.
*
* If size_or_array is a Number, allocates that number of zero-initialised bytes.
*/
function stack(size_or_array) {
- return Module['allocate'](size_or_array, 'i8', Module['ALLOC_STACK']);
+ return allocate(size_or_array, 'i8', Module['ALLOC_STACK']);
}
function array_from_string(string) {
- return Module['intArrayFromString'](string, true);
+ return intArrayFromString(string, true);
}
function random_stack(size) {
@@ -33,11 +23,11 @@ function random_stack(size) {
function restore_stack(wrapped) {
return function() {
- var sp = runtime.stackSave();
+ var sp = stackSave();
try {
return wrapped.apply(this, arguments);
} finally {
- runtime.stackRestore(sp);
+ stackRestore(sp);
}
}
}
@@ -315,7 +305,7 @@ Session.prototype['encrypt'] = restore_stack(function(
Module['_olm_encrypt_message_type']
)(this.ptr);
- plaintext_length = Module['lengthBytesUTF8'](plaintext);
+ plaintext_length = lengthBytesUTF8(plaintext);
var message_length = session_method(
Module['_olm_encrypt_message_length']
)(this.ptr, plaintext_length);
@@ -325,7 +315,7 @@ Session.prototype['encrypt'] = restore_stack(function(
// need to allow space for the terminator (which stringToUTF8 always
// writes), hence + 1.
plaintext_buffer = malloc(plaintext_length + 1);
- Module['stringToUTF8'](plaintext, plaintext_buffer, plaintext_length + 1);
+ stringToUTF8(plaintext, plaintext_buffer, plaintext_length + 1);
message_buffer = malloc(message_length + NULL_BYTE_PADDING_LENGTH);
@@ -338,14 +328,14 @@ Session.prototype['encrypt'] = restore_stack(function(
// UTF8ToString requires a null-terminated argument, so add the
// null terminator.
- Module['setValue'](
+ setValue(
message_buffer+message_length,
0, "i8"
);
return {
"type": message_type,
- "body": Module['UTF8ToString'](message_buffer),
+ "body": UTF8ToString(message_buffer),
};
} finally {
if (plaintext_buffer !== undefined) {
@@ -366,14 +356,14 @@ Session.prototype['decrypt'] = restore_stack(function(
try {
message_buffer = malloc(message.length);
- Module['writeAsciiToMemory'](message, message_buffer, true);
+ writeAsciiToMemory(message, message_buffer, true);
max_plaintext_length = session_method(
Module['_olm_decrypt_max_plaintext_length']
)(this.ptr, message_type, message_buffer, message.length);
// caculating the length destroys the input buffer, so we need to re-copy it.
- Module['writeAsciiToMemory'](message, message_buffer, true);
+ writeAsciiToMemory(message, message_buffer, true);
plaintext_buffer = malloc(max_plaintext_length + NULL_BYTE_PADDING_LENGTH);
@@ -385,7 +375,7 @@ Session.prototype['decrypt'] = restore_stack(function(
// UTF8ToString requires a null-terminated argument, so add the
// null terminator.
- Module['setValue'](
+ setValue(
plaintext_buffer+plaintext_length,
0, "i8"
);
@@ -473,22 +463,3 @@ olm_exports["get_library_version"] = restore_stack(function() {
getValue(buf+2, 'i8'),
];
});
-
-})();
-
-// export the olm functions into the environment.
-//
-// make sure that we do this *after* populating olm_exports, so that we don't
-// get a half-built window.Olm if there is an exception.
-
-if (typeof module !== 'undefined' && module.exports) {
- // node / browserify
- module.exports = olm_exports;
-}
-
-if (typeof(window) !== 'undefined') {
- // We've been imported directly into a browser. Define the global 'Olm' object.
- // (we do this even if module.exports was defined, because it's useful to have
- // Olm in the global scope for browserified and webpacked apps.)
- window["Olm"] = olm_exports;
-}
diff --git a/javascript/olm_pre.js b/javascript/olm_pre.js
index ae7aba5..314d7da 100644
--- a/javascript/olm_pre.js
+++ b/javascript/olm_pre.js
@@ -1,10 +1,7 @@
-var olm_exports = {};
var get_random_values;
-var process; // Shadow the process object so that emscripten won't get
- // confused by browserify
if (typeof(window) !== 'undefined') {
- // We've in a browser (directly, via browserify, or via webpack).
+ // We're in a browser (directly, via browserify, or via webpack).
get_random_values = function(buf) {
window.crypto.getRandomValues(buf);
};
@@ -12,7 +9,9 @@ if (typeof(window) !== 'undefined') {
// We're running in node.
var nodeCrypto = require("crypto");
get_random_values = function(buf) {
- var bytes = nodeCrypto.randomBytes(buf.length);
+ // [''] syntax needed here rather than '.' to prevent
+ // closure compiler from mangling the import(!)
+ var bytes = nodeCrypto['randomBytes'](buf.length);
buf.set(bytes);
};
process = global["process"];
@@ -20,14 +19,31 @@ if (typeof(window) !== 'undefined') {
throw new Error("Cannot find global to attach library to");
}
-(function() {
- /* applications should define OLM_OPTIONS in the environment to override
- * emscripten module settings */
- var Module = {};
- if (typeof(OLM_OPTIONS) !== 'undefined') {
- for (var key in OLM_OPTIONS) {
- if (OLM_OPTIONS.hasOwnProperty(key)) {
- Module[key] = OLM_OPTIONS[key];
- }
+/* applications should define OLM_OPTIONS in the environment to override
+ * emscripten module settings
+ */
+if (typeof(OLM_OPTIONS) !== 'undefined') {
+ for (var olm_option_key in OLM_OPTIONS) {
+ if (OLM_OPTIONS.hasOwnProperty(olm_option_key)) {
+ Module[olm_option_key] = OLM_OPTIONS[olm_option_key];
}
}
+}
+
+/* The 'length' argument to Pointer_stringify doesn't work if the input
+ * includes characters >= 128, which makes Pointer_stringify unreliable. We
+ * could use it on strings which are known to be ascii, but that seems
+ * dangerous. Instead we add a NULL character to all of our strings and just
+ * use UTF8ToString.
+ */
+var NULL_BYTE_PADDING_LENGTH = 1;
+
+Module['onRuntimeInitialized'] = function() {
+ OLM_ERROR = Module['_olm_error']();
+ olm_exports["PRIVATE_KEY_LENGTH"] = Module['_olm_pk_private_key_length']();
+ if (onInitSuccess) onInitSuccess();
+};
+
+Module['onAbort'] = function(err) {
+ if (onInitFail) onInitFail(err);
+};
diff --git a/javascript/olm_prefix.js b/javascript/olm_prefix.js
new file mode 100644
index 0000000..b33dfe9
--- /dev/null
+++ b/javascript/olm_prefix.js
@@ -0,0 +1,3 @@
+var olm_exports = {};
+var onInitSuccess;
+var onInitFail;
diff --git a/javascript/olm_suffix.js b/javascript/olm_suffix.js
new file mode 100644
index 0000000..3e2f664
--- /dev/null
+++ b/javascript/olm_suffix.js
@@ -0,0 +1,32 @@
+var olmInitPromise;
+
+olm_exports['init'] = function(opts) {
+ if (olmInitPromise) return olmInitPromise;
+
+ if (opts) OLM_OPTIONS = opts;
+
+ olmInitPromise = new Promise(function(resolve, reject) {
+ onInitSuccess = function() {
+ resolve();
+ };
+ onInitFail = function(err) {
+ reject(err);
+ };
+ Module();
+ });
+ return olmInitPromise;
+};
+
+if (typeof(window) !== 'undefined') {
+ // We've been imported directly into a browser. Define the global 'Olm' object.
+ // (we do this even if module.exports was defined, because it's useful to have
+ // Olm in the global scope for browserified and webpacked apps.)
+ window["Olm"] = olm_exports;
+}
+
+if (typeof module === 'object') {
+ // Emscripten sets the module exports to be its module
+ // with wrapped c functions. Clobber it with our higher
+ // level wrapper class.
+ module.exports = olm_exports;
+}
diff --git a/javascript/package.json b/javascript/package.json
index 9cae60e..efe3705 100644
--- a/javascript/package.json
+++ b/javascript/package.json
@@ -5,6 +5,7 @@
"main": "olm.js",
"files": [
"olm.js",
+ "olm.wasm",
"README.md"
],
"scripts": {
diff --git a/javascript/test/megolm.spec.js b/javascript/test/megolm.spec.js
index 8f9d24a..241d4bd 100644
--- a/javascript/test/megolm.spec.js
+++ b/javascript/test/megolm.spec.js
@@ -1,5 +1,6 @@
/*
Copyright 2016 OpenMarket Ltd
+Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -21,9 +22,13 @@ var Olm = require('../olm');
describe("megolm", function() {
var aliceSession, bobSession;
- beforeEach(function() {
- aliceSession = new Olm.OutboundGroupSession();
- bobSession = new Olm.InboundGroupSession();
+ beforeEach(function(done) {
+ Olm.init().then(function() {
+ aliceSession = new Olm.OutboundGroupSession();
+ bobSession = new Olm.InboundGroupSession();
+
+ done();
+ });
});
afterEach(function() {
diff --git a/javascript/test/olm.spec.js b/javascript/test/olm.spec.js
index b7cc3ae..77dd712 100644
--- a/javascript/test/olm.spec.js
+++ b/javascript/test/olm.spec.js
@@ -1,5 +1,6 @@
/*
Copyright 2016 OpenMarket Ltd
+Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -30,11 +31,18 @@ describe("olm", function() {
var aliceAccount, bobAccount;
var aliceSession, bobSession;
- beforeEach(function() {
- aliceAccount = new Olm.Account();
- bobAccount = new Olm.Account();
- aliceSession = new Olm.Session();
- bobSession = new Olm.Session();
+ beforeEach(function(done) {
+ // This should really be in a beforeAll, but jasmine-node
+ // doesn't support that
+ debugger;
+ Olm.init().then(function() {
+ aliceAccount = new Olm.Account();
+ bobAccount = new Olm.Account();
+ aliceSession = new Olm.Session();
+ bobSession = new Olm.Session();
+
+ done();
+ });
});
afterEach(function() {
diff --git a/javascript/test/pk.spec.js b/javascript/test/pk.spec.js
index aec90ac..b4b119e 100644
--- a/javascript/test/pk.spec.js
+++ b/javascript/test/pk.spec.js
@@ -18,20 +18,16 @@ limitations under the License.
var Olm = require('../olm');
-if (!Object.keys) {
- Object.keys = function(o) {
- var k=[], p;
- for (p in o) if (Object.prototype.hasOwnProperty.call(o,p)) k.push(p);
- return k;
- }
-}
-
describe("pk", function() {
var encryption, decryption;
- beforeEach(function() {
- encryption = new Olm.PkEncryption();
- decryption = new Olm.PkDecryption();
+ beforeEach(function(done) {
+ Olm.init().then(function() {
+ encryption = new Olm.PkEncryption();
+ decryption = new Olm.PkDecryption();
+
+ done();
+ });
});
afterEach(function () {
@@ -45,6 +41,20 @@ describe("pk", function() {
}
});
+ it('should import & export keys from private parts', function () {
+ var alice_private = new Uint8Array([
+ 0x77, 0x07, 0x6D, 0x0A, 0x73, 0x18, 0xA5, 0x7D,
+ 0x3C, 0x16, 0xC1, 0x72, 0x51, 0xB2, 0x66, 0x45,
+ 0xDF, 0x4C, 0x2F, 0x87, 0xEB, 0xC0, 0x99, 0x2A,
+ 0xB1, 0x77, 0xFB, 0xA5, 0x1D, 0xB9, 0x2C, 0x2A
+ ]);
+ var alice_public = decryption.init_with_private_key(alice_private);
+ expect(alice_public).toEqual("hSDwCYkwp1R0i33ctD73Wg2/Og0mOBr066SpjqqbTmo");
+
+ var alice_private_out = decryption.get_private_key();
+ expect(alice_private_out).toEqual(alice_private);
+ });
+
it('should encrypt and decrypt', function () {
var TEST_TEXT='têst1';
var pubkey = decryption.generate_key();
diff --git a/src/error.c b/src/error.c
index f541a93..5147b5c 100644
--- a/src/error.c
+++ b/src/error.c
@@ -31,6 +31,7 @@ static const char * ERRORS[] = {
"UNKNOWN_MESSAGE_INDEX",
"BAD_LEGACY_ACCOUNT_PICKLE",
"BAD_SIGNATURE",
+ "OLM_INPUT_BUFFER_TOO_SMALL",
};
const char * _olm_error_to_string(enum OlmErrorCode error)
diff --git a/src/pk.cpp b/src/pk.cpp
index b8fe95b..5cfcea2 100644
--- a/src/pk.cpp
+++ b/src/pk.cpp
@@ -22,15 +22,15 @@
#include "olm/pickle_encoding.h"
#include "olm/pickle.hh"
-extern "C" {
-
static const std::size_t MAC_LENGTH = 8;
- const struct _olm_cipher_aes_sha_256 olm_pk_cipher_aes_sha256 =
+const struct _olm_cipher_aes_sha_256 olm_pk_cipher_aes_sha256 =
OLM_CIPHER_INIT_AES_SHA_256("");
const struct _olm_cipher *olm_pk_cipher =
OLM_CIPHER_BASE(&olm_pk_cipher_aes_sha256);
+extern "C" {
+
struct OlmPkEncryption {
OlmErrorCode last_error;
_olm_curve25519_public_key recipient_key;
@@ -73,7 +73,11 @@ size_t olm_pk_encryption_set_recipient_key (
OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL; // FIXME:
return std::size_t(-1);
}
- olm::decode_base64((const uint8_t*)key, olm_pk_key_length(), (uint8_t *)encryption->recipient_key.public_key);
+ olm::decode_base64(
+ (const uint8_t*)key,
+ olm_pk_key_length(),
+ (uint8_t *)encryption->recipient_key.public_key
+ );
return 0;
}
@@ -81,7 +85,9 @@ size_t olm_pk_ciphertext_length(
OlmPkEncryption *encryption,
size_t plaintext_length
) {
- return olm::encode_base64_length(_olm_cipher_aes_sha_256_ops.encrypt_ciphertext_length(olm_pk_cipher, plaintext_length));
+ return olm::encode_base64_length(
+ _olm_cipher_aes_sha_256_ops.encrypt_ciphertext_length(olm_pk_cipher, plaintext_length)
+ );
}
size_t olm_pk_mac_length(
@@ -106,9 +112,9 @@ size_t olm_pk_encrypt(
) {
if (ciphertext_length
< olm_pk_ciphertext_length(encryption, plaintext_length)
- || mac_length
+ || mac_length
< _olm_cipher_aes_sha_256_ops.mac_length(olm_pk_cipher)
- || ephemeral_key_size
+ || ephemeral_key_size
< olm_pk_key_length()) {
encryption->last_error =
OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
@@ -122,11 +128,16 @@ size_t olm_pk_encrypt(
_olm_curve25519_key_pair ephemeral_keypair;
_olm_crypto_curve25519_generate_key((uint8_t *) random, &ephemeral_keypair);
- olm::encode_base64((const uint8_t *)ephemeral_keypair.public_key.public_key, CURVE25519_KEY_LENGTH, (uint8_t *)ephemeral_key);
+ olm::encode_base64(
+ (const uint8_t *)ephemeral_keypair.public_key.public_key,
+ CURVE25519_KEY_LENGTH,
+ (uint8_t *)ephemeral_key
+ );
olm::SharedKey secret;
_olm_crypto_curve25519_shared_secret(&ephemeral_keypair, &encryption->recipient_key, secret);
- size_t raw_ciphertext_length = _olm_cipher_aes_sha_256_ops.encrypt_ciphertext_length(olm_pk_cipher, plaintext_length);
+ size_t raw_ciphertext_length =
+ _olm_cipher_aes_sha_256_ops.encrypt_ciphertext_length(olm_pk_cipher, plaintext_length);
uint8_t *ciphertext_pos = (uint8_t *) ciphertext + ciphertext_length - raw_ciphertext_length;
uint8_t raw_mac[MAC_LENGTH];
size_t result = _olm_cipher_aes_sha_256_ops.encrypt(
@@ -176,35 +187,51 @@ size_t olm_clear_pk_decryption(
return sizeof(OlmPkDecryption);
}
-size_t olm_pk_generate_key_random_length(void) {
+size_t olm_pk_private_key_length(void) {
return CURVE25519_KEY_LENGTH;
}
+size_t olm_pk_generate_key_random_length(void) {
+ return olm_pk_private_key_length();
+}
+
size_t olm_pk_key_length(void) {
return olm::encode_base64_length(CURVE25519_KEY_LENGTH);
}
-size_t olm_pk_generate_key(
+size_t olm_pk_key_from_private(
OlmPkDecryption * decryption,
void * pubkey, size_t pubkey_length,
- void * random, size_t random_length
+ void * privkey, size_t privkey_length
) {
- if (pubkey_length < CURVE25519_KEY_LENGTH) {
+ if (pubkey_length < olm_pk_key_length()) {
decryption->last_error =
OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
return std::size_t(-1);
}
- if (random_length < olm_pk_generate_key_random_length()) {
+ if (privkey_length < olm_pk_private_key_length()) {
decryption->last_error =
- OlmErrorCode::OLM_NOT_ENOUGH_RANDOM;
+ OlmErrorCode::OLM_INPUT_BUFFER_TOO_SMALL;
return std::size_t(-1);
}
- _olm_crypto_curve25519_generate_key((uint8_t *) random, &decryption->key_pair);
- olm::encode_base64((const uint8_t *)decryption->key_pair.public_key.public_key, CURVE25519_KEY_LENGTH, (uint8_t *)pubkey);
+ _olm_crypto_curve25519_generate_key((uint8_t *) privkey, &decryption->key_pair);
+ olm::encode_base64(
+ (const uint8_t *)decryption->key_pair.public_key.public_key,
+ CURVE25519_KEY_LENGTH,
+ (uint8_t *)pubkey
+ );
return 0;
}
+size_t olm_pk_generate_key(
+ OlmPkDecryption * decryption,
+ void * pubkey, size_t pubkey_length,
+ void * privkey, size_t privkey_length
+) {
+ return olm_pk_key_from_private(decryption, pubkey, pubkey_length, privkey, privkey_length);
+}
+
namespace {
static const std::uint32_t PK_DECRYPTION_PICKLE_VERSION = 1;
@@ -267,7 +294,10 @@ size_t olm_pickle_pk_decryption(
return std::size_t(-1);
}
pickle(_olm_enc_output_pos(reinterpret_cast<std::uint8_t *>(pickled), raw_length), object);
- return _olm_enc_output(reinterpret_cast<std::uint8_t const *>(key), key_length, reinterpret_cast<std::uint8_t *>(pickled), raw_length);
+ return _olm_enc_output(
+ reinterpret_cast<std::uint8_t const *>(key), key_length,
+ reinterpret_cast<std::uint8_t *>(pickled), raw_length
+ );
}
size_t olm_unpickle_pk_decryption(
@@ -283,7 +313,8 @@ size_t olm_unpickle_pk_decryption(
}
std::uint8_t * const pos = reinterpret_cast<std::uint8_t *>(pickled);
std::size_t raw_length = _olm_enc_input(
- reinterpret_cast<std::uint8_t const *>(key), key_length, pos, pickled_length, &object.last_error
+ reinterpret_cast<std::uint8_t const *>(key), key_length,
+ pos, pickled_length, &object.last_error
);
if (raw_length == std::size_t(-1)) {
return std::size_t(-1);
@@ -300,7 +331,11 @@ size_t olm_unpickle_pk_decryption(
return std::size_t(-1);
}
if (pubkey != NULL) {
- olm::encode_base64((const uint8_t *)object.key_pair.public_key.public_key, CURVE25519_KEY_LENGTH, (uint8_t *)pubkey);
+ olm::encode_base64(
+ (const uint8_t *)object.key_pair.public_key.public_key,
+ CURVE25519_KEY_LENGTH,
+ (uint8_t *)pubkey
+ );
}
return pickled_length;
}
@@ -309,7 +344,9 @@ size_t olm_pk_max_plaintext_length(
OlmPkDecryption * decryption,
size_t ciphertext_length
) {
- return _olm_cipher_aes_sha_256_ops.decrypt_max_plaintext_length(olm_pk_cipher, olm::decode_base64_length(ciphertext_length));
+ return _olm_cipher_aes_sha_256_ops.decrypt_max_plaintext_length(
+ olm_pk_cipher, olm::decode_base64_length(ciphertext_length)
+ );
}
size_t olm_pk_decrypt(
@@ -327,7 +364,10 @@ size_t olm_pk_decrypt(
}
struct _olm_curve25519_public_key ephemeral;
- olm::decode_base64((const uint8_t*)ephemeral_key, ephemeral_key_length, (uint8_t *)ephemeral.public_key);
+ olm::decode_base64(
+ (const uint8_t*)ephemeral_key, ephemeral_key_length,
+ (uint8_t *)ephemeral.public_key
+ );
olm::SharedKey secret;
_olm_crypto_curve25519_shared_secret(&decryption->key_pair, &ephemeral, secret);
uint8_t raw_mac[MAC_LENGTH];
@@ -352,4 +392,21 @@ size_t olm_pk_decrypt(
}
}
+size_t olm_pk_get_private_key(
+ OlmPkDecryption * decryption,
+ void *private_key, size_t private_key_length
+) {
+ if (private_key_length < olm_pk_private_key_length()) {
+ decryption->last_error =
+ OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
+ return std::size_t(-1);
+ }
+ std::memcpy(
+ private_key,
+ decryption->key_pair.private_key.private_key,
+ olm_pk_private_key_length()
+ );
+ return olm_pk_private_key_length();
+}
+
}
diff --git a/tests/test_pk.cpp b/tests/test_pk.cpp
index ab1f477..42cc8c9 100644
--- a/tests/test_pk.cpp
+++ b/tests/test_pk.cpp
@@ -23,7 +23,7 @@ std::uint8_t alice_private[32] = {
0xB1, 0x77, 0xFB, 0xA5, 0x1D, 0xB9, 0x2C, 0x2A
};
-const std::uint8_t *alice_public = (std::uint8_t *) "hSDwCYkwp1R0i33ctD73Wg2/Og0mOBr066SpjqqbTmoK";
+const std::uint8_t *alice_public = (std::uint8_t *) "hSDwCYkwp1R0i33ctD73Wg2/Og0mOBr066SpjqqbTmo";
std::uint8_t bob_private[32] = {
0x5D, 0xAB, 0x08, 0x7E, 0x62, 0x4A, 0x8A, 0x4B,
@@ -32,11 +32,11 @@ std::uint8_t bob_private[32] = {
0x1C, 0x2F, 0x8B, 0x27, 0xFF, 0x88, 0xE0, 0xEB
};
-const std::uint8_t *bob_public = (std::uint8_t *) "3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08K";
+const std::uint8_t *bob_public = (std::uint8_t *) "3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08";
std::uint8_t pubkey[::olm_pk_key_length()];
-olm_pk_generate_key(
+olm_pk_key_from_private(
decryption,
pubkey, sizeof(pubkey),
alice_private, sizeof(alice_private)
@@ -44,6 +44,11 @@ olm_pk_generate_key(
assert_equals(alice_public, pubkey, olm_pk_key_length());
+uint8_t *alice_private_back_out = (uint8_t *)malloc(olm_pk_private_key_length());
+olm_pk_get_private_key(decryption, alice_private_back_out, olm_pk_private_key_length());
+assert_equals(alice_private, alice_private_back_out, olm_pk_private_key_length());
+free(alice_private_back_out);
+
std::uint8_t encryption_buffer[olm_pk_encryption_size()];
OlmPkEncryption *encryption = olm_pk_encryption(encryption_buffer);
@@ -105,7 +110,7 @@ const std::uint8_t *alice_public = (std::uint8_t *) "hSDwCYkwp1R0i33ctD73Wg2/Og0
std::uint8_t pubkey[olm_pk_key_length()];
-olm_pk_generate_key(
+olm_pk_key_from_private(
decryption,
pubkey, sizeof(pubkey),
alice_private, sizeof(alice_private)