aboutsummaryrefslogtreecommitdiff
path: root/javascript
diff options
context:
space:
mode:
authorHubert Chathi <hubert@uhoreg.ca>2018-06-11 17:48:45 -0400
committerHubert Chathi <hubert@uhoreg.ca>2018-06-27 16:38:45 -0400
commit128d45cc83b1378422625ea975152e1e3c9d88f6 (patch)
treec5b0840d4f1b4c49ccd6f14f032b377b424e407d /javascript
parent6a2a2741e8563bbdc4cc2fa3ad41551d2a482d32 (diff)
add initial implementation of basic private key encryption functionality
Diffstat (limited to 'javascript')
-rw-r--r--javascript/olm_pk.js179
-rw-r--r--javascript/olm_post.js2
-rw-r--r--javascript/test/pk.spec.js64
3 files changed, 245 insertions, 0 deletions
diff --git a/javascript/olm_pk.js b/javascript/olm_pk.js
new file mode 100644
index 0000000..e63e907
--- /dev/null
+++ b/javascript/olm_pk.js
@@ -0,0 +1,179 @@
+function PkEncryption() {
+ var size = Module['_olm_pk_encryption_size']();
+ this.buf = malloc(size);
+ this.ptr = Module['_olm_pk_encryption'](this.buf);
+}
+
+function pk_encryption_method(wrapped) {
+ return function() {
+ var result = wrapped.apply(this, arguments);
+ if (result === OLM_ERROR) {
+ var message = Pointer_stringify(
+ Module['_olm_pk_encryption_last_error'](arguments[0])
+ );
+ throw new Error("OLM." + message);
+ }
+ return result;
+ }
+}
+
+PkEncryption.prototype['free'] = function() {
+ Module['_olm_clear_pk_encryption'](this.ptr);
+ free(this.ptr);
+}
+
+PkEncryption.prototype['set_recipient_key'] = restore_stack(function(key) {
+ var key_array = array_from_string(key);
+ var key_buffer = stack(key_array);
+ pk_encryption_method(Module['_olm_pk_encryption_set_recipient_key'])(
+ this.ptr, key_buffer, key_array.length
+ );
+});
+
+PkEncryption.prototype['encrypt'] = restore_stack(function(
+ plaintext
+) {
+ var plaintext_buffer, ciphertext_buffer, plaintext_length;
+ try {
+ plaintext_length = Module['lengthBytesUTF8'](plaintext)
+ plaintext_buffer = malloc(plaintext_length + 1);
+ Module['stringToUTF8'](plaintext, plaintext_buffer, plaintext_length + 1);
+ var random_length = pk_encryption_method(
+ Module['_olm_pk_encrypt_random_length']
+ )();
+ var random = random_stack(random_length);
+ var ciphertext_length = pk_encryption_method(
+ Module['_olm_pk_ciphertext_length']
+ )(this.ptr, plaintext_length);
+ ciphertext_buffer = malloc(ciphertext_length + NULL_BYTE_PADDING_LENGTH);
+ var mac_length = pk_encryption_method(
+ Module['_olm_pk_mac_length']
+ )(this.ptr);
+ var mac_buffer = stack(mac_length + NULL_BYTE_PADDING_LENGTH);
+ Module['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,
+ 0, "i8"
+ );
+ pk_encryption_method(Module['_olm_pk_encrypt'])(
+ this.ptr,
+ plaintext_buffer, plaintext_length,
+ ciphertext_buffer, ciphertext_length,
+ mac_buffer, mac_length,
+ ephemeral_buffer, ephemeral_length,
+ random, random_length
+ );
+ // UTF8ToString requires a null-terminated argument, so add the
+ // null terminator.
+ Module['setValue'](
+ ciphertext_buffer+ciphertext_length,
+ 0, "i8"
+ );
+ return {
+ "ciphertext": Module['UTF8ToString'](ciphertext_buffer),
+ "mac": Pointer_stringify(mac_buffer),
+ "ephemeral": Pointer_stringify(ephemeral_buffer)
+ };
+ } finally {
+ if (plaintext_buffer !== undefined) {
+ // don't leave a copy of the plaintext in the heap.
+ bzero(plaintext_buffer, plaintext_length + 1);
+ free(plaintext_buffer);
+ }
+ if (ciphertext_buffer !== undefined) {
+ free(ciphertext_buffer);
+ }
+ }
+});
+
+
+function PkDecryption() {
+ var size = Module['_olm_pk_decryption_size']();
+ this.buf = malloc(size);
+ this.ptr = Module['_olm_pk_decryption'](this.buf);
+}
+
+function pk_decryption_method(wrapped) {
+ return function() {
+ var result = wrapped.apply(this, arguments);
+ if (result === OLM_ERROR) {
+ var message = Pointer_stringify(
+ Module['_olm_pk_decryption_last_error'](arguments[0])
+ );
+ throw new Error("OLM." + message);
+ }
+ return result;
+ }
+}
+
+PkDecryption.prototype['free'] = function() {
+ Module['_olm_clear_pk_decryption'](this.ptr);
+ free(this.ptr);
+}
+
+PkDecryption.prototype['generate_key'] = restore_stack(function () {
+ var random_length = pk_decryption_method(
+ Module['_olm_pk_key_length'] // FIXME: wrong method
+ )();
+ var random_buffer = random_stack(random_length);
+ var pubkey_length = pk_encryption_method(
+ Module['_olm_pk_key_length']
+ )();
+ var pubkey_buffer = stack(pubkey_length);
+ pk_decryption_method(Module['_olm_pk_generate_key'])(
+ this.ptr,
+ pubkey_buffer, pubkey_length,
+ random_buffer, random_length
+ );
+ return Pointer_stringify(pubkey_buffer);
+});
+
+PkDecryption.prototype['decrypt'] = restore_stack(function (
+ ephemeral_key, mac, ciphertext
+) {
+ var plaintext_buffer, ciphertext_buffer, plaintext_max_length;
+ try {
+ ciphertext_length = Module['lengthBytesUTF8'](ciphertext)
+ ciphertext_buffer = malloc(ciphertext_length + 1);
+ Module['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);
+ var mac_buffer = stack(mac_array);
+ plaintext_max_length = pk_decryption_method(Module['_olm_pk_max_plaintext_length'])(
+ this.ptr,
+ ciphertext_length
+ );
+ plaintext_buffer = malloc(plaintext_max_length + NULL_BYTE_PADDING_LENGTH);
+ var plaintext_length = pk_decryption_method(Module['_olm_pk_decrypt'])(
+ this.ptr,
+ ephemeralkey_buffer, ephemeralkey_array.length,
+ mac_buffer, mac_array.length,
+ ciphertext_buffer, ciphertext_length,
+ plaintext_buffer, plaintext_max_length
+ );
+ // UTF8ToString requires a null-terminated argument, so add the
+ // null terminator.
+ Module['setValue'](
+ plaintext_buffer+plaintext_length,
+ 0, "i8"
+ );
+ return Module['UTF8ToString'](plaintext_buffer);
+ } finally {
+ if (plaintext_buffer !== undefined) {
+ // don't leave a copy of the plaintext in the heap.
+ bzero(plaintext_buffer, plaintext_length + 1);
+ free(plaintext_buffer);
+ }
+ if (ciphertext_buffer !== undefined) {
+ free(ciphertext_buffer);
+ }
+ }
+})
diff --git a/javascript/olm_post.js b/javascript/olm_post.js
index 91830fa..7a1d284 100644
--- a/javascript/olm_post.js
+++ b/javascript/olm_post.js
@@ -461,6 +461,8 @@ Utility.prototype['ed25519_verify'] = restore_stack(function(
olm_exports["Account"] = Account;
olm_exports["Session"] = Session;
olm_exports["Utility"] = Utility;
+olm_exports["PkEncryption"] = PkEncryption;
+olm_exports["PkDecryption"] = PkDecryption;
olm_exports["get_library_version"] = restore_stack(function() {
var buf = stack(3);
diff --git a/javascript/test/pk.spec.js b/javascript/test/pk.spec.js
new file mode 100644
index 0000000..9eec47e
--- /dev/null
+++ b/javascript/test/pk.spec.js
@@ -0,0 +1,64 @@
+/*
+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.
+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.
+*/
+
+"use strict";
+
+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();
+ });
+
+ afterEach(function () {
+ if (encryption !== undefined) {
+ encryption.free();
+ encryption = undefined;
+ }
+ if (decryption !== undefined) {
+ decryption.free();
+ decryption = undefined;
+ }
+ });
+
+ it('should encrypt and decrypt', function () {
+ var TEST_TEXT='têst1';
+ var pubkey = decryption.generate_key();
+ encryption.set_recipient_key(pubkey);
+ var encrypted = encryption.encrypt(TEST_TEXT);
+ var decrypted = decryption.decrypt(encrypted.ephemeral, encrypted.mac, encrypted.ciphertext);
+ console.log(TEST_TEXT, "->", decrypted);
+ expect(decrypted).toEqual(TEST_TEXT);
+
+ TEST_TEXT='hot beverage: ☕';
+ encryption.set_recipient_key(pubkey);
+ encrypted = encryption.encrypt(TEST_TEXT);
+ decrypted = decryption.decrypt(encrypted.ephemeral, encrypted.mac, encrypted.ciphertext);
+ console.log(TEST_TEXT, "->", decrypted);
+ expect(decrypted).toEqual(TEST_TEXT);
+ });
+});