summaryrefslogtreecommitdiff
path: root/libs/libaxolotl/src/ratchet.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libaxolotl/src/ratchet.c')
-rwxr-xr-xlibs/libaxolotl/src/ratchet.c1240
1 files changed, 0 insertions, 1240 deletions
diff --git a/libs/libaxolotl/src/ratchet.c b/libs/libaxolotl/src/ratchet.c
deleted file mode 100755
index 83ab5a1eac..0000000000
--- a/libs/libaxolotl/src/ratchet.c
+++ /dev/null
@@ -1,1240 +0,0 @@
-#include "ratchet.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include "protobuf-c/protobuf-c.h"
-
-#include "hkdf.h"
-#include "curve.h"
-#include "session_state.h"
-#include "protocol.h"
-#include "vpool.h"
-#include "LocalStorageProtocol.pb-c.h"
-#include "signal_protocol_internal.h"
-
-#define HASH_OUTPUT_SIZE 32
-#define DERIVED_MESSAGE_SECRETS_SIZE 80
-#define DERIVED_ROOT_SECRETS_SIZE 64
-
-struct ratchet_chain_key {
- signal_type_base base;
- signal_context *global_context;
- hkdf_context *kdf;
- uint8_t *key;
- size_t key_len;
- uint32_t index;
-};
-
-struct ratchet_root_key {
- signal_type_base base;
- signal_context *global_context;
- hkdf_context *kdf;
- uint8_t *key;
- size_t key_len;
-};
-
-struct ratchet_identity_key_pair {
- signal_type_base base;
- ec_public_key *public_key;
- ec_private_key *private_key;
-};
-
-int ratchet_chain_key_create(ratchet_chain_key **chain_key, hkdf_context *kdf, const uint8_t *key, size_t key_len, uint32_t index, signal_context *global_context)
-{
- ratchet_chain_key *result = 0;
-
- if(!kdf || !key) {
- return SG_ERR_INVAL;
- }
-
- result = malloc(sizeof(ratchet_chain_key));
- if(!result) {
- return SG_ERR_NOMEM;
- }
-
- SIGNAL_INIT(result, ratchet_chain_key_destroy);
- result->global_context = global_context;
- result->kdf = kdf;
-
- result->key = malloc(key_len);
- if(!result->key) {
- free(result);
- return SG_ERR_NOMEM;
- }
- memcpy(result->key, key, key_len);
- result->key_len = key_len;
-
- result->index = index;
- SIGNAL_REF(result->kdf);
- *chain_key = result;
-
- return 0;
-}
-
-int ratchet_chain_key_get_key(const ratchet_chain_key *chain_key, signal_buffer **buffer)
-{
- signal_buffer *buf = 0;
- uint8_t *data = 0;
-
- buf = signal_buffer_alloc(chain_key->key_len);
- if(!buf) {
- return SG_ERR_NOMEM;
- }
-
- data = signal_buffer_data(buf);
- memcpy(data, chain_key->key, chain_key->key_len);
-
- *buffer = buf;
-
- return 0;
-}
-
-int ratchet_chain_key_get_key_protobuf(const ratchet_chain_key *chain_key, ProtobufCBinaryData *buffer)
-{
- uint8_t *data = 0;
-
- assert(chain_key);
- assert(buffer);
-
- data = malloc(chain_key->key_len);
- if(!data) {
- return SG_ERR_NOMEM;
- }
-
- memcpy(data, chain_key->key, chain_key->key_len);
-
- buffer->data = data;
- buffer->len = chain_key->key_len;
- return 0;
-}
-
-uint32_t ratchet_chain_key_get_index(const ratchet_chain_key *chain_key)
-{
- return chain_key->index;
-}
-
-ssize_t ratchet_chain_key_get_base_material(const ratchet_chain_key *chain_key, uint8_t **material, const uint8_t *seed, size_t seed_len)
-{
- int result = 0;
- signal_buffer *output_buffer = 0;
- uint8_t *output = 0;
- size_t output_len = 0;
-
- void *hmac_context = 0;
- result = signal_hmac_sha256_init(chain_key->global_context, &hmac_context, chain_key->key, chain_key->key_len);
- if(result < 0) {
- goto complete;
- }
-
- result = signal_hmac_sha256_update(chain_key->global_context, hmac_context, seed, seed_len);
- if(result < 0) {
- goto complete;
- }
-
- result = signal_hmac_sha256_final(chain_key->global_context, hmac_context, &output_buffer);
- if(result < 0) {
- goto complete;
- }
-
- output_len = signal_buffer_len(output_buffer);
- output = malloc(output_len);
- if(!output) {
- result = SG_ERR_NOMEM;
- goto complete;
- }
-
- memcpy(output, signal_buffer_data(output_buffer), output_len);
-
-complete:
- signal_hmac_sha256_cleanup(chain_key->global_context, hmac_context);
- signal_buffer_free(output_buffer);
-
- if(result >= 0) {
- *material = output;
- return (ssize_t)output_len;
- }
- else {
- return result;
- }
-}
-
-int ratchet_chain_key_get_message_keys(ratchet_chain_key *chain_key, ratchet_message_keys *message_keys)
-{
- static const uint8_t message_key_seed = 0x01;
- static const char key_material_seed[] = "WhisperMessageKeys";
- uint8_t salt[HASH_OUTPUT_SIZE];
- int result = 0;
- ssize_t result_size = 0;
- uint8_t *input_key_material = 0;
- size_t input_key_material_len = 0;
- uint8_t *key_material_data = 0;
- size_t key_material_data_len = 0;
-
- memset(message_keys, 0, sizeof(ratchet_message_keys));
-
- result_size = ratchet_chain_key_get_base_material(chain_key, &input_key_material, &message_key_seed, sizeof(message_key_seed));
- if(result_size < 0) {
- result = (int)result_size;
- signal_log(chain_key->global_context, SG_LOG_WARNING, "ratchet_chain_key_get_base_material failed");
- goto complete;
- }
- input_key_material_len = (size_t)result_size;
-
- memset(salt, 0, sizeof(salt));
-
- result_size = hkdf_derive_secrets(chain_key->kdf,
- &key_material_data,
- input_key_material, input_key_material_len,
- salt, sizeof(salt),
- (uint8_t *)key_material_seed, sizeof(key_material_seed) - 1,
- DERIVED_MESSAGE_SECRETS_SIZE);
- if(result_size < 0) {
- result = (int)result_size;
- signal_log(chain_key->global_context, SG_LOG_WARNING, "hkdf_derive_secrets failed");
- goto complete;
- }
- key_material_data_len = (size_t)result_size;
-
- if(key_material_data_len != RATCHET_CIPHER_KEY_LENGTH + RATCHET_MAC_KEY_LENGTH + RATCHET_IV_LENGTH) {
- signal_log(chain_key->global_context, SG_LOG_WARNING,
- "key_material_data length mismatch: %d != %d",
- key_material_data_len, (RATCHET_CIPHER_KEY_LENGTH + RATCHET_MAC_KEY_LENGTH + RATCHET_IV_LENGTH));
- result = SG_ERR_UNKNOWN;
- goto complete;
- }
-
- memcpy(message_keys->cipher_key, key_material_data, RATCHET_CIPHER_KEY_LENGTH);
- memcpy(message_keys->mac_key, key_material_data + RATCHET_CIPHER_KEY_LENGTH, RATCHET_MAC_KEY_LENGTH);
- memcpy(message_keys->iv, key_material_data + RATCHET_CIPHER_KEY_LENGTH + RATCHET_MAC_KEY_LENGTH, RATCHET_IV_LENGTH);
- message_keys->counter = chain_key->index;
-
-complete:
- if(input_key_material) {
- free(input_key_material);
- }
- if(key_material_data) {
- free(key_material_data);
- }
- if(result < 0) {
- return result;
- }
- else {
- return 0;
- }
-}
-
-int ratchet_chain_key_create_next(const ratchet_chain_key *chain_key, ratchet_chain_key **next_chain_key)
-{
- static const uint8_t chain_key_seed = 0x02;
- int result = 0;
- ssize_t result_size = 0;
- uint8_t *next_key = 0;
- size_t next_key_len = 0;
-
- result_size = ratchet_chain_key_get_base_material(chain_key, &next_key, &chain_key_seed, sizeof(chain_key_seed));
- if(result_size < 0) {
- result = (int)result_size;
- signal_log(chain_key->global_context, SG_LOG_WARNING, "ratchet_chain_key_get_base_material failed");
- goto complete;
- }
- next_key_len = (size_t)result_size;
-
- result = ratchet_chain_key_create(
- next_chain_key,
- chain_key->kdf,
- next_key, next_key_len,
- chain_key->index + 1,
- chain_key->global_context);
-
-complete:
- if(next_key) {
- free(next_key);
- }
-
- return result;
-}
-
-void ratchet_chain_key_destroy(signal_type_base *type)
-{
- ratchet_chain_key *chain_key = (ratchet_chain_key *)type;
- SIGNAL_UNREF(chain_key->kdf);
- if(chain_key->key) {
- signal_explicit_bzero(chain_key->key, chain_key->key_len);
- free(chain_key->key);
- }
- free(chain_key);
-}
-
-int ratchet_root_key_create(ratchet_root_key **root_key, hkdf_context *kdf, const uint8_t *key, size_t key_len, signal_context *global_context)
-{
- ratchet_root_key *result = 0;
-
- if(!kdf || !key) {
- return SG_ERR_INVAL;
- }
-
- result = malloc(sizeof(ratchet_root_key));
- if(!result) {
- return SG_ERR_NOMEM;
- }
-
- SIGNAL_INIT(result, ratchet_root_key_destroy);
- result->global_context = global_context;
- result->kdf = kdf;
-
- result->key = malloc(key_len);
- if(!result->key) {
- free(result);
- return SG_ERR_NOMEM;
- }
- memcpy(result->key, key, key_len);
- result->key_len = key_len;
- SIGNAL_REF(result->kdf);
- *root_key = result;
-
- return 0;
-}
-
-int ratchet_root_key_create_chain(ratchet_root_key *root_key,
- ratchet_root_key **new_root_key, ratchet_chain_key **new_chain_key,
- ec_public_key *their_ratchet_key,
- ec_private_key *our_ratchet_key_private)
-{
- static const char key_info[] = "WhisperRatchet";
- int result = 0;
- ssize_t result_size = 0;
- uint8_t *shared_secret = 0;
- size_t shared_secret_len = 0;
- uint8_t *derived_secret = 0;
- ratchet_root_key *new_root_key_result = 0;
- ratchet_chain_key *new_chain_key_result = 0;
-
- if(!their_ratchet_key || !our_ratchet_key_private) {
- return SG_ERR_INVAL;
- }
-
- result = curve_calculate_agreement(&shared_secret, their_ratchet_key, our_ratchet_key_private);
- if(result < 0) {
- signal_log(root_key->global_context, SG_LOG_WARNING, "curve_calculate_agreement failed");
- goto complete;
- }
- shared_secret_len = (size_t)result;
-
- result_size = hkdf_derive_secrets(root_key->kdf, &derived_secret,
- shared_secret, shared_secret_len,
- root_key->key, root_key->key_len,
- (uint8_t *)key_info, sizeof(key_info) - 1,
- DERIVED_ROOT_SECRETS_SIZE);
- if(result_size < 0) {
- result = (int)result_size;
- signal_log(root_key->global_context, SG_LOG_WARNING, "hkdf_derive_secrets failed");
- goto complete;
- }
- else if(result_size != DERIVED_ROOT_SECRETS_SIZE) {
- result = SG_ERR_UNKNOWN;
- signal_log(root_key->global_context, SG_LOG_WARNING, "hkdf_derive_secrets size mismatch");
- goto complete;
- }
-
- result = ratchet_root_key_create(&new_root_key_result, root_key->kdf,
- derived_secret, 32,
- root_key->global_context);
- if(result < 0) {
- signal_log(root_key->global_context, SG_LOG_WARNING, "ratchet_root_key_create failed");
- goto complete;
- }
-
- result = ratchet_chain_key_create(&new_chain_key_result, root_key->kdf,
- derived_secret + 32, 32, 0,
- root_key->global_context);
- if(result < 0) {
- signal_log(root_key->global_context, SG_LOG_WARNING, "ratchet_chain_key_create failed");
- goto complete;
- }
-
-complete:
- if(shared_secret) {
- free(shared_secret);
- }
- if(derived_secret) {
- free(derived_secret);
- }
- if(result < 0) {
- if(new_root_key_result) {
- SIGNAL_UNREF(new_root_key_result);
- }
- if(new_chain_key_result) {
- SIGNAL_UNREF(new_chain_key_result);
- }
- return result;
- }
- else {
- *new_root_key = new_root_key_result;
- *new_chain_key = new_chain_key_result;
- return 0;
- }
-}
-
-int ratchet_root_key_get_key(ratchet_root_key *root_key, signal_buffer **buffer)
-{
- signal_buffer *buf = 0;
- uint8_t *data = 0;
-
- assert(root_key);
-
- buf = signal_buffer_alloc(root_key->key_len);
- if(!buf) {
- return SG_ERR_NOMEM;
- }
-
- data = signal_buffer_data(buf);
- memcpy(data, root_key->key, root_key->key_len);
-
- *buffer = buf;
-
- return 0;
-}
-
-int ratchet_root_key_get_key_protobuf(const ratchet_root_key *root_key, ProtobufCBinaryData *buffer)
-{
- uint8_t *data = 0;
-
- assert(root_key);
- assert(buffer);
-
- data = malloc(root_key->key_len);
- if(!data) {
- return SG_ERR_NOMEM;
- }
-
- memcpy(data, root_key->key, root_key->key_len);
-
- buffer->data = data;
- buffer->len = root_key->key_len;
- return 0;
-}
-
-int ratchet_root_key_compare(const ratchet_root_key *key1, const ratchet_root_key *key2)
-{
- if(key1 == key2) {
- return 0;
- }
- else if(key1 == 0 && key2 != 0) {
- return -1;
- }
- else if(key1 != 0 && key2 == 0) {
- return 1;
- }
- else {
- int kdf_compare = hkdf_compare(key1->kdf, key2->kdf);
- if(kdf_compare != 0) {
- return kdf_compare;
- }
- else if(key1->key_len < key2->key_len) {
- return -1;
- }
- else if(key1->key_len > key2->key_len) {
- return 1;
- }
- else {
- return signal_constant_memcmp(key1->key, key2->key, key1->key_len);
- }
- }
-}
-
-void ratchet_root_key_destroy(signal_type_base *type)
-{
- ratchet_root_key *root_key = (ratchet_root_key *)type;
- SIGNAL_UNREF(root_key->kdf);
- if(root_key->key) {
- signal_explicit_bzero(root_key->key, root_key->key_len);
- free(root_key->key);
- }
- free(root_key);
-}
-
-int ratchet_identity_key_pair_create(
- ratchet_identity_key_pair **key_pair,
- ec_public_key *public_key,
- ec_private_key *private_key)
-{
- ratchet_identity_key_pair *result = malloc(sizeof(ratchet_identity_key_pair));
- if(!result) {
- return SG_ERR_NOMEM;
- }
-
- SIGNAL_INIT(result, ratchet_identity_key_pair_destroy);
- SIGNAL_REF(public_key);
- SIGNAL_REF(private_key);
- result->public_key = public_key;
- result->private_key = private_key;
-
- *key_pair = result;
-
- return 0;
-}
-
-int ratchet_identity_key_pair_serialize(signal_buffer **buffer, const ratchet_identity_key_pair *key_pair)
-{
- int result = 0;
- size_t result_size = 0;
- signal_buffer *result_buf = 0;
- Textsecure__IdentityKeyPairStructure key_structure = TEXTSECURE__IDENTITY_KEY_PAIR_STRUCTURE__INIT;
- size_t len = 0;
- uint8_t *data = 0;
-
- if(!key_pair) {
- result = SG_ERR_INVAL;
- goto complete;
- }
-
- result = ec_public_key_serialize_protobuf(&key_structure.publickey, key_pair->public_key);
- if(result < 0) {
- goto complete;
- }
- key_structure.has_publickey = 1;
-
- result = ec_private_key_serialize_protobuf(&key_structure.privatekey, key_pair->private_key);
- if(result < 0) {
- goto complete;
- }
- key_structure.has_privatekey = 1;
-
- len = textsecure__identity_key_pair_structure__get_packed_size(&key_structure);
- result_buf = signal_buffer_alloc(len);
- if(!result_buf) {
- result = SG_ERR_NOMEM;
- goto complete;
- }
-
- data = signal_buffer_data(result_buf);
- result_size = textsecure__identity_key_pair_structure__pack(&key_structure, data);
- if(result_size != len) {
- signal_buffer_free(result_buf);
- result = SG_ERR_INVALID_PROTO_BUF;
- result_buf = 0;
- goto complete;
- }
-
-complete:
- if(key_structure.has_publickey) {
- free(key_structure.publickey.data);
- }
- if(key_structure.has_privatekey) {
- free(key_structure.privatekey.data);
- }
- if(result >= 0) {
- result = 0;
- *buffer = result_buf;
- }
- return result;
-}
-
-int ratchet_identity_key_pair_deserialize(ratchet_identity_key_pair **key_pair, const uint8_t *data, size_t len, signal_context *global_context)
-{
- int result = 0;
- ec_public_key *public_key = 0;
- ec_private_key *private_key = 0;
- ratchet_identity_key_pair *result_pair = 0;
- Textsecure__IdentityKeyPairStructure *key_structure = 0;
-
- key_structure = textsecure__identity_key_pair_structure__unpack(0, len, data);
- if(!key_structure) {
- result = SG_ERR_INVALID_PROTO_BUF;
- goto complete;
- }
-
- if(!key_structure->has_publickey || !key_structure->has_privatekey) {
- result = SG_ERR_INVALID_KEY;
- goto complete;
- }
-
- result = curve_decode_point(
- &public_key,
- key_structure->publickey.data,
- key_structure->publickey.len,
- global_context);
- if(result < 0) {
- goto complete;
- }
-
- result = curve_decode_private_point(
- &private_key,
- key_structure->privatekey.data,
- key_structure->privatekey.len,
- global_context);
- if(result < 0) {
- goto complete;
- }
-
- result = ratchet_identity_key_pair_create(&result_pair,
- public_key, private_key);
-
-complete:
- SIGNAL_UNREF(public_key);
- SIGNAL_UNREF(private_key);
- if(key_structure) {
- textsecure__identity_key_pair_structure__free_unpacked(key_structure, 0);
- }
- if(result >= 0) {
- *key_pair = result_pair;
- }
- return result;
-}
-
-ec_public_key *ratchet_identity_key_pair_get_public(const ratchet_identity_key_pair *key_pair)
-{
- assert(key_pair);
- assert(key_pair->public_key);
- return key_pair->public_key;
-}
-
-ec_private_key *ratchet_identity_key_pair_get_private(const ratchet_identity_key_pair *key_pair)
-{
- assert(key_pair);
- assert(key_pair->private_key);
- return key_pair->private_key;
-}
-
-void ratchet_identity_key_pair_destroy(signal_type_base *type)
-{
- ratchet_identity_key_pair *key_pair = (ratchet_identity_key_pair *)type;
- SIGNAL_UNREF(key_pair->public_key);
- SIGNAL_UNREF(key_pair->private_key);
- free(key_pair);
-}
-
-struct symmetric_signal_protocol_parameters
-{
- signal_type_base base;
- ratchet_identity_key_pair *our_identity_key;
- ec_key_pair *our_base_key;
- ec_key_pair *our_ratchet_key;
- ec_public_key *their_base_key;
- ec_public_key *their_ratchet_key;
- ec_public_key *their_identity_key;
-};
-
-struct alice_signal_protocol_parameters
-{
- signal_type_base base;
- ratchet_identity_key_pair *our_identity_key;
- ec_key_pair *our_base_key;
- ec_public_key *their_identity_key;
- ec_public_key *their_signed_pre_key;
- ec_public_key *their_one_time_pre_key; /* optional */
- ec_public_key *their_ratchet_key;
-};
-
-struct bob_signal_protocol_parameters
-{
- signal_type_base base;
- ratchet_identity_key_pair *our_identity_key;
- ec_key_pair *our_signed_pre_key;
- ec_key_pair *our_one_time_pre_key; /* optional */
- ec_key_pair *our_ratchet_key;
- ec_public_key *their_identity_key;
- ec_public_key *their_base_key;
-};
-
-int symmetric_signal_protocol_parameters_create(
- symmetric_signal_protocol_parameters **parameters,
- ratchet_identity_key_pair *our_identity_key,
- ec_key_pair *our_base_key,
- ec_key_pair *our_ratchet_key,
- ec_public_key *their_base_key,
- ec_public_key *their_ratchet_key,
- ec_public_key *their_identity_key)
-{
- symmetric_signal_protocol_parameters *result = 0;
-
- if(!our_identity_key || !our_base_key || !our_ratchet_key
- || !their_base_key || !their_ratchet_key || !their_identity_key) {
- return SG_ERR_INVAL;
- }
-
- result = malloc(sizeof(symmetric_signal_protocol_parameters));
- if(!result) {
- return SG_ERR_NOMEM;
- }
-
- memset(result, 0, sizeof(symmetric_signal_protocol_parameters));
-
- SIGNAL_INIT(result, symmetric_signal_protocol_parameters_destroy);
- SIGNAL_REF(our_identity_key);
- SIGNAL_REF(our_base_key);
- SIGNAL_REF(our_ratchet_key);
- SIGNAL_REF(their_base_key);
- SIGNAL_REF(their_ratchet_key);
- SIGNAL_REF(their_identity_key);
- result->our_identity_key = our_identity_key;
- result->our_base_key = our_base_key;
- result->our_ratchet_key = our_ratchet_key;
- result->their_base_key = their_base_key;
- result->their_ratchet_key = their_ratchet_key;
- result->their_identity_key = their_identity_key;
-
- *parameters = result;
- return 0;
-}
-
-ratchet_identity_key_pair *symmetric_signal_protocol_parameters_get_our_identity_key(const symmetric_signal_protocol_parameters *parameters)
-{
- assert(parameters);
- return parameters->our_identity_key;
-}
-
-ec_key_pair *symmetric_signal_protocol_parameters_get_our_base_key(const symmetric_signal_protocol_parameters *parameters)
-{
- assert(parameters);
- return parameters->our_base_key;
-}
-
-ec_key_pair *symmetric_signal_protocol_parameters_get_our_ratchet_key(const symmetric_signal_protocol_parameters *parameters)
-{
- assert(parameters);
- return parameters->our_ratchet_key;
-}
-
-ec_public_key *symmetric_signal_protocol_parameters_get_their_base_key(const symmetric_signal_protocol_parameters *parameters)
-{
- assert(parameters);
- return parameters->their_base_key;
-}
-
-ec_public_key *symmetric_signal_protocol_parameters_get_their_ratchet_key(const symmetric_signal_protocol_parameters *parameters)
-{
- assert(parameters);
- return parameters->their_ratchet_key;
-}
-
-ec_public_key *symmetric_signal_protocol_parameters_get_their_identity_key(const symmetric_signal_protocol_parameters *parameters)
-{
- assert(parameters);
- return parameters->their_identity_key;
-}
-
-void symmetric_signal_protocol_parameters_destroy(signal_type_base *type)
-{
- symmetric_signal_protocol_parameters *parameters = (symmetric_signal_protocol_parameters *)type;
-
- SIGNAL_UNREF(parameters->our_identity_key);
- SIGNAL_UNREF(parameters->our_base_key);
- SIGNAL_UNREF(parameters->our_ratchet_key);
- SIGNAL_UNREF(parameters->their_base_key);
- SIGNAL_UNREF(parameters->their_ratchet_key);
- SIGNAL_UNREF(parameters->their_identity_key);
-
- free(parameters);
-}
-
-int alice_signal_protocol_parameters_create(
- alice_signal_protocol_parameters **parameters,
- ratchet_identity_key_pair *our_identity_key,
- ec_key_pair *our_base_key,
- ec_public_key *their_identity_key,
- ec_public_key *their_signed_pre_key,
- ec_public_key *their_one_time_pre_key,
- ec_public_key *their_ratchet_key)
-{
- alice_signal_protocol_parameters *result = 0;
-
- /* Only "their_one_time_pre_key" is allowed to be null */
- if(!our_identity_key || !our_base_key || !their_identity_key
- || !their_signed_pre_key || !their_ratchet_key) {
- return SG_ERR_INVAL;
- }
-
- result = malloc(sizeof(alice_signal_protocol_parameters));
- if(!result) {
- return SG_ERR_NOMEM;
- }
-
- memset(result, 0, sizeof(alice_signal_protocol_parameters));
-
- SIGNAL_INIT(result, alice_signal_protocol_parameters_destroy);
- SIGNAL_REF(our_identity_key);
- SIGNAL_REF(our_base_key);
- SIGNAL_REF(their_identity_key);
- SIGNAL_REF(their_signed_pre_key);
- SIGNAL_REF(their_ratchet_key);
- result->our_identity_key = our_identity_key;
- result->our_base_key = our_base_key;
- result->their_identity_key = their_identity_key;
- result->their_signed_pre_key = their_signed_pre_key;
- result->their_ratchet_key = their_ratchet_key;
-
- if(their_one_time_pre_key) {
- SIGNAL_REF(their_one_time_pre_key);
- result->their_one_time_pre_key = their_one_time_pre_key;
- }
-
- *parameters = result;
- return 0;
-}
-
-void alice_signal_protocol_parameters_destroy(signal_type_base *type)
-{
- alice_signal_protocol_parameters *parameters = (alice_signal_protocol_parameters *)type;
-
- SIGNAL_UNREF(parameters->our_identity_key);
- SIGNAL_UNREF(parameters->our_base_key);
- SIGNAL_UNREF(parameters->their_identity_key);
- SIGNAL_UNREF(parameters->their_signed_pre_key);
- SIGNAL_UNREF(parameters->their_ratchet_key);
-
- if(parameters->their_one_time_pre_key) {
- SIGNAL_UNREF(parameters->their_one_time_pre_key);
- }
-
- free(parameters);
-}
-
-int bob_signal_protocol_parameters_create(
- bob_signal_protocol_parameters **parameters,
- ratchet_identity_key_pair *our_identity_key,
- ec_key_pair *our_signed_pre_key,
- ec_key_pair *our_one_time_pre_key,
- ec_key_pair *our_ratchet_key,
- ec_public_key *their_identity_key,
- ec_public_key *their_base_key)
-{
- bob_signal_protocol_parameters *result = 0;
-
- /* Only "our_one_time_pre_key" is allowed to be null */
- if(!our_identity_key || !our_signed_pre_key || !our_ratchet_key
- || !their_identity_key || !their_base_key) {
- return SG_ERR_INVAL;
- }
-
- result = malloc(sizeof(bob_signal_protocol_parameters));
- if(!result) {
- return SG_ERR_NOMEM;
- }
-
- memset(result, 0, sizeof(bob_signal_protocol_parameters));
-
- SIGNAL_INIT(result, bob_signal_protocol_parameters_destroy);
- SIGNAL_REF(our_identity_key);
- SIGNAL_REF(our_signed_pre_key);
- SIGNAL_REF(our_ratchet_key);
- SIGNAL_REF(their_identity_key);
- SIGNAL_REF(their_base_key);
- result->our_identity_key = our_identity_key;
- result->our_signed_pre_key = our_signed_pre_key;
- result->our_ratchet_key = our_ratchet_key;
- result->their_identity_key = their_identity_key;
- result->their_base_key = their_base_key;
-
- if(our_one_time_pre_key) {
- SIGNAL_REF(our_one_time_pre_key);
- result->our_one_time_pre_key = our_one_time_pre_key;
- }
-
- *parameters = result;
- return 0;
-}
-
-void bob_signal_protocol_parameters_destroy(signal_type_base *type)
-{
- bob_signal_protocol_parameters *parameters = (bob_signal_protocol_parameters *)type;
-
- SIGNAL_UNREF(parameters->our_identity_key);
- SIGNAL_UNREF(parameters->our_signed_pre_key);
- SIGNAL_UNREF(parameters->our_ratchet_key);
- SIGNAL_UNREF(parameters->their_identity_key);
- SIGNAL_UNREF(parameters->their_base_key);
-
- if(parameters->our_one_time_pre_key) {
- SIGNAL_UNREF(parameters->our_one_time_pre_key);
- }
-
- free(parameters);
-}
-
-int ratcheting_session_calculate_derived_keys(ratchet_root_key **root_key, ratchet_chain_key **chain_key,
- uint8_t *secret, size_t secret_len, signal_context *global_context)
-{
- int result = 0;
- ssize_t result_size = 0;
- hkdf_context *kdf = 0;
- ratchet_root_key *root_key_result = 0;
- ratchet_chain_key *chain_key_result = 0;
- uint8_t *output = 0;
- uint8_t salt[HASH_OUTPUT_SIZE];
- static const char key_info[] = "WhisperText";
-
- result = hkdf_create(&kdf, 3, global_context);
- if(result < 0) {
- goto complete;
- }
-
- memset(salt, 0, sizeof(salt));
-
- result_size = hkdf_derive_secrets(kdf, &output,
- secret, secret_len,
- salt, sizeof(salt),
- (uint8_t *)key_info, sizeof(key_info) - 1, 64);
- if(result_size != 64) {
- result = SG_ERR_UNKNOWN;
- goto complete;
- }
-
- result = ratchet_root_key_create(&root_key_result, kdf, output, 32, global_context);
- if(result < 0) {
- goto complete;
- }
-
- result = ratchet_chain_key_create(&chain_key_result, kdf, output + 32, 32, 0, global_context);
- if(result < 0) {
- goto complete;
- }
-
-complete:
- if(kdf) {
- SIGNAL_UNREF(kdf);
- }
- if(output) {
- free(output);
- }
-
- if(result < 0) {
- if(root_key_result) {
- SIGNAL_UNREF(root_key_result);
- }
- if(chain_key_result) {
- SIGNAL_UNREF(chain_key_result);
- }
- }
- else {
- *root_key = root_key_result;
- *chain_key = chain_key_result;
- }
-
- return result;
-}
-
-int ratcheting_session_symmetric_is_alice(symmetric_signal_protocol_parameters *parameters)
-{
- //FIXME Java code checks if our_base_key < their_base_key
- // This comparison may not return the same result. However, we should find
- // out whether the Java code was doing the right thing and why.
- return ec_public_key_memcmp(
- ec_key_pair_get_public(parameters->our_base_key),
- parameters->their_base_key) < 0;
-}
-
-int ratcheting_session_symmetric_initialize(
- session_state *state,
- symmetric_signal_protocol_parameters *parameters,
- signal_context *global_context)
-{
- int result = 0;
-
- assert(state);
- assert(parameters);
- assert(global_context);
-
- if(ratcheting_session_symmetric_is_alice(parameters)) {
- alice_signal_protocol_parameters *alice_parameters = 0;
- result = alice_signal_protocol_parameters_create(&alice_parameters,
- parameters->our_identity_key,
- parameters->our_base_key,
- parameters->their_identity_key,
- parameters->their_base_key,
- 0,
- parameters->their_ratchet_key);
- if(result >= 0) {
- result = ratcheting_session_alice_initialize(state, alice_parameters, global_context);
- }
- if(alice_parameters) {
- SIGNAL_UNREF(alice_parameters);
- }
- }
- else {
- bob_signal_protocol_parameters *bob_parameters = 0;
- result = bob_signal_protocol_parameters_create(&bob_parameters,
- parameters->our_identity_key,
- parameters->our_base_key,
- 0,
- parameters->our_ratchet_key,
- parameters->their_identity_key,
- parameters->their_base_key);
- if(result >= 0) {
- result = ratcheting_session_bob_initialize(state, bob_parameters, global_context);
- }
- if(bob_parameters) {
- SIGNAL_UNREF(bob_parameters);
- }
- }
- return result;
-}
-
-int ratcheting_session_alice_initialize(
- session_state *state,
- alice_signal_protocol_parameters *parameters,
- signal_context *global_context)
-{
- int result = 0;
- uint8_t *agreement = 0;
- int agreement_len = 0;
- ec_key_pair *sending_ratchet_key = 0;
- ratchet_root_key *derived_root = 0;
- ratchet_chain_key *derived_chain = 0;
- ratchet_root_key *sending_chain_root = 0;
- ratchet_chain_key *sending_chain_key = 0;
- struct vpool vp;
- uint8_t *secret = 0;
- size_t secret_len = 0;
- uint8_t discontinuity_data[32];
-
- assert(state);
- assert(parameters);
- assert(global_context);
-
- vpool_init(&vp, 1024, 0);
-
- result = curve_generate_key_pair(global_context, &sending_ratchet_key);
- if(result < 0) {
- goto complete;
- }
-
- memset(discontinuity_data, 0xFF, sizeof(discontinuity_data));
- if(!vpool_insert(&vp, vpool_get_length(&vp), discontinuity_data, sizeof(discontinuity_data))) {
- result = SG_ERR_NOMEM;
- goto complete;
- }
-
- agreement_len = curve_calculate_agreement(&agreement,
- parameters->their_signed_pre_key, parameters->our_identity_key->private_key);
- if(agreement_len < 0) {
- result = agreement_len;
- goto complete;
- }
- if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) {
- free(agreement); agreement = 0; agreement_len = 0;
- }
- else {
- result = SG_ERR_NOMEM;
- goto complete;
- }
-
- agreement_len = curve_calculate_agreement(&agreement,
- parameters->their_identity_key, ec_key_pair_get_private(parameters->our_base_key));
- if(agreement_len < 0) {
- result = agreement_len;
- goto complete;
- }
- if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) {
- free(agreement); agreement = 0; agreement_len = 0;
- }
- else {
- result = SG_ERR_NOMEM;
- goto complete;
- }
-
- agreement_len = curve_calculate_agreement(&agreement,
- parameters->their_signed_pre_key, ec_key_pair_get_private(parameters->our_base_key));
- if(agreement_len < 0) {
- result = agreement_len;
- goto complete;
- }
- if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) {
- free(agreement); agreement = 0; agreement_len = 0;
- }
- else {
- result = SG_ERR_NOMEM;
- goto complete;
- }
-
- if(parameters->their_one_time_pre_key) {
- agreement_len = curve_calculate_agreement(&agreement,
- parameters->their_one_time_pre_key, ec_key_pair_get_private(parameters->our_base_key));
- if(agreement_len < 0) {
- result = agreement_len;
- goto complete;
- }
- if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) {
- free(agreement); agreement = 0; agreement_len = 0;
- }
- else {
- result = SG_ERR_NOMEM;
- goto complete;
- }
- }
-
- if(vpool_is_empty(&vp)) {
- result = SG_ERR_UNKNOWN;
- goto complete;
- }
-
- secret = vpool_get_buf(&vp);
- secret_len = vpool_get_length(&vp);
-
- result = ratcheting_session_calculate_derived_keys(&derived_root, &derived_chain, secret, secret_len, global_context);
- if(result < 0) {
- goto complete;
- }
-
- result = ratchet_root_key_create_chain(derived_root,
- &sending_chain_root, &sending_chain_key,
- parameters->their_ratchet_key,
- ec_key_pair_get_private(sending_ratchet_key));
- if(result < 0) {
- goto complete;
- }
-
- result = session_state_add_receiver_chain(state, parameters->their_ratchet_key, derived_chain);
- if(result < 0) {
- goto complete;
- }
-
- session_state_set_session_version(state, CIPHERTEXT_CURRENT_VERSION);
- session_state_set_remote_identity_key(state, parameters->their_identity_key);
- session_state_set_local_identity_key(state, parameters->our_identity_key->public_key);
- session_state_set_sender_chain(state, sending_ratchet_key, sending_chain_key);
- session_state_set_root_key(state, sending_chain_root);
-
-complete:
- vpool_final(&vp);
- if(agreement) {
- free(agreement);
- }
- if(sending_ratchet_key) {
- SIGNAL_UNREF(sending_ratchet_key);
- }
- if(derived_root) {
- SIGNAL_UNREF(derived_root);
- }
- if(derived_chain) {
- SIGNAL_UNREF(derived_chain);
- }
- if(sending_chain_root) {
- SIGNAL_UNREF(sending_chain_root);
- }
- if(sending_chain_key) {
- SIGNAL_UNREF(sending_chain_key);
- }
-
- return result;
-}
-
-int ratcheting_session_bob_initialize(
- session_state *state,
- bob_signal_protocol_parameters *parameters,
- signal_context *global_context)
-{
- int result = 0;
- uint8_t *agreement = 0;
- int agreement_len = 0;
- ratchet_root_key *derived_root = 0;
- ratchet_chain_key *derived_chain = 0;
- struct vpool vp;
- uint8_t *secret = 0;
- size_t secret_len = 0;
- uint8_t discontinuity_data[32];
-
- assert(state);
- assert(parameters);
- assert(global_context);
-
- vpool_init(&vp, 1024, 0);
-
- memset(discontinuity_data, 0xFF, sizeof(discontinuity_data));
- if(!vpool_insert(&vp, vpool_get_length(&vp), discontinuity_data, sizeof(discontinuity_data))) {
- result = SG_ERR_NOMEM;
- goto complete;
- }
-
- agreement_len = curve_calculate_agreement(&agreement,
- parameters->their_identity_key, ec_key_pair_get_private(parameters->our_signed_pre_key));
- if(agreement_len < 0) {
- result = agreement_len;
- goto complete;
- }
- if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) {
- free(agreement); agreement = 0; agreement_len = 0;
- }
- else {
- result = SG_ERR_NOMEM;
- goto complete;
- }
-
- agreement_len = curve_calculate_agreement(&agreement,
- parameters->their_base_key, parameters->our_identity_key->private_key);
- if(agreement_len < 0) {
- result = agreement_len;
- goto complete;
- }
- if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) {
- free(agreement); agreement = 0; agreement_len = 0;
- }
- else {
- result = SG_ERR_NOMEM;
- goto complete;
- }
-
- agreement_len = curve_calculate_agreement(&agreement,
- parameters->their_base_key, ec_key_pair_get_private(parameters->our_signed_pre_key));
- if(agreement_len < 0) {
- result = agreement_len;
- goto complete;
- }
- if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) {
- free(agreement); agreement = 0; agreement_len = 0;
- }
- else {
- result = SG_ERR_NOMEM;
- goto complete;
- }
-
- if(parameters->our_one_time_pre_key) {
- agreement_len = curve_calculate_agreement(&agreement,
- parameters->their_base_key, ec_key_pair_get_private(parameters->our_one_time_pre_key));
- if(agreement_len < 0) {
- result = agreement_len;
- goto complete;
- }
- if(vpool_insert(&vp, vpool_get_length(&vp), agreement, (size_t)agreement_len)) {
- free(agreement); agreement = 0; agreement_len = 0;
- }
- else {
- result = SG_ERR_NOMEM;
- goto complete;
- }
- }
-
- if(vpool_is_empty(&vp)) {
- result = SG_ERR_UNKNOWN;
- goto complete;
- }
-
- secret = vpool_get_buf(&vp);
- secret_len = vpool_get_length(&vp);
-
- result = ratcheting_session_calculate_derived_keys(&derived_root, &derived_chain, secret, secret_len, global_context);
-
-complete:
- if(result >= 0) {
- session_state_set_session_version(state, CIPHERTEXT_CURRENT_VERSION);
- session_state_set_remote_identity_key(state, parameters->their_identity_key);
- session_state_set_local_identity_key(state, parameters->our_identity_key->public_key);
- session_state_set_sender_chain(state, parameters->our_ratchet_key, derived_chain);
- session_state_set_root_key(state, derived_root);
- }
-
- vpool_final(&vp);
- if(agreement) {
- free(agreement);
- }
- if(derived_root) {
- SIGNAL_UNREF(derived_root);
- }
- if(derived_chain) {
- SIGNAL_UNREF(derived_chain);
- }
-
- return result;
-}