Ejemplo n.º 1
0
int main(void)
{
    void *buf;
    size_t size;

#ifdef SIGSEGV
    signal(SIGSEGV, segv_handler);
#endif
#ifdef SIGBUS
    signal(SIGBUS, segv_handler);
#endif
#ifdef SIGABRT
    signal(SIGABRT, segv_handler);
#endif
    size = 1U + randombytes_uniform(100000U);
    buf = sodium_malloc(size);
    assert(buf != NULL);
    sodium_mprotect_noaccess(buf);
    sodium_mprotect_readwrite(buf);
#ifndef __EMSCRIPTEN__
    sodium_memzero(((unsigned char *)buf) - 8, 8U);
    sodium_mprotect_readonly(buf);
    sodium_free(buf);
    printf("Underflow not caught\n");
#endif
    return 0;
}
Ejemplo n.º 2
0
int main(void)
{
    void *buf;
    size_t size;
    unsigned int i;

    if (sodium_malloc(SIZE_MAX - 1U) != NULL) {
        return 1;
    }
    if (sodium_allocarray(SIZE_MAX / 2U + 1U, SIZE_MAX / 2U) != NULL) {
        return 1;
    }
    sodium_free(sodium_allocarray(0U, 0U));
    sodium_free(sodium_allocarray(0U, 1U));
    sodium_free(sodium_allocarray(1U, 0U));

    buf = sodium_allocarray(1000U, 50U);
    memset(buf, 0, 50000U);
    sodium_free(buf);

    sodium_free(sodium_malloc(0U));
    sodium_free(NULL);
    for (i = 0U; i < 10000U; i++) {
        size = randombytes_uniform(100000U);
        buf = sodium_malloc(size);
        assert(buf != NULL);
        memset(buf, i, size);
        sodium_mprotect_noaccess(buf);
        sodium_free(buf);
    }
    printf("OK\n");

#ifdef SIGSEGV
    signal(SIGSEGV, segv_handler);
#endif
#ifdef SIGBUS
    signal(SIGBUS, segv_handler);
#endif
#ifdef SIGABRT
    signal(SIGABRT, segv_handler);
#endif
    size = randombytes_uniform(100000U);
    buf = sodium_malloc(size);
    assert(buf != NULL);
    sodium_mprotect_readonly(buf);
    sodium_mprotect_readwrite(buf);
#ifndef __EMSCRIPTEN__
    sodium_memzero(((unsigned char *)buf) + size, 1U);
    sodium_mprotect_noaccess(buf);
    sodium_free(buf);
    printf("Overflow not caught\n");
#endif
    return 0;
}
Ejemplo n.º 3
0
/*
 * Sign a piece of data. Returns the data and signature in one output buffer.
 */
return_status master_keys_sign(
		master_keys * const keys,
		const buffer_t * const data,
		buffer_t * const signed_data) { //output, length of data + SIGNATURE_SIZE
	return_status status = return_status_init();

	if ((keys == NULL)
			|| (data == NULL)
			|| (signed_data == NULL)
			|| (signed_data->buffer_length < (data->content_length + SIGNATURE_SIZE))) {
		throw(INVALID_INPUT, "Invalid input to master_keys_sign.");
	}

	sodium_mprotect_readonly(keys);

	int status_int = 0;
	unsigned long long signed_message_length;
	status_int = crypto_sign(
			signed_data->content,
			&signed_message_length,
			data->content,
			data->content_length,
			keys->private_signing_key->content);
	if (status_int != 0) {
		throw(SIGN_ERROR, "Failed to sign message.");
	}

	signed_data->content_length = (size_t) signed_message_length;

cleanup:
	if (keys != NULL) {
		sodium_mprotect_noaccess(keys);
	}

	on_error {
		if (signed_data != NULL) {
			signed_data->content_length = 0;
		}
	}

	return status;
}
Ejemplo n.º 4
0
/*
 * Get the public identity key.
 */
return_status master_keys_get_identity_key(
		master_keys * const keys,
		buffer_t * const public_identity_key) {
	return_status status = return_status_init();

	//check input
	if ((keys == NULL) || (public_identity_key == NULL) || (public_identity_key->buffer_length < PUBLIC_KEY_SIZE)) {
		throw(INVALID_INPUT, "Invalid input to master_keys_get_identity_key.");
	}

	sodium_mprotect_readonly(keys);

	if (buffer_clone(public_identity_key, keys->public_identity_key) != 0) {
		goto cleanup;
	}

cleanup:
	if (keys != NULL) {
		sodium_mprotect_noaccess(keys);
	}

	return status;
}
Ejemplo n.º 5
0
/*
 * Get the public signing key.
 */
return_status master_keys_get_signing_key(
		master_keys * const keys,
		buffer_t * const public_signing_key) {
	return_status status = return_status_init();

	//check input
	if ((keys == NULL) || (public_signing_key == NULL) || (public_signing_key->buffer_length < PUBLIC_MASTER_KEY_SIZE)) {
		throw(INVALID_INPUT, "Invalid input to master_keys_get_signing_key.");
	}

	sodium_mprotect_readonly(keys);

	if (buffer_clone(public_signing_key, keys->public_signing_key) != 0) {
		throw(BUFFER_ERROR, "Failed to copy public signing key.");
	}

cleanup:
	if (keys != NULL) {
		sodium_mprotect_noaccess(keys);
	}

	return status;
}
Ejemplo n.º 6
0
int main(void) {
	sodium_init();

	//create a user_store
	user_store *store = user_store_create();

	//check the content
	buffer_t *list = user_store_list(store);
	if (list->content_length != 0) {
		fprintf(stderr, "ERROR: List of users is not empty.\n");
		user_store_destroy(store);
		buffer_destroy_from_heap(list);

		return EXIT_FAILURE;
	}
	buffer_destroy_from_heap(list);

	int status;
	//create three users with prekeys and identity keys
	//first alice
	//alice identity key
	buffer_t *alice_private_identity = buffer_create(crypto_box_SECRETKEYBYTES, crypto_box_SECRETKEYBYTES);
	buffer_t *alice_public_identity = buffer_create(crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES);
	status = generate_and_print_keypair(
			alice_public_identity,
			alice_private_identity,
			buffer_create_from_string("Alice"),
			buffer_create_from_string("identity"));
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to generate Alice's identity keypair.\n");
		buffer_clear(alice_private_identity);
		return status;
	}

	//alice prekeys
	buffer_t *alice_private_prekeys = buffer_create(PREKEY_AMOUNT * crypto_box_SECRETKEYBYTES, PREKEY_AMOUNT * crypto_box_SECRETKEYBYTES);
	buffer_t *alice_public_prekeys = buffer_create(PREKEY_AMOUNT * crypto_box_PUBLICKEYBYTES, PREKEY_AMOUNT * crypto_box_PUBLICKEYBYTES);
	status = generate_prekeys(alice_private_prekeys, alice_public_prekeys);
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to generate Alice's prekeys.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		return status;
	}

	//then bob
	//bob's identity key
	buffer_t *bob_private_identity = buffer_create(crypto_box_SECRETKEYBYTES, crypto_box_SECRETKEYBYTES);
	buffer_t *bob_public_identity = buffer_create(crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES);
	status = generate_and_print_keypair(
			bob_public_identity,
			bob_private_identity,
			buffer_create_from_string("Bob"),
			buffer_create_from_string("identity"));
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to generate Bob's identity keypair.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		return status;
	}

	//bob's prekeys
	buffer_t *bob_private_prekeys = buffer_create(PREKEY_AMOUNT * crypto_box_SECRETKEYBYTES, PREKEY_AMOUNT * crypto_box_SECRETKEYBYTES);
	buffer_t *bob_public_prekeys = buffer_create(PREKEY_AMOUNT * crypto_box_PUBLICKEYBYTES, PREKEY_AMOUNT * crypto_box_PUBLICKEYBYTES);
	status = generate_prekeys(bob_private_prekeys, bob_public_prekeys);
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to generate Bob's prekeys.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		return status;
	}

	//then charlie
	//charlie's identity key
	buffer_t *charlie_private_identity = buffer_create(crypto_box_SECRETKEYBYTES, crypto_box_SECRETKEYBYTES);
	buffer_t *charlie_public_identity = buffer_create(crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES);
	status = generate_and_print_keypair(
			charlie_public_identity,
			charlie_private_identity,
			buffer_create_from_string("Charlie"),
			buffer_create_from_string("identity"));
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to generate Charlie's identity keypair.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		return status;
	}

	//charlie's prekeys
	buffer_t *charlie_private_prekeys = buffer_create(PREKEY_AMOUNT * crypto_box_SECRETKEYBYTES, PREKEY_AMOUNT * crypto_box_SECRETKEYBYTES);
	buffer_t *charlie_public_prekeys = buffer_create(PREKEY_AMOUNT * crypto_box_PUBLICKEYBYTES, PREKEY_AMOUNT * crypto_box_PUBLICKEYBYTES);
	status = generate_prekeys(charlie_private_prekeys, charlie_public_prekeys);
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to generate Charlie's prekeys.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		return status;
	}

	//add alice to the user store
	status = user_store_add(
			store,
			alice_public_identity,
			alice_private_identity,
			alice_public_prekeys,
			alice_private_prekeys);
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to add Alice to the user store.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return status;
	}
	printf("Successfully added Alice to the user store.\n");

	//check length of the user store
	sodium_mprotect_readonly(store);
	if (store->length != 1) {
		fprintf(stderr, "ERROR: User store has incorrect length.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	sodium_mprotect_noaccess(store);
	printf("Length of the user store matches.");

	//list user store
	list = user_store_list(store);
	if (buffer_compare(list, alice_public_identity) != 0) {
		fprintf(stderr, "ERROR: Failed to list users.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		buffer_destroy_from_heap(list);
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	buffer_destroy_from_heap(list);
	printf("Successfully listed users.\n");

	//add bob to the user store
	status = user_store_add(
			store,
			bob_public_identity,
			bob_private_identity,
			bob_public_prekeys,
			bob_private_prekeys);
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to add Bob to the user store.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return status;
	}
	printf("Successfully added Bob to the user store.\n");

	//check length of the user store
	sodium_mprotect_readonly(store);
	if (store->length != 2) {
		fprintf(stderr, "ERROR: User store has incorrect length.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	sodium_mprotect_noaccess(store);
	printf("Length of the user store matches.");

	//list user store
	list = user_store_list(store);
	if ((buffer_compare_partial(list, 0, alice_public_identity, 0, crypto_box_PUBLICKEYBYTES) != 0)
			|| (buffer_compare_partial(list, crypto_box_PUBLICKEYBYTES, bob_public_identity, 0, crypto_box_PUBLICKEYBYTES) != 0)) {
		fprintf(stderr, "ERROR: Failed to list users.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		buffer_destroy_from_heap(list);
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	buffer_destroy_from_heap(list);
	printf("Successfully listed users.\n");

	//add charlie to the user store
	status = user_store_add(
			store,
			charlie_public_identity,
			charlie_private_identity,
			charlie_public_prekeys,
			charlie_private_prekeys);
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to add Charlie to the user store.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return status;
	}
	printf("Successfully added Charlie to the user store.\n");

	//check length of the user store
	sodium_mprotect_readonly(store);
	if (store->length != 3) {
		fprintf(stderr, "ERROR: User store has incorrect length.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	sodium_mprotect_noaccess(store);
	printf("Length of the user store matches.");

	//list user store
	list = user_store_list(store);
	if ((buffer_compare_partial(list, 0, alice_public_identity, 0, crypto_box_PUBLICKEYBYTES) != 0)
			|| (buffer_compare_partial(list, crypto_box_PUBLICKEYBYTES, bob_public_identity, 0, crypto_box_PUBLICKEYBYTES) != 0)
			|| (buffer_compare_partial(list, 2 * crypto_box_PUBLICKEYBYTES, charlie_public_identity, 0, crypto_box_PUBLICKEYBYTES) != 0)) {
		fprintf(stderr, "ERROR: Failed to list users.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		buffer_destroy_from_heap(list);
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	buffer_destroy_from_heap(list);
	printf("Successfully listed users.\n");

	//find node
	user_store_node *bob_node = user_store_find_node(store, bob_public_identity);
	if (bob_node == NULL) {
		fprintf(stderr, "ERROR: Failed to find Bob's node.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	printf("Node found.\n");

	sodium_mprotect_readonly(bob_node);
	if ((buffer_compare(&(bob_node->public_identity_key), bob_public_identity) != 0)
			|| (buffer_compare(&(bob_node->private_identity_key), bob_private_identity) != 0)
			|| (buffer_compare(&(bob_node->public_prekeys), bob_public_prekeys) != 0)
			|| (buffer_compare(&(bob_node->private_prekeys), bob_private_prekeys) != 0)) {
		fprintf(stderr, "ERROR: Bob's data from the user store doesn't match.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	sodium_mprotect_noaccess(bob_node);
	printf("Data from the node matches.\n");

	//remove a user identified by it's key
	user_store_remove_by_key(store, bob_public_identity);
	//check the length
	sodium_mprotect_readonly(store);
	if (store->length != 2) {
		fprintf(stderr, "ERROR: User store has incorrect length.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	sodium_mprotect_noaccess(store);
	printf("Length of the user store matches.");
	//check the user list
	list = user_store_list(store);
	if ((buffer_compare_partial(list, 0, alice_public_identity, 0, crypto_box_PUBLICKEYBYTES) != 0)
			|| (buffer_compare_partial(list, crypto_box_PUBLICKEYBYTES, charlie_public_identity, 0, crypto_box_PUBLICKEYBYTES) != 0)) {
		fprintf(stderr, "ERROR: Removing user failed.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		buffer_destroy_from_heap(list);
		return EXIT_FAILURE;
	}
	buffer_destroy_from_heap(list);
	printf("Successfully removed user.\n");

	//readd bob
	status = user_store_add(
			store,
			bob_public_identity,
			bob_private_identity,
			bob_public_prekeys,
			bob_private_prekeys);
	if (status != 0) {
		fprintf(stderr, "ERROR: Failed to readd Bob to the user store.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return status;
	}
	printf("Successfully readded Bob to the user store.\n");

	//now find bob again
	bob_node = user_store_find_node(store, bob_public_identity);
	if (bob_node == NULL) {
		fprintf(stderr, "ERROR: Failed to find Bob's node.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	printf("Bob's node found again.\n");

	//remove bob by it's node
	user_store_remove(store, bob_node);
	//check the length
	sodium_mprotect_readonly(store);
	if (store->length != 2) {
		fprintf(stderr, "ERROR: User store has incorrect length.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	sodium_mprotect_noaccess(store);
	printf("Length of the user store matches.");
	//check the user list
	list = user_store_list(store);
	if ((buffer_compare_partial(list, 0, alice_public_identity, 0, crypto_box_PUBLICKEYBYTES) != 0)
			|| (buffer_compare_partial(list, crypto_box_PUBLICKEYBYTES, charlie_public_identity, 0, crypto_box_PUBLICKEYBYTES) != 0)) {
		fprintf(stderr, "ERROR: Removing user failed.\n");
		buffer_clear(alice_private_identity);
		buffer_clear(alice_private_prekeys);
		buffer_clear(bob_private_identity);
		buffer_clear(bob_private_prekeys);
		buffer_clear(charlie_private_identity);
		buffer_clear(charlie_private_prekeys);
		user_store_destroy(store);
		buffer_destroy_from_heap(list);
		return EXIT_FAILURE;
	}
	buffer_destroy_from_heap(list);
	printf("Successfully removed user.\n");

	buffer_clear(alice_private_identity);
	buffer_clear(alice_private_prekeys);
	buffer_clear(bob_private_identity);
	buffer_clear(bob_private_prekeys);
	buffer_clear(charlie_private_identity);
	buffer_clear(charlie_private_prekeys);

	//clear the user store
	user_store_clear(store);
	//check the length
	sodium_mprotect_readonly(store);
	if (store->length != 0) {
		fprintf(stderr, "ERROR: User store has incorrect length.\n");
		user_store_destroy(store);
		return EXIT_FAILURE;
	}
	printf("Successfully cleared user store.\n");

	sodium_mprotect_noaccess(store);

	user_store_destroy(store);
	return EXIT_SUCCESS;
}
Ejemplo n.º 7
0
return_status master_keys_export(
		master_keys * const keys,
		Key ** const public_signing_key,
		Key ** const private_signing_key,
		Key ** const public_identity_key,
		Key ** const private_identity_key) {
	return_status status = return_status_init();

	//check input
	if ((keys == NULL)
			|| (public_signing_key == NULL) || (private_signing_key == NULL)
			|| (public_identity_key == NULL) || (private_identity_key == NULL)) {
		throw(INVALID_INPUT, "Invalid input to keys_export");
	}

	//allocate the structs
	*public_signing_key = zeroed_malloc(sizeof(Key));
	throw_on_failed_alloc(*public_signing_key);
	key__init(*public_signing_key);
	*private_signing_key = zeroed_malloc(sizeof(Key));
	throw_on_failed_alloc(*private_signing_key);
	key__init(*private_signing_key);
	*public_identity_key = zeroed_malloc(sizeof(Key));
	throw_on_failed_alloc(*public_identity_key);
	key__init(*public_identity_key);
	*private_identity_key = zeroed_malloc(sizeof(Key));
	throw_on_failed_alloc(*private_identity_key);
	key__init(*private_identity_key);

	//allocate the key buffers
	(*public_signing_key)->key.data = zeroed_malloc(PUBLIC_MASTER_KEY_SIZE);
	throw_on_failed_alloc((*public_signing_key)->key.data);
	(*public_signing_key)->key.len = PUBLIC_MASTER_KEY_SIZE;
	(*private_signing_key)->key.data = zeroed_malloc(PRIVATE_MASTER_KEY_SIZE);
	throw_on_failed_alloc((*private_signing_key)->key.data);
	(*private_signing_key)->key.len = PRIVATE_MASTER_KEY_SIZE;
	(*public_identity_key)->key.data = zeroed_malloc(PUBLIC_KEY_SIZE);
	throw_on_failed_alloc((*public_identity_key)->key.data);
	(*public_identity_key)->key.len = PUBLIC_KEY_SIZE;
	(*private_identity_key)->key.data = zeroed_malloc(PUBLIC_KEY_SIZE);
	throw_on_failed_alloc((*private_identity_key)->key.data);
	(*private_identity_key)->key.len = PUBLIC_KEY_SIZE;

	//unlock the master keys
	sodium_mprotect_readonly(keys);

	//copy the keys
	if (buffer_clone_to_raw((*public_signing_key)->key.data, (*public_signing_key)->key.len, keys->public_signing_key) != 0) {
		throw(BUFFER_ERROR, "Failed to export public signing key.");
	}
	if (buffer_clone_to_raw((*private_signing_key)->key.data, (*private_signing_key)->key.len, keys->private_signing_key) != 0) {
		throw(BUFFER_ERROR, "Failed to export private signing key.");
	}
	if (buffer_clone_to_raw((*public_identity_key)->key.data, (*public_identity_key)->key.len, keys->public_identity_key) != 0) {
		throw(BUFFER_ERROR, "Failed to export public identity key.");
	}
	if (buffer_clone_to_raw((*private_identity_key)->key.data, (*private_identity_key)->key.len, keys->private_identity_key) != 0) {
		throw(BUFFER_ERROR, "Failed to export private identity key.");
	}

cleanup:
	on_error {
		if ((public_signing_key != NULL) && (*public_signing_key != NULL)) {
			key__free_unpacked(*public_signing_key, &protobuf_c_allocators);
			*public_signing_key = NULL;
		}

		if ((private_signing_key != NULL) && (*private_signing_key != NULL)) {
			key__free_unpacked(*private_signing_key, &protobuf_c_allocators);
			*private_signing_key = NULL;
		}

		if ((public_identity_key != NULL) && (*public_identity_key != NULL)) {
			key__free_unpacked(*public_identity_key, &protobuf_c_allocators);
			*public_identity_key = NULL;
		}

		if ((private_identity_key != NULL) && (*private_identity_key != NULL)) {
			key__free_unpacked(*private_identity_key, &protobuf_c_allocators);
			*private_identity_key = NULL;
		}

	}

	if (keys != NULL) {
		sodium_mprotect_noaccess(keys);
	}

	return status;
}