aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/olm/pk.h44
-rw-r--r--javascript/olm_pk.js89
-rw-r--r--javascript/olm_post.js1
-rw-r--r--javascript/test/olm.spec.js1
-rw-r--r--javascript/test/pk.spec.js34
-rw-r--r--src/pk.cpp86
-rw-r--r--tests/test_pk.cpp70
7 files changed, 320 insertions, 5 deletions
diff --git a/include/olm/pk.h b/include/olm/pk.h
index c46baa0..aed14ef 100644
--- a/include/olm/pk.h
+++ b/include/olm/pk.h
@@ -1,4 +1,4 @@
-/* Copyright 2018 New Vector Ltd
+/* Copyright 2018, 2019 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.
@@ -207,6 +207,48 @@ size_t olm_pk_get_private_key(
void *private_key, size_t private_key_length
);
+typedef struct OlmPkSigning OlmPkSigning;
+
+/* The size of a signing object in bytes */
+size_t olm_pk_signing_size(void);
+
+/** Initialise a signing object using the supplied memory
+ * The supplied memory must be at least olm_pk_sign_size() bytes */
+OlmPkSigning *olm_pk_signing(
+ void * memory
+);
+
+/** A null terminated string describing the most recent error to happen to a
+ * signing object */
+const char * olm_pk_signing_last_error(
+ OlmPkSigning * sign
+);
+
+/** Clears the memory used to back this signing object */
+size_t olm_clear_pk_signing(
+ OlmPkSigning *sign
+);
+
+/**
+ * Initialise the signing object with a public/private keypair from a seed
+ */
+size_t olm_pk_signing_key_from_seed(
+ OlmPkSigning * sign,
+ void * pubkey, size_t pubkey_length,
+ void * seed, size_t seed_length
+);
+
+size_t olm_pk_sign_seed_length(void);
+size_t olm_pk_sign_public_key_length(void);
+
+size_t olm_pk_signature_length();
+
+size_t olm_pk_sign(
+ OlmPkSigning *sign,
+ uint8_t const * message, size_t message_length,
+ uint8_t * signature, size_t signature_length
+);
+
#ifdef __cplusplus
}
#endif
diff --git a/javascript/olm_pk.js b/javascript/olm_pk.js
index 81dbad4..9159fbf 100644
--- a/javascript/olm_pk.js
+++ b/javascript/olm_pk.js
@@ -271,3 +271,92 @@ PkDecryption.prototype['decrypt'] = restore_stack(function (
}
}
})
+
+
+function PkSigning() {
+ var size = Module['_olm_pk_signing_size']();
+ this.buf = malloc(size);
+ this.ptr = Module['_olm_pk_signing'](this.buf);
+}
+
+function pk_signing_method(wrapped) {
+ return function() {
+ var result = wrapped.apply(this, arguments);
+ if (result === OLM_ERROR) {
+ var message = Pointer_stringify(
+ Module['_olm_pk_signing_last_error'](arguments[0])
+ );
+ throw new Error("OLM." + message);
+ }
+ return result;
+ }
+}
+
+PkSigning.prototype['free'] = function() {
+ Module['_olm_clear_pk_signing'](this.ptr);
+ free(this.ptr);
+}
+
+PkSigning.prototype['init_with_seed'] = restore_stack(function (seed) {
+ var seed_buffer = stack(seed.length);
+ Module['HEAPU8'].set(seed, seed_buffer);
+
+ var pubkey_length = pk_decryption_method(
+ Module['_olm_pk_sign_public_key_length']
+ )();
+ var pubkey_buffer = stack(pubkey_length + NULL_BYTE_PADDING_LENGTH);
+ try {
+ pk_signing_method(Module['_olm_pk_signing_key_from_seed'])(
+ this.ptr,
+ pubkey_buffer, pubkey_length,
+ seed_buffer, seed.length
+ );
+ } finally {
+ // clear out our copy of the seed
+ bzero(seed_buffer, seed.length);
+ }
+ return Pointer_stringify(pubkey_buffer);
+});
+
+PkSigning.prototype['generate_seed'] = restore_stack(function () {
+ var random_length = pk_decryption_method(
+ Module['_olm_pk_sign_seed_length']
+ )();
+ var random_buffer = random_stack(random_length);
+ var key_arr = new Uint8Array(
+ new Uint8Array(Module['HEAPU8'].buffer, random_buffer, random_length)
+ );
+ bzero(random_buffer, random_length);
+ return key_arr;
+});
+
+PkSigning.prototype['sign'] = restore_stack(function (message) {
+ // XXX: Should be able to sign any bytes rather than just strings,
+ // but this is consistent with encrypt for now.
+ //var message_buffer = stack(message.length);
+ //Module['HEAPU8'].set(message, message_buffer);
+ var message_buffer, message_length;
+
+ try {
+ message_length = lengthBytesUTF8(message)
+ message_buffer = malloc(message_length + 1);
+ stringToUTF8(message, message_buffer, message_length + 1);
+
+ var sig_length = pk_decryption_method(
+ Module['_olm_pk_signature_length']
+ )();
+ var sig_buffer = stack(sig_length + NULL_BYTE_PADDING_LENGTH);
+ pk_signing_method(Module['_olm_pk_sign'])(
+ this.ptr,
+ message_buffer, message_length,
+ sig_buffer, sig_length
+ );
+ return Pointer_stringify(sig_buffer);
+ } finally {
+ if (message_buffer !== undefined) {
+ // don't leave a copy of the plaintext in the heap.
+ bzero(message_buffer, message_length + 1);
+ free(message_buffer);
+ }
+ }
+});
diff --git a/javascript/olm_post.js b/javascript/olm_post.js
index 3bf0d66..a3a3ef4 100644
--- a/javascript/olm_post.js
+++ b/javascript/olm_post.js
@@ -534,6 +534,7 @@ olm_exports["Session"] = Session;
olm_exports["Utility"] = Utility;
olm_exports["PkEncryption"] = PkEncryption;
olm_exports["PkDecryption"] = PkDecryption;
+olm_exports["PkSigning"] = PkSigning;
olm_exports["SAS"] = SAS;
olm_exports["get_library_version"] = restore_stack(function() {
diff --git a/javascript/test/olm.spec.js b/javascript/test/olm.spec.js
index 77dd712..a698314 100644
--- a/javascript/test/olm.spec.js
+++ b/javascript/test/olm.spec.js
@@ -34,7 +34,6 @@ describe("olm", function() {
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();
diff --git a/javascript/test/pk.spec.js b/javascript/test/pk.spec.js
index b4b119e..f212b96 100644
--- a/javascript/test/pk.spec.js
+++ b/javascript/test/pk.spec.js
@@ -1,5 +1,5 @@
/*
-Copyright 2018 New Vector Ltd
+Copyright 2018, 2019 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.
@@ -19,12 +19,13 @@ limitations under the License.
var Olm = require('../olm');
describe("pk", function() {
- var encryption, decryption;
+ var encryption, decryption, signing;
beforeEach(function(done) {
Olm.init().then(function() {
encryption = new Olm.PkEncryption();
decryption = new Olm.PkDecryption();
+ signing = new Olm.PkSigning();
done();
});
@@ -39,6 +40,10 @@ describe("pk", function() {
decryption.free();
decryption = undefined;
}
+ if (signing !== undefined) {
+ signing.free();
+ signing = undefined;
+ }
});
it('should import & export keys from private parts', function () {
@@ -89,4 +94,29 @@ describe("pk", function() {
expect(decrypted).toEqual(TEST_TEXT);
new_decryption.free();
});
+
+ it('should sign and verify', function () {
+ var seed = 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 TEST_TEXT = "We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness.";
+ //var seed = signing.generate_seed();
+ var pubkey = signing.init_with_seed(seed);
+ var sig = signing.sign(TEST_TEXT);
+
+ var util = new Olm.Utility();
+ util.ed25519_verify(pubkey, TEST_TEXT, sig);
+ var verifyFailure;
+ try {
+ util.ed25519_verify(pubkey, TEST_TEXT, 'p' + sig.slice(1));
+ } catch (e) {
+ verifyFailure = e;
+ }
+ expect(verifyFailure).not.toBeNull();
+ util.free();
+ });
});
diff --git a/src/pk.cpp b/src/pk.cpp
index 8db958a..5db472c 100644
--- a/src/pk.cpp
+++ b/src/pk.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2018 New Vector Ltd
+/* Copyright 2018, 2019 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.
@@ -409,4 +409,88 @@ size_t olm_pk_get_private_key(
return olm_pk_private_key_length();
}
+struct OlmPkSigning {
+ OlmErrorCode last_error;
+ _olm_ed25519_key_pair key_pair;
+};
+
+size_t olm_pk_signing_size(void) {
+ return sizeof(OlmPkSigning);
+}
+
+OlmPkSigning *olm_pk_signing(void * memory) {
+ olm::unset(memory, sizeof(OlmPkSigning));
+ return new(memory) OlmPkSigning;
+}
+
+const char * olm_pk_signing_last_error(OlmPkSigning * sign) {
+ auto error = sign->last_error;
+ return _olm_error_to_string(error);
+}
+
+size_t olm_clear_pk_signing(OlmPkSigning *sign) {
+ /* Clear the memory backing the signing */
+ olm::unset(sign, sizeof(OlmPkSigning));
+ /* Initialise a fresh signing object in case someone tries to use it */
+ new(sign) OlmPkSigning();
+ return sizeof(OlmPkSigning);
+}
+
+size_t olm_pk_sign_seed_length(void) {
+ return ED25519_RANDOM_LENGTH;
+}
+
+size_t olm_pk_sign_public_key_length(void) {
+ return olm::encode_base64_length(ED25519_PUBLIC_KEY_LENGTH);
+}
+
+size_t olm_pk_signing_key_from_seed(
+ OlmPkSigning * signing,
+ void * pubkey, size_t pubkey_length,
+ void * seed, size_t seed_length
+) {
+ if (pubkey_length < olm_pk_sign_public_key_length()) {
+ signing->last_error =
+ OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
+ return std::size_t(-1);
+ }
+ if (seed_length < olm_pk_sign_seed_length()) {
+ signing->last_error =
+ OlmErrorCode::OLM_INPUT_BUFFER_TOO_SMALL;
+ return std::size_t(-1);
+ }
+
+ _olm_crypto_ed25519_generate_key((uint8_t *) seed, &signing->key_pair);
+ olm::encode_base64(
+ (const uint8_t *)signing->key_pair.public_key.public_key,
+ ED25519_PUBLIC_KEY_LENGTH,
+ (uint8_t *)pubkey
+ );
+ return 0;
+}
+
+size_t olm_pk_signature_length() {
+ return olm::encode_base64_length(ED25519_SIGNATURE_LENGTH);
+}
+
+#include "olm/utility.hh"
+
+size_t olm_pk_sign(
+ OlmPkSigning *signing,
+ uint8_t const * message, size_t message_length,
+ uint8_t * signature, size_t signature_length
+) {
+ if (signature_length < olm_pk_signature_length()) {
+ signing->last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
+ return std::size_t(-1);
+ }
+ uint8_t *raw_sig = signature + olm_pk_signature_length() - ED25519_SIGNATURE_LENGTH;
+ _olm_crypto_ed25519_sign(
+ &signing->key_pair,
+ message, message_length, raw_sig
+ );
+ olm::encode_base64(raw_sig, ED25519_SIGNATURE_LENGTH, signature);
+ return olm_pk_signature_length();
+}
+
}
diff --git a/tests/test_pk.cpp b/tests/test_pk.cpp
index 42cc8c9..874710b 100644
--- a/tests/test_pk.cpp
+++ b/tests/test_pk.cpp
@@ -163,4 +163,74 @@ free(ciphertext);
free(plaintext_buffer);
}
+
+{ /* Signing Test Case 1 */
+
+TestCase test_case("Public Key Signing");
+
+std::uint8_t signing_buffer[olm_pk_signing_size()];
+OlmPkSigning *signing = olm_pk_signing(signing_buffer);
+
+std::uint8_t seed[32] = {
+ 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
+};
+
+//const std::uint8_t *pub_key = (std::uint8_t *) "hSDwCYkwp1R0i33ctD73Wg2/Og0mOBr066SpjqqbTmoK";
+
+char pubkey[olm_pk_sign_public_key_length() + 1];
+
+olm_pk_signing_key_from_seed(
+ signing,
+ pubkey, sizeof(pubkey),
+ seed, sizeof(seed)
+);
+
+printf("pubkey: %s\n", pubkey);
+
+char *message = strdup("We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness.");
+
+std::uint8_t *sig_buffer = (std::uint8_t *) malloc(olm_pk_signature_length() + 1);
+
+olm_pk_sign(
+ signing,
+ (const uint8_t *)message, strlen(message),
+ sig_buffer, olm_pk_signature_length()
+);
+
+printf("sig: %s\n", sig_buffer);
+
+void * utility_buffer = malloc(::olm_utility_size());
+::OlmUtility * utility = ::olm_utility(utility_buffer);
+
+size_t result;
+
+result = ::olm_ed25519_verify(
+ utility,
+ pubkey, olm_pk_sign_public_key_length(),
+ message, strlen(message),
+ sig_buffer, olm_pk_signature_length()
+);
+
+assert_equals((size_t)0, result);
+
+sig_buffer[5] = 'm';
+
+result = ::olm_ed25519_verify(
+ utility,
+ pubkey, olm_pk_sign_public_key_length(),
+ message, strlen(message),
+ sig_buffer, olm_pk_signature_length()
+);
+
+assert_equals((size_t)-1, result);
+
+free(message);
+free(sig_buffer);
+
+olm_clear_pk_signing(signing);
+
+}
}