Add methods for generating new one time keys and for tracking which one time keys have been published
This commit is contained in:
parent
0e988237f6
commit
5634be0507
2 changed files with 121 additions and 40 deletions
|
@ -31,6 +31,7 @@ struct IdentityKeys {
|
||||||
|
|
||||||
struct OneTimeKey {
|
struct OneTimeKey {
|
||||||
std::uint32_t id;
|
std::uint32_t id;
|
||||||
|
bool published;
|
||||||
Curve25519KeyPair key;
|
Curve25519KeyPair key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,15 +40,17 @@ static std::size_t const MAX_ONE_TIME_KEYS = 100;
|
||||||
|
|
||||||
|
|
||||||
struct Account {
|
struct Account {
|
||||||
|
Account();
|
||||||
IdentityKeys identity_keys;
|
IdentityKeys identity_keys;
|
||||||
List<OneTimeKey, MAX_ONE_TIME_KEYS> one_time_keys;
|
List<OneTimeKey, MAX_ONE_TIME_KEYS> one_time_keys;
|
||||||
|
std::uint32_t next_one_time_key_id;
|
||||||
ErrorCode last_error;
|
ErrorCode last_error;
|
||||||
|
|
||||||
/** Number of random bytes needed to create a new account */
|
/** Number of random bytes needed to create a new account */
|
||||||
std::size_t new_account_random_length();
|
std::size_t new_account_random_length();
|
||||||
|
|
||||||
/** Create a new account. Returns NOT_ENOUGH_RANDOM if the number of random
|
/** Create a new account. Returns std::size_t(-1) on error. If the number of
|
||||||
* bytes is too small. */
|
* random bytes is too small then last_error will be NOT_ENOUGH_RANDOM */
|
||||||
std::size_t new_account(
|
std::size_t new_account(
|
||||||
uint8_t const * random, std::size_t random_length
|
uint8_t const * random, std::size_t random_length
|
||||||
);
|
);
|
||||||
|
@ -61,35 +64,30 @@ struct Account {
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Output the identity keys for this account as JSON in the following
|
/** Output the identity keys for this account as JSON in the following
|
||||||
* format.
|
* format:
|
||||||
*
|
*
|
||||||
* 14 {"algorithms":
|
* {"algorithms":
|
||||||
* 30 ["m.olm.curve25519-aes-sha256"
|
* ["m.olm.curve25519-aes-sha256"
|
||||||
* 15 ],"device_id":"
|
* ]
|
||||||
* ? <device identifier>
|
* ,"device_id":"<device identifier>"
|
||||||
* 22 ","keys":{"curve25519:
|
* ,"keys":
|
||||||
* 4 <base64 characters>
|
* {"curve25519:<key id>":"<base64 characters>"
|
||||||
* 3 ":"
|
* ,"ed25519:<key id>":"<base64 characters>"
|
||||||
* 43 <base64 characters>
|
* }
|
||||||
* 11 ","ed25519:
|
* ,"user_id":"<user identifier>"
|
||||||
* 4 <base64 characters>
|
* ,"valid_after_ts":<digits>
|
||||||
* 3 ":"
|
* ,"valid_until_ts":<digits>
|
||||||
* 43 <base64 characters>
|
* ,"signatures":
|
||||||
* 14 "},"user_id":"
|
* {"<user identifier>/<device identifier>":
|
||||||
* ? <user identifier>
|
* {"ed25519:<key id>":"<base64 characters>"
|
||||||
* 19 ","valid_after_ts":
|
* }
|
||||||
* ? <digits>
|
* }
|
||||||
* 18 ,"valid_until_ts":
|
* }
|
||||||
* ? <digits>
|
*
|
||||||
* 16 ,"signatures":{"
|
* The user_id and device_id must not contain 0x00-0x1F, '\"' or '\\'.
|
||||||
* ? <user identifier>
|
* The JSON up to but not including the "signatures" key will be signed
|
||||||
* 1 /
|
* using the account's ed25519 key. That signature is then included under
|
||||||
* ? <device identifier>
|
* the "signatures" key.
|
||||||
* 12 ":{"ed25519:
|
|
||||||
* 4 <base64 characters>
|
|
||||||
* 3 ":"
|
|
||||||
* 86 <base64 characters>
|
|
||||||
* 4 "}}}
|
|
||||||
*
|
*
|
||||||
* Returns the size of the JSON written or std::size_t(-1) on error.
|
* Returns the size of the JSON written or std::size_t(-1) on error.
|
||||||
* If the buffer is too small last_error will be OUTPUT_BUFFER_TOO_SMALL. */
|
* If the buffer is too small last_error will be OUTPUT_BUFFER_TOO_SMALL. */
|
||||||
|
@ -104,7 +102,13 @@ struct Account {
|
||||||
/** Number of bytes needed to output the one time keys for this account */
|
/** Number of bytes needed to output the one time keys for this account */
|
||||||
std::size_t get_one_time_keys_json_length();
|
std::size_t get_one_time_keys_json_length();
|
||||||
|
|
||||||
/*
|
/** Output the one time keys that haven't been published yet as JSON:
|
||||||
|
*
|
||||||
|
* {"curve25519:<key id>":"<base64 characters>"
|
||||||
|
* ,"curve25519:<key_id>":"<base64 characters>"
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
*
|
||||||
* Returns the size of the JSON written or std::size_t(-1) on error.
|
* Returns the size of the JSON written or std::size_t(-1) on error.
|
||||||
* If the buffer is too small last_error will be OUTPUT_BUFFER_TOO_SMALL.
|
* If the buffer is too small last_error will be OUTPUT_BUFFER_TOO_SMALL.
|
||||||
*/
|
*/
|
||||||
|
@ -112,6 +116,28 @@ struct Account {
|
||||||
std::uint8_t * one_time_json, std::size_t one_time_json_length
|
std::uint8_t * one_time_json, std::size_t one_time_json_length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** Mark the current list of one_time_keys as being published. They
|
||||||
|
* will no longer be returned by get_one_time_keys_json_length(). */
|
||||||
|
std::size_t mark_keys_as_published();
|
||||||
|
|
||||||
|
/** The largest number of one time keys this account can store. */
|
||||||
|
std::size_t max_number_of_one_time_keys();
|
||||||
|
|
||||||
|
/** Returns the number of random bytes needed to generate a given number
|
||||||
|
* of new one time keys. */
|
||||||
|
std::size_t generate_one_time_keys_random_length(
|
||||||
|
std::size_t number_of_keys
|
||||||
|
);
|
||||||
|
|
||||||
|
/** Generates a number of new one time keys. If the total number of keys
|
||||||
|
* stored by this account exceeds max_number_of_one_time_keys() then the
|
||||||
|
* old keys are discarded. Returns std::size_t(-1) on error. If the number
|
||||||
|
* of random bytes is too small then last_error will be NOT_ENOUGH_RANDOM */
|
||||||
|
std::size_t generate_one_time_keys(
|
||||||
|
std::size_t number_of_keys,
|
||||||
|
std::uint8_t const * random, std::size_t random_length
|
||||||
|
);
|
||||||
|
|
||||||
/** Lookup a one time key with the given public key */
|
/** Lookup a one time key with the given public key */
|
||||||
OneTimeKey const * lookup_key(
|
OneTimeKey const * lookup_key(
|
||||||
Curve25519PublicKey const & public_key
|
Curve25519PublicKey const & public_key
|
||||||
|
|
|
@ -16,6 +16,11 @@
|
||||||
#include "olm/base64.hh"
|
#include "olm/base64.hh"
|
||||||
#include "olm/pickle.hh"
|
#include "olm/pickle.hh"
|
||||||
|
|
||||||
|
olm::Account::Account(
|
||||||
|
) : next_one_time_key_id(0),
|
||||||
|
last_error(olm::ErrorCode::SUCCESS) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
olm::OneTimeKey const * olm::Account::lookup_key(
|
olm::OneTimeKey const * olm::Account::lookup_key(
|
||||||
olm::Curve25519PublicKey const & public_key
|
olm::Curve25519PublicKey const & public_key
|
||||||
|
@ -54,19 +59,12 @@ std::size_t olm::Account::new_account(
|
||||||
return std::size_t(-1);
|
return std::size_t(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned id = 0;
|
|
||||||
|
|
||||||
olm::ed25519_generate_key(random, identity_keys.ed25519_key);
|
olm::ed25519_generate_key(random, identity_keys.ed25519_key);
|
||||||
random += 32;
|
random += 32;
|
||||||
olm::curve25519_generate_key(random, identity_keys.curve25519_key);
|
olm::curve25519_generate_key(random, identity_keys.curve25519_key);
|
||||||
random += 32;
|
random += 32;
|
||||||
|
|
||||||
for (unsigned i = 0; i < 10; ++i) {
|
generate_one_time_keys(10, random, random_length - 64);
|
||||||
OneTimeKey & key = *one_time_keys.insert(one_time_keys.end());
|
|
||||||
key.id = ++id;
|
|
||||||
olm::curve25519_generate_key(random, key.key);
|
|
||||||
random += 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -236,6 +234,9 @@ std::size_t olm::Account::get_one_time_keys_json_length(
|
||||||
) {
|
) {
|
||||||
std::size_t length = 0;
|
std::size_t length = 0;
|
||||||
for (auto const & key : one_time_keys) {
|
for (auto const & key : one_time_keys) {
|
||||||
|
if (key.published) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
length += 2; /* {" */
|
length += 2; /* {" */
|
||||||
length += sizeof(ONE_TIME_KEY_JSON_ALG) - 1;
|
length += sizeof(ONE_TIME_KEY_JSON_ALG) - 1;
|
||||||
length += 1; /* : */
|
length += 1; /* : */
|
||||||
|
@ -262,6 +263,9 @@ std::size_t olm::Account::get_one_time_keys_json(
|
||||||
}
|
}
|
||||||
std::uint8_t sep = '{';
|
std::uint8_t sep = '{';
|
||||||
for (auto const & key : one_time_keys) {
|
for (auto const & key : one_time_keys) {
|
||||||
|
if (key.published) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
*(pos++) = sep;
|
*(pos++) = sep;
|
||||||
*(pos++) = '\"';
|
*(pos++) = '\"';
|
||||||
pos = write_string(pos, ONE_TIME_KEY_JSON_ALG);
|
pos = write_string(pos, ONE_TIME_KEY_JSON_ALG);
|
||||||
|
@ -284,6 +288,48 @@ std::size_t olm::Account::get_one_time_keys_json(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::size_t olm::Account::mark_keys_as_published(
|
||||||
|
) {
|
||||||
|
std::size_t count = 0;
|
||||||
|
for (auto & key : one_time_keys) {
|
||||||
|
if (!key.published) {
|
||||||
|
key.published = true;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::size_t olm::Account::max_number_of_one_time_keys(
|
||||||
|
) {
|
||||||
|
return olm::MAX_ONE_TIME_KEYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t olm::Account::generate_one_time_keys_random_length(
|
||||||
|
std::size_t number_of_keys
|
||||||
|
) {
|
||||||
|
return 32 * number_of_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t olm::Account::generate_one_time_keys(
|
||||||
|
std::size_t number_of_keys,
|
||||||
|
std::uint8_t const * random, std::size_t random_length
|
||||||
|
) {
|
||||||
|
if (random_length < generate_one_time_keys_random_length(number_of_keys)) {
|
||||||
|
last_error = olm::ErrorCode::NOT_ENOUGH_RANDOM;
|
||||||
|
return std::size_t(-1);
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < number_of_keys; ++i) {
|
||||||
|
OneTimeKey & key = *one_time_keys.insert(one_time_keys.begin());
|
||||||
|
key.id = ++next_one_time_key_id;
|
||||||
|
key.published = false;
|
||||||
|
olm::curve25519_generate_key(random, key.key);
|
||||||
|
random += 32;
|
||||||
|
}
|
||||||
|
return number_of_keys;
|
||||||
|
}
|
||||||
|
|
||||||
namespace olm {
|
namespace olm {
|
||||||
|
|
||||||
static std::size_t pickle_length(
|
static std::size_t pickle_length(
|
||||||
|
@ -319,7 +365,11 @@ static std::uint8_t const * unpickle(
|
||||||
static std::size_t pickle_length(
|
static std::size_t pickle_length(
|
||||||
olm::OneTimeKey const & value
|
olm::OneTimeKey const & value
|
||||||
) {
|
) {
|
||||||
return olm::pickle_length(value.id) + olm::pickle_length(value.key);
|
std::size_t length = 0;
|
||||||
|
length += olm::pickle_length(value.id);
|
||||||
|
length += olm::pickle_length(value.published);
|
||||||
|
length += olm::pickle_length(value.key);
|
||||||
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -328,6 +378,7 @@ static std::uint8_t * pickle(
|
||||||
olm::OneTimeKey const & value
|
olm::OneTimeKey const & value
|
||||||
) {
|
) {
|
||||||
pos = olm::pickle(pos, value.id);
|
pos = olm::pickle(pos, value.id);
|
||||||
|
pos = olm::pickle(pos, value.published);
|
||||||
pos = olm::pickle(pos, value.key);
|
pos = olm::pickle(pos, value.key);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
@ -338,6 +389,7 @@ static std::uint8_t const * unpickle(
|
||||||
olm::OneTimeKey & value
|
olm::OneTimeKey & value
|
||||||
) {
|
) {
|
||||||
pos = olm::unpickle(pos, end, value.id);
|
pos = olm::unpickle(pos, end, value.id);
|
||||||
|
pos = olm::unpickle(pos, end, value.published);
|
||||||
pos = olm::unpickle(pos, end, value.key);
|
pos = olm::unpickle(pos, end, value.key);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
@ -351,6 +403,7 @@ std::size_t olm::pickle_length(
|
||||||
std::size_t length = 0;
|
std::size_t length = 0;
|
||||||
length += olm::pickle_length(value.identity_keys);
|
length += olm::pickle_length(value.identity_keys);
|
||||||
length += olm::pickle_length(value.one_time_keys);
|
length += olm::pickle_length(value.one_time_keys);
|
||||||
|
length += olm::pickle_length(value.next_one_time_key_id);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,6 +414,7 @@ std::uint8_t * olm::pickle(
|
||||||
) {
|
) {
|
||||||
pos = olm::pickle(pos, value.identity_keys);
|
pos = olm::pickle(pos, value.identity_keys);
|
||||||
pos = olm::pickle(pos, value.one_time_keys);
|
pos = olm::pickle(pos, value.one_time_keys);
|
||||||
|
pos = olm::pickle(pos, value.next_one_time_key_id);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,5 +425,6 @@ std::uint8_t const * olm::unpickle(
|
||||||
) {
|
) {
|
||||||
pos = olm::unpickle(pos, end, value.identity_keys);
|
pos = olm::unpickle(pos, end, value.identity_keys);
|
||||||
pos = olm::unpickle(pos, end, value.one_time_keys);
|
pos = olm::unpickle(pos, end, value.one_time_keys);
|
||||||
|
pos = olm::unpickle(pos, end, value.next_one_time_key_id);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue