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:
commit
b1130fb77f
9 changed files with 138 additions and 19 deletions
|
@ -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:
|
||||||
|
|
|
@ -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. */
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)
|
||||||
|
|
41
src/pk.cpp
41
src/pk.cpp
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue