Commit fcbedf19 authored by Hubert Chathi's avatar Hubert Chathi Committed by GitHub

Merge pull request #81 from matrix-org/dbkr/pk_sign

Add signing class to the pk module
parents 45091c15 48dda792
......@@ -86,9 +86,6 @@ 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 -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
......
/* 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_signing_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
......
......@@ -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_signing_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_signing_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_signing_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);
}
}
});
......@@ -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() {
......
......@@ -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();
......
/*
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();
});
});
/* 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,86 @@ 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);
}
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();
}
}
......@@ -162,5 +162,75 @@ assert_equals(plaintext, plaintext_buffer, strlen((const char *)plaintext));
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);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment