Add a test for the axolotl API

This commit is contained in:
Mark Haines 2015-06-16 15:15:40 +01:00
parent 11861404e4
commit 76f49cf177
7 changed files with 178 additions and 9 deletions

View file

@ -67,7 +67,6 @@ std::size_t enc_output(
std::size_t length = ciphertext_length + PICKLE_CIPHER.mac_length(); std::size_t length = ciphertext_length + PICKLE_CIPHER.mac_length();
std::size_t base64_length = axolotl::encode_base64_length(length); std::size_t base64_length = axolotl::encode_base64_length(length);
std::uint8_t * raw_output = output + base64_length - length; std::uint8_t * raw_output = output + base64_length - length;
length -= PICKLE_CIPHER.mac_length();
PICKLE_CIPHER.encrypt( PICKLE_CIPHER.encrypt(
key, key_length, key, key_length,
raw_output, raw_length, raw_output, raw_length,
@ -395,6 +394,12 @@ size_t axolotl_account_one_time_keys(
} }
size_t axolotl_create_outbound_session_random_length(
AxolotlSession * session
) {
return from_c(session)->new_outbound_session_random_length();
}
size_t axolotl_create_outbound_session( size_t axolotl_create_outbound_session(
AxolotlSession * session, AxolotlSession * session,
AxolotlAccount * account, AxolotlAccount * account,

View file

@ -237,15 +237,18 @@ std::size_t axolotl::aes_decrypt_cbc(
) { ) {
std::uint32_t key_schedule[60]; std::uint32_t key_schedule[60];
::aes_key_setup(key.key, key_schedule, 256); ::aes_key_setup(key.key, key_schedule, 256);
std::uint8_t block1[AES_BLOCK_LENGTH];
std::uint8_t block2[AES_BLOCK_LENGTH];
std::memcpy(block1, iv.iv, AES_BLOCK_LENGTH);
for (std::size_t i = 0; i < input_length; i += AES_BLOCK_LENGTH) { for (std::size_t i = 0; i < input_length; i += AES_BLOCK_LENGTH) {
std::memcpy(block2, &input[i], AES_BLOCK_LENGTH);
::aes_decrypt(&input[i], &output[i], key_schedule, 256); ::aes_decrypt(&input[i], &output[i], key_schedule, 256);
if (i == 0) { xor_block<AES_BLOCK_LENGTH>(&output[i], block1);
xor_block<AES_BLOCK_LENGTH>(&output[i], iv.iv); std::memcpy(block1, block2, AES_BLOCK_LENGTH);
} else {
xor_block<AES_BLOCK_LENGTH>(&output[i], &input[i - AES_BLOCK_LENGTH]);
}
} }
axolotl::unset(key_schedule); axolotl::unset(key_schedule);
axolotl::unset(block1);
axolotl::unset(block2);
std::size_t padding = output[input_length - 1]; std::size_t padding = output[input_length - 1];
return (padding > input_length) ? std::size_t(-1) : (input_length - padding); return (padding > input_length) ? std::size_t(-1) : (input_length - padding);
} }

View file

@ -141,12 +141,12 @@ std::size_t verify_mac_and_decrypt_for_new_chain(
/* They shouldn't move to a new chain until we've sent them a message /* They shouldn't move to a new chain until we've sent them a message
* acknowledging the last one */ * acknowledging the last one */
if (session.sender_chain.empty()) { if (session.sender_chain.empty()) {
return false; return std::size_t(-1);
} }
/* Limit the number of hashes we're prepared to compute */ /* Limit the number of hashes we're prepared to compute */
if (reader.counter > MAX_MESSAGE_GAP) { if (reader.counter > MAX_MESSAGE_GAP) {
return false; return std::size_t(-1);
} }
std::memcpy( std::memcpy(
new_chain.ratchet_key.public_key, reader.ratchet_key, KEY_LENGTH new_chain.ratchet_key.public_key, reader.ratchet_key, KEY_LENGTH
@ -191,6 +191,7 @@ void axolotl::Ratchet::initialise_as_bob(
derived_secrets, sizeof(derived_secrets) derived_secrets, sizeof(derived_secrets)
); );
receiver_chains.insert(); receiver_chains.insert();
receiver_chains[0].chain_key.index = 0;
std::memcpy(root_key, derived_secrets, 32); std::memcpy(root_key, derived_secrets, 32);
std::memcpy(receiver_chains[0].chain_key.key, derived_secrets + 32, 32); std::memcpy(receiver_chains[0].chain_key.key, derived_secrets + 32, 32);
receiver_chains[0].ratchet_key = their_ratchet_key; receiver_chains[0].ratchet_key = their_ratchet_key;
@ -210,6 +211,7 @@ void axolotl::Ratchet::initialise_as_alice(
derived_secrets, sizeof(derived_secrets) derived_secrets, sizeof(derived_secrets)
); );
sender_chain.insert(); sender_chain.insert();
sender_chain[0].chain_key.index = 0;
std::memcpy(root_key, derived_secrets, 32); std::memcpy(root_key, derived_secrets, 32);
std::memcpy(sender_chain[0].chain_key.key, derived_secrets + 32, 32); std::memcpy(sender_chain[0].chain_key.key, derived_secrets + 32, 32);
sender_chain[0].ratchet_key = our_ratchet_key; sender_chain[0].ratchet_key = our_ratchet_key;

View file

@ -332,6 +332,8 @@ std::size_t axolotl::Session::decrypt(
if (result == std::size_t(-1)) { if (result == std::size_t(-1)) {
last_error = ratchet.last_error; last_error = ratchet.last_error;
ratchet.last_error = axolotl::ErrorCode::SUCCESS; ratchet.last_error = axolotl::ErrorCode::SUCCESS;
} else {
received_message = true;
} }
return result; return result;
} }

View file

@ -53,6 +53,25 @@ void assert_equals(
} }
} }
template<typename T>
void assert_not_equals(
const char *file,
unsigned line,
const char *expected_expr,
const char *actual_expr,
T const & expected,
T const & actual
) {
if (expected == actual) {
std::cout << "FAILED: " << TEST_CASE << std::endl;
std::cout << file << ":" << line << std::endl;
std::cout << expected_expr << " == " << actual_expr << std::endl;
std::cout << "Unexpected: " << expected << std::endl;
std::cout << "Actual: " << actual << std::endl;
std::exit(1);
}
}
void assert_equals( void assert_equals(
const char *file, const char *file,
@ -77,6 +96,10 @@ void assert_equals(
__FILE__, __LINE__, #expected, #actual, expected, actual, ##__VA_ARGS__ \ __FILE__, __LINE__, #expected, #actual, expected, actual, ##__VA_ARGS__ \
) )
#define assert_not_equals(expected, actual, ...) assert_not_equals( \
__FILE__, __LINE__, #expected, #actual, expected, actual, ##__VA_ARGS__ \
)
class TestCase { class TestCase {
public: public:
TestCase(const char *name) { TEST_CASE = name; } TestCase(const char *name) { TEST_CASE = name; }

135
tests/test_axolotl.cpp Normal file
View file

@ -0,0 +1,135 @@
#include "axolotl/axolotl.hh"
#include "unittest.hh"
#include <cstddef>
#include <cstdint>
#include <cstring>
int main() {
{ /** Pickle account test */
TestCase test_case("Pickle account test");
std::uint8_t account_buffer[::axolotl_account_size()];
::AxolotlAccount *account = ::axolotl_account(account_buffer);
std::size_t random_length = ::axolotl_create_account_random_length(account);
std::uint8_t random[random_length];
std::memset(random, 4, random_length); /* http://xkcd.com/221/ */
::axolotl_create_account(account, random, random_length);
std::size_t pickle_length = ::axolotl_pickle_account_length(account);
std::uint8_t pickle1[pickle_length];
::axolotl_pickle_account(account, "secret_key", 10, pickle1, pickle_length);
std::uint8_t pickle2[pickle_length];
std::memcpy(pickle2, pickle1, pickle_length);
std::uint8_t account_buffer2[::axolotl_account_size()];
::AxolotlAccount *account2 = ::axolotl_account(account_buffer2);
::axolotl_unpickle_account(account2, "secret_key", 10, pickle2, pickle_length);
assert_equals(pickle_length, ::axolotl_pickle_account_length(account2));
::axolotl_pickle_account(account2, "secret_key", 10, pickle2, pickle_length);
assert_equals(pickle1, pickle2, pickle_length);
}
{ /** Loopback test */
TestCase test_case("Loopback test");
std::uint8_t a_account_buffer[::axolotl_account_size()];
::AxolotlAccount *a_account = ::axolotl_account(a_account_buffer);
std::uint8_t a_random[::axolotl_create_account_random_length(a_account)];
std::memset(a_random, 4, sizeof(a_random)); /* http://xkcd.com/221/ */
::axolotl_create_account(a_account, a_random, sizeof(a_random));
std::uint8_t b_account_buffer[::axolotl_account_size()];
::AxolotlAccount *b_account = ::axolotl_account(b_account_buffer);
std::uint8_t b_random[::axolotl_create_account_random_length(b_account)];
std::memset(b_random, 5, sizeof(b_random)); /* http://xkcd.com/221/ */
::axolotl_create_account(b_account, b_random, sizeof(b_random));
std::uint8_t b_id_keys[::axolotl_account_identity_keys_length(b_account)];
std::uint8_t b_ot_keys[::axolotl_account_one_time_keys_length(b_account)];
::axolotl_account_identity_keys(b_account, b_id_keys, sizeof(b_id_keys));
::axolotl_account_one_time_keys(b_account, b_ot_keys, sizeof(b_ot_keys));
std::uint8_t a_session_buffer[::axolotl_session_size()];
::AxolotlSession *a_session = ::axolotl_session(a_session_buffer);
std::uint8_t a_rand[::axolotl_create_outbound_session_random_length(a_session)];
std::memset(b_random, 6, sizeof(a_rand)); /* http://xkcd.com/221/ */
assert_not_equals(std::size_t(-1), ::axolotl_create_outbound_session(
a_session, a_account,
b_id_keys + 14, 43,
::atol((char *)(b_ot_keys + 62)), b_ot_keys + 74, 43,
a_rand, sizeof(a_rand)
));
std::uint8_t plaintext[] = "Hello, World";
std::uint8_t message_1[::axolotl_encrypt_message_length(a_session, 12)];
std::uint8_t a_message_random[::axolotl_encrypt_random_length(a_session)];
assert_equals(std::size_t(0), ::axolotl_encrypt_message_type(a_session));
assert_not_equals(std::size_t(-1), ::axolotl_encrypt(
a_session,
plaintext, 12,
a_message_random, sizeof(a_message_random),
message_1, sizeof(message_1)
));
std::uint8_t tmp_message_1[sizeof(message_1)];
std::memcpy(tmp_message_1, message_1, sizeof(message_1));
std::uint8_t b_session_buffer[::axolotl_account_size()];
::AxolotlSession *b_session = ::axolotl_session(b_session_buffer);
::axolotl_create_inbound_session(
b_session, b_account, tmp_message_1, sizeof(message_1)
);
std::memcpy(tmp_message_1, message_1, sizeof(message_1));
std::uint8_t plaintext_1[::axolotl_decrypt_max_plaintext_length(
b_session, 0, tmp_message_1, sizeof(message_1)
)];
std::memcpy(tmp_message_1, message_1, sizeof(message_1));
assert_equals(std::size_t(12), ::axolotl_decrypt(
b_session, 0,
tmp_message_1, sizeof(message_1),
plaintext_1, sizeof(plaintext_1)
));
assert_equals(plaintext, plaintext_1, 12);
std::uint8_t message_2[::axolotl_encrypt_message_length(b_session, 12)];
std::uint8_t b_message_random[::axolotl_encrypt_random_length(b_session)];
assert_equals(std::size_t(1), ::axolotl_encrypt_message_type(b_session));
assert_not_equals(std::size_t(-1), ::axolotl_encrypt(
b_session,
plaintext, 12,
b_message_random, sizeof(b_message_random),
message_2, sizeof(message_2)
));
std::uint8_t tmp_message_2[sizeof(message_2)];
std::memcpy(tmp_message_2, message_2, sizeof(message_2));
std::uint8_t plaintext_2[::axolotl_decrypt_max_plaintext_length(
a_session, 1, tmp_message_2, sizeof(message_2)
)];
std::memcpy(tmp_message_2, message_2, sizeof(message_2));
assert_equals(std::size_t(12), ::axolotl_decrypt(
a_session, 1,
tmp_message_2, sizeof(message_2),
plaintext_2, sizeof(plaintext_2)
));
assert_equals(plaintext, plaintext_2, 12);
std::memcpy(tmp_message_2, message_2, sizeof(message_2));
assert_equals(std::size_t(-1), ::axolotl_decrypt(
a_session, 1,
tmp_message_2, sizeof(message_2),
plaintext_2, sizeof(plaintext_2)
));
}
}

View file

@ -1,4 +1,3 @@
#include "axolotl/base64.hh" #include "axolotl/base64.hh"
#include "unittest.hh" #include "unittest.hh"