Add signing class to the pk module
This commit is contained in:
parent
45091c158d
commit
8df2ab7c07
7 changed files with 320 additions and 5 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
86
src/pk.cpp
86
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue