Merge pull request #61 from matrix-org/dbkr/pk_private_export_import

Work with PkDecryption keys by their private keys
This commit is contained in:
David Baker 2018-10-12 08:24:45 +01:00 committed by GitHub
commit b1130fb77f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 138 additions and 19 deletions

View file

@ -6,6 +6,10 @@ started up asynchronously. The imported module now has an init()
method which returns a promise. The library cannot be used until method which returns a promise. The library cannot be used until
this promise resolves. It will reject if the library fails to start. this promise resolves. It will reject if the library fails to start.
olm_pk_generate_key() and olm_pk_generate_key_random_length() have
been removed: to generate a random key, use olm_pk_key_from_private()
with random bytes as the private key.
Changes in `2.3.0 <http://matrix.org/git/olm/commit/?h=2.3.0>`_ Changes in `2.3.0 <http://matrix.org/git/olm/commit/?h=2.3.0>`_
This release includes the following changes since 2.2.2: This release includes the following changes since 2.2.2:

View file

@ -51,6 +51,13 @@ enum OlmErrorCode {
*/ */
OLM_BAD_SIGNATURE = 14, OLM_BAD_SIGNATURE = 14,
OLM_INPUT_BUFFER_TOO_SMALL = 15,
// Not an error code, just here to pad out the enum past 16 because
// otherwise the compiler warns about a redunant check. If you're
// adding an error code, replace this one!
OLM_ERROR_NOT_INVENTED_YET = 16,
/* remember to update the list of string constants in error.c when updating /* remember to update the list of string constants in error.c when updating
* this list. */ * this list. */
}; };

View file

@ -80,7 +80,7 @@ size_t olm_pk_encrypt_random_length(
* key. Returns olm_error() on failure. If the ciphertext, mac, or * key. Returns olm_error() on failure. If the ciphertext, mac, or
* ephemeral_key buffers were too small then olm_pk_encryption_last_error() * ephemeral_key buffers were too small then olm_pk_encryption_last_error()
* will be "OUTPUT_BUFFER_TOO_SMALL". If there weren't enough random bytes then * will be "OUTPUT_BUFFER_TOO_SMALL". If there weren't enough random bytes then
* olm_pk_encryption_last_error() will be "NOT_ENOUGH_RANDOM". */ * olm_pk_encryption_last_error() will be "OLM_INPUT_BUFFER_TOO_SMALL". */
size_t olm_pk_encrypt( size_t olm_pk_encrypt(
OlmPkEncryption *encryption, OlmPkEncryption *encryption,
void const * plaintext, size_t plaintext_length, void const * plaintext, size_t plaintext_length,
@ -112,19 +112,36 @@ size_t olm_clear_pk_decryption(
OlmPkDecryption *decryption OlmPkDecryption *decryption
); );
/** The number of random bytes needed to generate a new key. */ /** Get the number of bytes required to store an olm private key
*/
size_t olm_pk_private_key_length();
/** DEPRECATED: Use olm_pk_private_key_length()
*/
size_t olm_pk_generate_key_random_length(void); size_t olm_pk_generate_key_random_length(void);
/** Generate a new key pair to use for decrypting messages. The private key is /** Initialise the key from the private part of a key as returned by
* stored in the decryption object, and the associated public key will be * olm_pk_get_private_key(). The associated public key will be written to the
* written to the pubkey buffer. Returns olm_error() on failure. If the pubkey * pubkey buffer. Returns olm_error() on failure. If the pubkey buffer is too
* buffer is too small then olm_pk_decryption_last_error() will be * small then olm_pk_decryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL".
* "OUTPUT_BUFFER_TOO_SMALL". If there weren't enough random bytes then * If the private key was not long enough then olm_pk_decryption_last_error()
* olm_pk_decryption_last_error() will be "NOT_ENOUGH_RANDOM". */ * will be "OLM_INPUT_BUFFER_TOO_SMALL".
*
* Note that the pubkey is a base64 encoded string, but the private key is
* an unencoded byte array
*/
size_t olm_pk_key_from_private(
OlmPkDecryption * decryption,
void * pubkey, size_t pubkey_length,
void * privkey, size_t privkey_length
);
/** DEPRECATED: Use olm_pk_key_from_private
*/
size_t olm_pk_generate_key( size_t olm_pk_generate_key(
OlmPkDecryption * decryption, OlmPkDecryption * decryption,
void * pubkey, size_t pubkey_length, void * pubkey, size_t pubkey_length,
void * random, size_t random_length void * privkey, size_t privkey_length
); );
/** Returns the number of bytes needed to store a decryption object. */ /** Returns the number of bytes needed to store a decryption object. */
@ -177,6 +194,19 @@ size_t olm_pk_decrypt(
void * plaintext, size_t max_plaintext_length void * plaintext, size_t max_plaintext_length
); );
/**
* Get the private key for an OlmDecryption object as an unencoded byte array
* private_key must be a pointer to a buffer of at least
* olm_pk_private_key_length() bytes and this length must be passed in
* private_key_length. If the given buffer is too small, returns olm_error()
* and olm_pk_encryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL".
* Returns the number of bytes written.
*/
size_t olm_pk_get_private_key(
OlmPkDecryption * decryption,
void *private_key, size_t private_key_length
);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -118,16 +118,32 @@ PkDecryption.prototype['free'] = function() {
free(this.ptr); free(this.ptr);
} }
PkDecryption.prototype['init_with_private_key'] = restore_stack(function (private_key) {
var private_key_buffer = stack(private_key.length);
Module['HEAPU8'].set(private_key, private_key_buffer);
var pubkey_length = pk_decryption_method(
Module['_olm_pk_key_length']
)();
var pubkey_buffer = stack(pubkey_length + NULL_BYTE_PADDING_LENGTH);
pk_decryption_method(Module['_olm_pk_key_from_private'])(
this.ptr,
pubkey_buffer, pubkey_length,
private_key_buffer, private_key.length
);
return Pointer_stringify(pubkey_buffer);
});
PkDecryption.prototype['generate_key'] = restore_stack(function () { PkDecryption.prototype['generate_key'] = restore_stack(function () {
var random_length = pk_decryption_method( var random_length = pk_decryption_method(
Module['_olm_pk_generate_key_random_length'] Module['_olm_pk_private_key_length']
)(); )();
var random_buffer = random_stack(random_length); var random_buffer = random_stack(random_length);
var pubkey_length = pk_decryption_method( var pubkey_length = pk_decryption_method(
Module['_olm_pk_key_length'] Module['_olm_pk_key_length']
)(); )();
var pubkey_buffer = stack(pubkey_length + NULL_BYTE_PADDING_LENGTH); var pubkey_buffer = stack(pubkey_length + NULL_BYTE_PADDING_LENGTH);
pk_decryption_method(Module['_olm_pk_generate_key'])( pk_decryption_method(Module['_olm_pk_key_from_private'])(
this.ptr, this.ptr,
pubkey_buffer, pubkey_length, pubkey_buffer, pubkey_length,
random_buffer, random_length random_buffer, random_length
@ -135,6 +151,18 @@ PkDecryption.prototype['generate_key'] = restore_stack(function () {
return Pointer_stringify(pubkey_buffer); return Pointer_stringify(pubkey_buffer);
}); });
PkDecryption.prototype['get_private_key'] = restore_stack(function () {
var privkey_length = pk_encryption_method(
Module['_olm_pk_private_key_length']
)();
var privkey_buffer = stack(privkey_length);
pk_decryption_method(Module['_olm_pk_get_private_key'])(
this.ptr,
privkey_buffer, privkey_length
);
return new Uint8Array(Module['HEAPU8'].buffer, privkey_buffer, privkey_length);
});
PkDecryption.prototype['pickle'] = restore_stack(function (key) { PkDecryption.prototype['pickle'] = restore_stack(function (key) {
var key_array = array_from_string(key); var key_array = array_from_string(key);
var pickle_length = pk_decryption_method( var pickle_length = pk_decryption_method(

View file

@ -40,6 +40,7 @@ var NULL_BYTE_PADDING_LENGTH = 1;
Module['onRuntimeInitialized'] = function() { Module['onRuntimeInitialized'] = function() {
OLM_ERROR = Module['_olm_error'](); OLM_ERROR = Module['_olm_error']();
olm_exports["PRIVATE_KEY_LENGTH"] = Module['_olm_pk_private_key_length']();
if (onInitSuccess) onInitSuccess(); if (onInitSuccess) onInitSuccess();
}; };

View file

@ -41,6 +41,20 @@ describe("pk", function() {
} }
}); });
it('should import & export keys from private parts', function () {
var alice_private = 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 alice_public = decryption.init_with_private_key(alice_private);
expect(alice_public).toEqual("hSDwCYkwp1R0i33ctD73Wg2/Og0mOBr066SpjqqbTmo");
var alice_private_out = decryption.get_private_key();
expect(alice_private_out).toEqual(alice_private);
});
it('should encrypt and decrypt', function () { it('should encrypt and decrypt', function () {
var TEST_TEXT='têst1'; var TEST_TEXT='têst1';
var pubkey = decryption.generate_key(); var pubkey = decryption.generate_key();

View file

@ -31,6 +31,7 @@ static const char * ERRORS[] = {
"UNKNOWN_MESSAGE_INDEX", "UNKNOWN_MESSAGE_INDEX",
"BAD_LEGACY_ACCOUNT_PICKLE", "BAD_LEGACY_ACCOUNT_PICKLE",
"BAD_SIGNATURE", "BAD_SIGNATURE",
"OLM_INPUT_BUFFER_TOO_SMALL",
}; };
const char * _olm_error_to_string(enum OlmErrorCode error) const char * _olm_error_to_string(enum OlmErrorCode error)

View file

@ -187,31 +187,35 @@ size_t olm_clear_pk_decryption(
return sizeof(OlmPkDecryption); return sizeof(OlmPkDecryption);
} }
size_t olm_pk_generate_key_random_length(void) { size_t olm_pk_private_key_length(void) {
return CURVE25519_KEY_LENGTH; return CURVE25519_KEY_LENGTH;
} }
size_t olm_pk_generate_key_random_length(void) {
return olm_pk_private_key_length();
}
size_t olm_pk_key_length(void) { size_t olm_pk_key_length(void) {
return olm::encode_base64_length(CURVE25519_KEY_LENGTH); return olm::encode_base64_length(CURVE25519_KEY_LENGTH);
} }
size_t olm_pk_generate_key( size_t olm_pk_key_from_private(
OlmPkDecryption * decryption, OlmPkDecryption * decryption,
void * pubkey, size_t pubkey_length, void * pubkey, size_t pubkey_length,
void * random, size_t random_length void * privkey, size_t privkey_length
) { ) {
if (pubkey_length < olm_pk_key_length()) { if (pubkey_length < olm_pk_key_length()) {
decryption->last_error = decryption->last_error =
OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL; OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
return std::size_t(-1); return std::size_t(-1);
} }
if (random_length < olm_pk_generate_key_random_length()) { if (privkey_length < olm_pk_private_key_length()) {
decryption->last_error = decryption->last_error =
OlmErrorCode::OLM_NOT_ENOUGH_RANDOM; OlmErrorCode::OLM_INPUT_BUFFER_TOO_SMALL;
return std::size_t(-1); return std::size_t(-1);
} }
_olm_crypto_curve25519_generate_key((uint8_t *) random, &decryption->key_pair); _olm_crypto_curve25519_generate_key((uint8_t *) privkey, &decryption->key_pair);
olm::encode_base64( olm::encode_base64(
(const uint8_t *)decryption->key_pair.public_key.public_key, (const uint8_t *)decryption->key_pair.public_key.public_key,
CURVE25519_KEY_LENGTH, CURVE25519_KEY_LENGTH,
@ -220,6 +224,14 @@ size_t olm_pk_generate_key(
return 0; return 0;
} }
size_t olm_pk_generate_key(
OlmPkDecryption * decryption,
void * pubkey, size_t pubkey_length,
void * privkey, size_t privkey_length
) {
return olm_pk_key_from_private(decryption, pubkey, pubkey_length, privkey, privkey_length);
}
namespace { namespace {
static const std::uint32_t PK_DECRYPTION_PICKLE_VERSION = 1; static const std::uint32_t PK_DECRYPTION_PICKLE_VERSION = 1;
@ -380,4 +392,21 @@ size_t olm_pk_decrypt(
} }
} }
size_t olm_pk_get_private_key(
OlmPkDecryption * decryption,
void *private_key, size_t private_key_length
) {
if (private_key_length < olm_pk_private_key_length()) {
decryption->last_error =
OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
return std::size_t(-1);
}
std::memcpy(
private_key,
decryption->key_pair.private_key.private_key,
olm_pk_private_key_length()
);
return olm_pk_private_key_length();
}
} }

View file

@ -36,7 +36,7 @@ const std::uint8_t *bob_public = (std::uint8_t *) "3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbe
std::uint8_t pubkey[::olm_pk_key_length()]; std::uint8_t pubkey[::olm_pk_key_length()];
olm_pk_generate_key( olm_pk_key_from_private(
decryption, decryption,
pubkey, sizeof(pubkey), pubkey, sizeof(pubkey),
alice_private, sizeof(alice_private) alice_private, sizeof(alice_private)
@ -44,6 +44,11 @@ olm_pk_generate_key(
assert_equals(alice_public, pubkey, olm_pk_key_length()); assert_equals(alice_public, pubkey, olm_pk_key_length());
uint8_t *alice_private_back_out = (uint8_t *)malloc(olm_pk_private_key_length());
olm_pk_get_private_key(decryption, alice_private_back_out, olm_pk_private_key_length());
assert_equals(alice_private, alice_private_back_out, olm_pk_private_key_length());
free(alice_private_back_out);
std::uint8_t encryption_buffer[olm_pk_encryption_size()]; std::uint8_t encryption_buffer[olm_pk_encryption_size()];
OlmPkEncryption *encryption = olm_pk_encryption(encryption_buffer); OlmPkEncryption *encryption = olm_pk_encryption(encryption_buffer);
@ -105,7 +110,7 @@ const std::uint8_t *alice_public = (std::uint8_t *) "hSDwCYkwp1R0i33ctD73Wg2/Og0
std::uint8_t pubkey[olm_pk_key_length()]; std::uint8_t pubkey[olm_pk_key_length()];
olm_pk_generate_key( olm_pk_key_from_private(
decryption, decryption,
pubkey, sizeof(pubkey), pubkey, sizeof(pubkey),
alice_private, sizeof(alice_private) alice_private, sizeof(alice_private)