diff --git a/javascript/olm_inbound_group_session.js b/javascript/olm_inbound_group_session.js
index 1b7fcfe52c1a90f1a4e861b815cae67900b093c7..2e4727f72b359d4c0a8032a0056e7272015980f0 100644
--- a/javascript/olm_inbound_group_session.js
+++ b/javascript/olm_inbound_group_session.js
@@ -64,33 +64,51 @@ InboundGroupSession.prototype['create'] = restore_stack(function(session_key) {
 InboundGroupSession.prototype['decrypt'] = restore_stack(function(
     message
 ) {
-    var message_array = array_from_string(message);
-    var message_buffer = stack(message_array);
-    var max_plaintext_length = inbound_group_session_method(
-        Module['_olm_group_decrypt_max_plaintext_length']
-    )(this.ptr, message_buffer, message_array.length);
-    // caculating the length destroys the input buffer.
-    // So we copy the array to a new buffer
-    var message_buffer = stack(message_array);
-    var plaintext_buffer = stack(max_plaintext_length + NULL_BYTE_PADDING_LENGTH);
-    var message_index = stack(4);
-    var plaintext_length = inbound_group_session_method(Module["_olm_group_decrypt"])(
-        this.ptr,
-        message_buffer, message_array.length,
-        plaintext_buffer, max_plaintext_length,
-        message_index
-    );
+    var message_buffer, 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"
-    );
+    try {
+        message_buffer = malloc(message.length);
+        Module['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);
+
+        plaintext_buffer = malloc(max_plaintext_length + NULL_BYTE_PADDING_LENGTH);
+        var message_index = stack(4);
 
-    return {
-        "plaintext": Pointer_stringify(plaintext_buffer),
-        "message_index": Module['getValue'](message_index, "i32")
+        plaintext_length = inbound_group_session_method(
+            Module["_olm_group_decrypt"]
+        )(
+            this.ptr,
+            message_buffer, message.length,
+            plaintext_buffer, max_plaintext_length,
+            message_index
+        );
+
+        // UTF8ToString requires a null-terminated argument, so add the
+        // null terminator.
+        Module['setValue'](
+            plaintext_buffer+plaintext_length,
+            0, "i8"
+        );
+
+        return {
+            "plaintext": UTF8ToString(plaintext_buffer),
+            "message_index": Module['getValue'](message_index, "i32")
+        }
+    } finally {
+        if (message_buffer !== undefined) {
+            free(message_buffer);
+        }
+        if (plaintext_buffer !== undefined) {
+            // don't leave a copy of the plaintext in the heap.
+            bzero(plaintext_buffer, plaintext_length + NULL_BYTE_PADDING_LENGTH);
+            free(plaintext_buffer);
+        }
     }
 });
 
diff --git a/javascript/olm_outbound_group_session.js b/javascript/olm_outbound_group_session.js
index 88a441d535714c8834957e9ed086e463859499d4..0402c3c743a0ee70211035685ba23fe3e83b1bea 100644
--- a/javascript/olm_outbound_group_session.js
+++ b/javascript/olm_outbound_group_session.js
@@ -63,20 +63,38 @@ OutboundGroupSession.prototype['create'] = restore_stack(function() {
     );
 });
 
-OutboundGroupSession.prototype['encrypt'] = restore_stack(function(plaintext) {
-    var plaintext_array = array_from_string(plaintext);
-    var message_length = outbound_group_session_method(
-        Module['_olm_group_encrypt_message_length']
-    )(this.ptr, plaintext_array.length);
-    var plaintext_buffer = stack(plaintext_array);
-    var message_buffer = stack(message_length + NULL_BYTE_PADDING_LENGTH);
-    outbound_group_session_method(Module['_olm_group_encrypt'])(
-        this.ptr,
-        plaintext_buffer, plaintext_array.length,
-        message_buffer, message_length
-    );
-    return Pointer_stringify(message_buffer);
-});
+OutboundGroupSession.prototype['encrypt'] = function(plaintext) {
+    var plaintext_buffer, message_buffer, plaintext_length;
+    try {
+        plaintext_length = Module['lengthBytesUTF8'](plaintext);
+
+        var message_length = outbound_group_session_method(
+            Module['_olm_group_encrypt_message_length']
+        )(this.ptr, plaintext_length);
+
+        // 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);
+
+        message_buffer = malloc(message_length + NULL_BYTE_PADDING_LENGTH);
+        outbound_group_session_method(Module['_olm_group_encrypt'])(
+            this.ptr,
+            plaintext_buffer, plaintext_length,
+            message_buffer, message_length
+        );
+        return Module['UTF8ToString'](message_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 (message_buffer !== undefined) {
+            free(message_buffer);
+        }
+    }
+};
 
 OutboundGroupSession.prototype['session_id'] = restore_stack(function() {
     var length = outbound_group_session_method(
diff --git a/javascript/olm_post.js b/javascript/olm_post.js
index 54e42c52399f649bb176f17d99ff88b50ee4d5c1..3e80c0ba95487bbfb4264a560f1ef8bc78a1cc1b 100644
--- a/javascript/olm_post.js
+++ b/javascript/olm_post.js
@@ -4,9 +4,11 @@ var free = Module['_free'];
 var Pointer_stringify = Module['Pointer_stringify'];
 var OLM_ERROR = Module['_olm_error']();
 
-/* The 'length' argument to Pointer_stringify doesn't work if the input includes
- * characters >= 128; we therefore need to add a NULL character to all of our
- * strings. This acts as a symbolic constant to help show what we're doing.
+/* 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;
 
@@ -40,6 +42,13 @@ function restore_stack(wrapped) {
     }
 }
 
+/* set a memory area to zero */
+function bzero(ptr, n) {
+    while(n-- > 0) {
+        Module['HEAP8'][ptr++] = 0;
+    }
+}
+
 function Account() {
     var size = Module['_olm_account_size']();
     this.buf = malloc(size);
@@ -297,59 +306,94 @@ Session.prototype['matches_inbound_from'] = restore_stack(function(
 Session.prototype['encrypt'] = restore_stack(function(
     plaintext
 ) {
-    var random_length = session_method(
-        Module['_olm_encrypt_random_length']
-    )(this.ptr);
-    var message_type = session_method(
-        Module['_olm_encrypt_message_type']
-    )(this.ptr);
-    var plaintext_array = array_from_string(plaintext);
-    var message_length = session_method(
-        Module['_olm_encrypt_message_length']
-    )(this.ptr, plaintext_array.length);
-    var random = random_stack(random_length);
-    var plaintext_buffer = stack(plaintext_array);
-    var message_buffer = stack(message_length + NULL_BYTE_PADDING_LENGTH);
-    session_method(Module['_olm_encrypt'])(
-        this.ptr,
-        plaintext_buffer, plaintext_array.length,
-        random, random_length,
-        message_buffer, message_length
-    );
-    return {
-        "type": message_type,
-        "body": Pointer_stringify(message_buffer)
-    };
+    var plaintext_buffer, message_buffer, plaintext_length;
+    try {
+        var random_length = session_method(
+            Module['_olm_encrypt_random_length']
+        )(this.ptr);
+        var message_type = session_method(
+            Module['_olm_encrypt_message_type']
+        )(this.ptr);
+
+        plaintext_length = Module['lengthBytesUTF8'](plaintext);
+        var message_length = session_method(
+            Module['_olm_encrypt_message_length']
+        )(this.ptr, plaintext_length);
+
+        var random = random_stack(random_length);
+
+        // 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);
+
+        message_buffer = malloc(message_length + NULL_BYTE_PADDING_LENGTH);
+
+        session_method(Module['_olm_encrypt'])(
+            this.ptr,
+            plaintext_buffer, plaintext_length,
+            random, random_length,
+            message_buffer, message_length
+        );
+        return {
+            "type": message_type,
+            "body": Module['UTF8ToString'](message_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 (message_buffer !== undefined) {
+            free(message_buffer);
+        }
+    }
 });
 
 Session.prototype['decrypt'] = restore_stack(function(
     message_type, message
 ) {
-    var message_array = array_from_string(message);
-    var message_buffer = stack(message_array);
-    var max_plaintext_length = session_method(
-        Module['_olm_decrypt_max_plaintext_length']
-    )(this.ptr, message_type, message_buffer, message_array.length);
-    // caculating the length destroys the input buffer.
-    // So we copy the array to a new buffer
-    var message_buffer = stack(message_array);
-    var plaintext_buffer = stack(
-        max_plaintext_length + NULL_BYTE_PADDING_LENGTH
-    );
-    var plaintext_length = session_method(Module["_olm_decrypt"])(
-        this.ptr, message_type,
-        message_buffer, message.length,
-        plaintext_buffer, max_plaintext_length
-    );
-
-    // 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"
-    );
+    var message_buffer, plaintext_buffer, max_plaintext_length;
+
+    try {
+        message_buffer = malloc(message.length);
+        Module['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);
+
+        plaintext_buffer = malloc(max_plaintext_length + NULL_BYTE_PADDING_LENGTH);
+
+        var plaintext_length = session_method(Module["_olm_decrypt"])(
+            this.ptr, message_type,
+            message_buffer, message.length,
+            plaintext_buffer, max_plaintext_length
+        );
+
+        // UTF8ToString requires a null-terminated argument, so add the
+        // null terminator.
+        Module['setValue'](
+            plaintext_buffer+plaintext_length,
+            0, "i8"
+        );
+
+        return UTF8ToString(plaintext_buffer);
+    } finally {
+        if (message_buffer !== undefined) {
+            free(message_buffer);
+        }
+        if (plaintext_buffer !== undefined) {
+            // don't leave a copy of the plaintext in the heap.
+            bzero(plaintext_buffer, max_plaintext_length + NULL_BYTE_PADDING_LENGTH);
+            free(plaintext_buffer);
+        }
+    }
 
-    return Pointer_stringify(plaintext_buffer);
 });
 
 function Utility() {