From e998aca8f75e46cd360210ac588ee77af0106c6d Mon Sep 17 00:00:00 2001 From: Dubslow Date: Tue, 31 Mar 2015 18:15:59 -0500 Subject: Fix toxencryptsave to be consistent with new_api Upon my own decision, the two tox_encryped_new convenience functions were removed due to basically needing two different sets of error codes. At iphydf's suggestion the corresponding tox_get_encrypted_savedata convenience functions were removed as well. --- auto_tests/encryptsave_test.c | 124 +++++++++++---------- toxencryptsave/toxencryptsave.c | 235 +++++++++++++++------------------------- toxencryptsave/toxencryptsave.h | 220 +++++++++++++++---------------------- 3 files changed, 240 insertions(+), 339 deletions(-) diff --git a/auto_tests/encryptsave_test.c b/auto_tests/encryptsave_test.c index e2f41f43..9ab29a27 100644 --- a/auto_tests/encryptsave_test.c +++ b/auto_tests/encryptsave_test.c @@ -55,7 +55,6 @@ END_TEST START_TEST(test_save_friend) { - TOX_ERR_ENCRYPTED_NEW err = TOX_ERR_ENCRYPTED_NEW_OK; Tox *tox1 = tox_new(0, 0, 0, 0); Tox *tox2 = tox_new(0, 0, 0, 0); ck_assert_msg(tox1 || tox2, "Failed to create 2 tox instances"); @@ -63,99 +62,108 @@ START_TEST(test_save_friend) tox_callback_friend_request(tox2, accept_friend_request, &to_compare); uint8_t address[TOX_ADDRESS_SIZE]; tox_self_get_address(tox2, address); - int test = tox_friend_add(tox1, address, (uint8_t *)"Gentoo", 7, 0); - ck_assert_msg(test == 0, "Failed to add friend error code: %i", test); + uint32_t test = tox_friend_add(tox1, address, (uint8_t *)"Gentoo", 7, 0); + ck_assert_msg(test != UINT32_MAX, "Failed to add friend"); - uint32_t size = tox_encrypted_size(tox1); + size_t size = tox_get_savedata_size(tox1); uint8_t data[size]; - test = tox_encrypted_save(tox1, data, "correcthorsebatterystaple", 25); - ck_assert_msg(test == 0, "failed to encrypted save"); - //ck_assert_msg(tox_is_save_encrypted(data) == 1, "magic number missing"); - - Tox *tox3 = tox_encrypted_new(0, data, size, "correcthorsebatterystaple", 25, &err); - ck_assert_msg(err == TOX_ERR_ENCRYPTED_NEW_OK, "failed to encrypted new"); + tox_get_savedata(tox1, data); + size_t size2 = size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH; + uint8_t enc_data[size2]; + TOX_ERR_ENCRYPTION error1; + bool ret = tox_pass_encrypt(data, size, "correcthorsebatterystaple", 25, enc_data, &error1); + ck_assert_msg(ret, "failed to encrypted save: %u", error1); + ck_assert_msg(tox_is_data_encrypted(enc_data), "magic number missing"); + + TOX_ERR_NEW err2; + Tox *tox3 = tox_new(0, enc_data, size2, &err2); + ck_assert_msg(err2 == TOX_ERR_NEW_LOAD_ENCRYPTED, "wrong error! %u. should fail with %u", err2, TOX_ERR_NEW_LOAD_ENCRYPTED); + uint8_t dec_data[size]; + TOX_ERR_DECRYPTION err3; + ret = tox_pass_decrypt(enc_data, size2, "correcthorsebatterystaple", 25, dec_data, &err3); + ck_assert_msg(ret, "failed to decrypt save: %u", err3); + tox3 = tox_new(0, dec_data, size, &err2); + ck_assert_msg(err2 == TOX_ERR_NEW_OK, "failed to load from decrypted data: %u", err2); uint8_t address2[TOX_PUBLIC_KEY_SIZE]; - test = tox_friend_get_public_key(tox3, 0, address2, 0); - ck_assert_msg(test == 1, "no friends!"); + ret = tox_friend_get_public_key(tox3, 0, address2, 0); + ck_assert_msg(ret, "no friends!"); ck_assert_msg(memcmp(address, address2, TOX_PUBLIC_KEY_SIZE) == 0, "addresses don't match!"); - size = tox_encrypted_size(tox3); + size = tox_get_savedata_size(tox3); uint8_t data2[size]; + tox_get_savedata(tox3, data2); uint8_t key[32 + crypto_box_BEFORENMBYTES]; memcpy(key, salt, 32); memcpy(key + 32, known_key2, crypto_box_BEFORENMBYTES); - test = tox_encrypted_key_save(tox3, data2, key); - ck_assert_msg(test == 0, "failed to encrypted save the second"); - //ck_assert_msg(tox_is_save_encrypted(data2) == 1, "magic number the second missing"); - - // first test tox_encrypted_key_new - Tox *tox4 = tox_encrypted_key_new(0, data2, size, key, &err); - ck_assert_msg(err == TOX_ERR_ENCRYPTED_NEW_OK, "failed to encrypted new the second"); - uint8_t address4[TOX_PUBLIC_KEY_SIZE]; - test = tox_friend_get_public_key(tox4, 0, address4, 0); - ck_assert_msg(test == 1, "no friends! the second"); - ck_assert_msg(memcmp(address, address2, TOX_PUBLIC_KEY_SIZE) == 0, "addresses don't match! the second"); - - // now test compaitibilty with tox_encrypted_new, first manually... + size2 = size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH; + uint8_t encdata2[size2]; + ret = tox_pass_key_encrypt(data2, size, key, encdata2, &error1); + ck_assert_msg(ret, "failed to key encrypt %u", error1); + ck_assert_msg(tox_is_data_encrypted(encdata2), "magic number the second missing"); + uint8_t out1[size], out2[size]; - //printf("Trying to decrypt from pw:\n"); - uint32_t sz1 = tox_pass_decrypt(data2, size, pw, pwlen, out1); - uint32_t sz2 = tox_pass_key_decrypt(data2, size, key, out2); - ck_assert_msg(sz1 == sz2, "differing output sizes"); - ck_assert_msg(memcmp(out1, out2, sz1) == 0, "differing output data"); + ret = tox_pass_decrypt(encdata2, size2, pw, pwlen, out1, &err3); + ck_assert_msg(ret, "failed to pw decrypt %u", err3); + ret = tox_pass_key_decrypt(encdata2, size2, key, out2, &err3); + ck_assert_msg(ret, "failed to key decrypt %u", err3); + ck_assert_msg(memcmp(out1, out2, size) == 0, "differing output data"); // and now with the code in use (I only bothered with manually to debug this, and it seems a waste // to remove the manual check now that it's there) - Tox *tox5 = tox_encrypted_new(0, data2, size, pw, pwlen, &err); - ck_assert_msg(err == TOX_ERR_ENCRYPTED_NEW_OK, "failed to encrypted new the third"); + Tox *tox4 = tox_new(0, out1, size, &err2); + ck_assert_msg(err2 == TOX_ERR_NEW_OK, "failed to new the third"); uint8_t address5[TOX_PUBLIC_KEY_SIZE]; - test = tox_friend_get_public_key(tox4, 0, address5, 0); - ck_assert_msg(test == 1, "no friends! the third"); + ret = tox_friend_get_public_key(tox4, 0, address5, 0); + ck_assert_msg(ret, "no friends! the third"); ck_assert_msg(memcmp(address, address2, TOX_PUBLIC_KEY_SIZE) == 0, "addresses don't match! the third"); tox_kill(tox1); tox_kill(tox2); tox_kill(tox3); tox_kill(tox4); - tox_kill(tox5); } END_TEST START_TEST(test_keys) { - uint8_t key[tox_pass_key_length()]; - tox_derive_key_from_pass("123qweasdzxc", 12, key); + TOX_ERR_ENCRYPTION encerr; + TOX_ERR_DECRYPTION decerr; + TOX_ERR_KEY_DERIVATION keyerr; + uint8_t key[TOX_PASS_KEY_LENGTH]; + bool ret = tox_derive_key_from_pass("123qweasdzxc", 12, key, &keyerr); + ck_assert_msg(ret, "generic failure 1: %u", keyerr); uint8_t *string = "No Patrick, mayonnaise is not an instrument."; // 44 - uint8_t encrypted[44 + tox_pass_encryption_extra_length()]; - int sz = tox_pass_key_encrypt(string, 44, key, encrypted); - - uint8_t encrypted2[44 + tox_pass_encryption_extra_length()]; - int sz2 = tox_pass_encrypt(string, 44, "123qweasdzxc", 12, encrypted2); + uint8_t encrypted[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH]; + ret = tox_pass_key_encrypt(string, 44, key, encrypted, &encerr); + ck_assert_msg(ret, "generic failure 2: %u", encerr); - ck_assert_msg(sz == sz2, "an encryption failed"); + uint8_t encrypted2[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH]; + ret = tox_pass_encrypt(string, 44, "123qweasdzxc", 12, encrypted2, &encerr); + ck_assert_msg(ret, "generic failure 3: %u", encerr); - uint8_t out1[44 + tox_pass_encryption_extra_length()]; - uint8_t out2[44 + tox_pass_encryption_extra_length()]; + uint8_t out1[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH]; + uint8_t out2[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH]; - sz = tox_pass_key_decrypt(encrypted, 44 + tox_pass_encryption_extra_length(), key, out1); - ck_assert_msg(sz == 44, "sz isn't right"); + ret = tox_pass_key_decrypt(encrypted, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, key, out1, &decerr); + ck_assert_msg(ret, "generic failure 4: %u", decerr); ck_assert_msg(memcmp(out1, string, 44) == 0, "decryption 1 failed"); - sz2 = tox_pass_decrypt(encrypted2, 44 + tox_pass_encryption_extra_length(), "123qweasdzxc", 12, out2); - ck_assert_msg(sz2 == 44, "sz2 isn't right"); + ret = tox_pass_decrypt(encrypted2, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, "123qweasdzxc", 12, out2, &decerr); + ck_assert_msg(ret, "generic failure 5: %u", &decerr); ck_assert_msg(memcmp(out2, string, 44) == 0, "decryption 2 failed"); // test that pass_decrypt can decrypt things from pass_key_encrypt - sz = tox_pass_decrypt(encrypted, 44 + tox_pass_encryption_extra_length(), "123qweasdzxc", 12, out1); - ck_assert_msg(sz == 44, "sz isn't right"); + ret = tox_pass_decrypt(encrypted, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, "123qweasdzxc", 12, out1, &decerr); + ck_assert_msg(ret, "generic failure 6: %u", decerr); ck_assert_msg(memcmp(out1, string, 44) == 0, "decryption 3 failed"); - uint8_t salt[tox_pass_salt_length()]; - ck_assert_msg(0 == tox_get_salt(encrypted, salt), "couldn't get salt"); - uint8_t key2[tox_pass_key_length()]; - tox_derive_key_with_salt("123qweasdzxc", 12, salt, key2); - ck_assert_msg(0 == memcmp(key, key2, tox_pass_key_length()), "salt comparison failed"); + uint8_t salt[TOX_PASS_SALT_LENGTH]; + ck_assert_msg(tox_get_salt(encrypted, salt), "couldn't get salt"); + uint8_t key2[TOX_PASS_KEY_LENGTH]; + ret = tox_derive_key_with_salt("123qweasdzxc", 12, salt, key2, &keyerr); + ck_assert_msg(ret, "generic failure 7: %u", keyerr); + ck_assert_msg(0 == memcmp(key, key2, TOX_PASS_KEY_LENGTH), "salt comparison failed"); } END_TEST @@ -163,7 +171,7 @@ Suite *encryptsave_suite(void) { Suite *s = suite_create("encryptsave"); - DEFTESTCASE_SLOW(known_kdf, 60); /* is 5-10 seconds on my computer, but is directly dependent on CPU */ + DEFTESTCASE_SLOW(known_kdf, 60); DEFTESTCASE_SLOW(save_friend, 20); DEFTESTCASE_SLOW(keys, 30); diff --git a/toxencryptsave/toxencryptsave.c b/toxencryptsave/toxencryptsave.c index 874f0fd0..e7ec31f1 100644 --- a/toxencryptsave/toxencryptsave.c +++ b/toxencryptsave/toxencryptsave.c @@ -37,81 +37,68 @@ #include #endif -#define TOX_PASS_ENCRYPTION_EXTRA_LENGTH (crypto_box_MACBYTES + crypto_box_NONCEBYTES \ - + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH) - -#define TOX_PASS_KEY_LENGTH (crypto_pwhash_scryptsalsa208sha256_SALTBYTES + crypto_box_KEYBYTES) - -int tox_pass_encryption_extra_length() -{ - return TOX_PASS_ENCRYPTION_EXTRA_LENGTH; -} +#if TOX_PASS_SALT_LENGTH != crypto_pwhash_scryptsalsa208sha256_SALTBYTES +#error TOX_PASS_SALT_LENGTH is assumed to be equal to crypto_pwhash_scryptsalsa208sha256_SALTBYTES +#endif -int tox_pass_key_length() -{ - return TOX_PASS_KEY_LENGTH; -} +#if TOX_PASS_KEY_LENGTH != (crypto_pwhash_scryptsalsa208sha256_SALTBYTES + crypto_box_KEYBYTES) +#error TOX_PASS_KEY_LENGTH is assumed to be equal to (crypto_pwhash_scryptsalsa208sha256_SALTBYTES + crypto_box_KEYBYTES) +#endif -int tox_pass_salt_length() -{ - return crypto_pwhash_scryptsalsa208sha256_SALTBYTES; -} +#if TOX_PASS_ENCRYPTION_EXTRA_LENGTH != (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH) +#error TOX_PASS_ENCRYPTION_EXTRA_LENGTH is assumed to be equal to (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH) +#endif -/* This "module" provides functions analogous to tox_load and tox_save in toxcore - * Clients should consider alerting their users that, unlike plain data, if even one bit +/* Clients should consider alerting their users that, unlike plain data, if even one bit * becomes corrupted, the data will be entirely unrecoverable. * Ditto if they forget their password, there is no way to recover the data. */ -/* return size of the messenger data (for encrypted saving). */ -uint32_t tox_encrypted_size(const Tox *tox) -{ - return tox_get_savedata_size(tox) + TOX_PASS_ENCRYPTION_EXTRA_LENGTH; -} - /* This retrieves the salt used to encrypt the given data, which can then be passed to * derive_key_with_salt to produce the same key as was previously used. Any encrpyted * data with this module can be used as input. * - * returns -1 if the magic number is wrong - * returns 0 otherwise (no guarantee about validity of data) + * returns true if magic number matches + * success does not say anything about the validity of the data, only that data of + * the appropriate size was copied */ -int tox_get_salt(uint8_t *data, uint8_t *salt) +bool tox_get_salt(const uint8_t *data, uint8_t *salt) { if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) - return -1; + return 0; data += TOX_ENC_SAVE_MAGIC_LENGTH; memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); - return 0; + return 1; } /* Generates a secret symmetric key from the given passphrase. out_key must be at least * TOX_PASS_KEY_LENGTH bytes long. * Be sure to not compromise the key! Only keep it in memory, do not write to disk. - * This function is fairly cheap, but irungentoo insists that you be allowed to - * cache the result if you want, to minimize computation for repeated encryptions. * The password is zeroed after key derivation. * The key should only be used with the other functions in this module, as it * includes a salt. + * Note that this function is not deterministic; to derive the same key from a + * password, you also must know the random salt that was used. See below. * - * returns 0 on success - * returns -1 on failure + * returns true on success */ -int tox_derive_key_from_pass(uint8_t *passphrase, uint32_t pplength, uint8_t *out_key) +bool tox_derive_key_from_pass(uint8_t *passphrase, size_t pplength, uint8_t *out_key, TOX_ERR_KEY_DERIVATION *error) { uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; randombytes(salt, sizeof salt); - return tox_derive_key_with_salt(passphrase, pplength, salt, out_key); + return tox_derive_key_with_salt(passphrase, pplength, salt, out_key, error); } /* Same as above, except with use the given salt for deterministic key derivation. * The salt must be tox_salt_length() bytes in length. */ -int tox_derive_key_with_salt(uint8_t *passphrase, uint32_t pplength, uint8_t *salt, uint8_t *out_key) +bool tox_derive_key_with_salt(uint8_t *passphrase, size_t pplength, uint8_t *salt, uint8_t *out_key, TOX_ERR_KEY_DERIVATION *error) { - if (pplength == 0) - return -1; + if (pplength == 0 || !passphrase || !salt || !out_key) { + SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_NULL); + return 0; + } uint8_t passkey[crypto_hash_sha256_BYTES]; crypto_hash_sha256(passkey, passphrase, pplength); @@ -127,27 +114,32 @@ int tox_derive_key_with_salt(uint8_t *passphrase, uint32_t pplength, uint8_t *sa crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { /* out of memory most likely */ - return -1; + SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_FAILED); + return 0; } sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ memcpy(out_key, salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); memcpy(out_key + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, key, crypto_box_KEYBYTES); - return 0; + SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_OK); + return 1; } -/* Encrypt arbitrary with a key produced by tox_derive_key_from_pass. The output +/* Encrypt arbitrary with a key produced by tox_derive_key_*. The output * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. * key must be TOX_PASS_KEY_LENGTH bytes. * If you already have a symmetric key from somewhere besides this module, simply * call encrypt_data_symmetric in toxcore/crypto_core directly. * - * - * returns 0 on success - * returns -1 on failure + * returns true on success */ -int tox_pass_key_encrypt(const uint8_t *data, uint32_t data_len, const uint8_t *key, uint8_t *out) +bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const uint8_t *key, uint8_t *out, TOX_ERR_ENCRYPTION *error) { + if (data_len == 0 || !data || !key || !out) { + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL); + return 0; + } + /* the output data consists of, in order: * salt, nonce, mac, enc_data * where the mac is automatically prepended by the encrypt() @@ -173,78 +165,58 @@ int tox_pass_key_encrypt(const uint8_t *data, uint32_t data_len, const uint8_t * /* now encrypt */ if (encrypt_data_symmetric(key, nonce, data, data_len, out) != data_len + crypto_box_MACBYTES) { - return -1; + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_FAILED); + return 0; } - return 0; + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_OK); + return 1; } /* Encrypts the given data with the given passphrase. The output array must be * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates * to tox_derive_key_from_pass and tox_pass_key_encrypt. * - * returns 0 on success - * returns -1 on failure + * returns true on success */ -int tox_pass_encrypt(const uint8_t *data, uint32_t data_len, uint8_t *passphrase, uint32_t pplength, uint8_t *out) +bool tox_pass_encrypt(const uint8_t *data, size_t data_len, uint8_t *passphrase, size_t pplength, uint8_t *out, TOX_ERR_ENCRYPTION *error) { uint8_t key[TOX_PASS_KEY_LENGTH]; + TOX_ERR_KEY_DERIVATION _error; + + if (!tox_derive_key_from_pass(passphrase, pplength, key, &_error)) { + if (_error == TOX_ERR_KEY_DERIVATION_NULL) { + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL); + } else if (_error == TOX_ERR_KEY_DERIVATION_FAILED) { + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED); + } + return 0; + } - if (tox_derive_key_from_pass(passphrase, pplength, key) == -1) - return -1; - - return tox_pass_key_encrypt(data, data_len, key, out); -} - -/* Save the messenger data encrypted with the given password. - * data must be at least tox_encrypted_size(). - * - * returns 0 on success - * returns -1 on failure - */ -int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength) -{ - /* first get plain save data */ - uint32_t temp_size = tox_get_savedata_size(tox); - uint8_t temp_data[temp_size]; - tox_get_savedata(tox, temp_data); - - /* now encrypt */ - return tox_pass_encrypt(temp_data, temp_size, passphrase, pplength, data); -} - -/* Save the messenger data encrypted with the given key from tox_derive_key. - * data must be at least tox_encrypted_size(). - * - * returns 0 on success - * returns -1 on failure - */ -int tox_encrypted_key_save(const Tox *tox, uint8_t *data, uint8_t *key) -{ - /* first get plain save data */ - uint32_t temp_size = tox_get_savedata_size(tox); - uint8_t temp_data[temp_size]; - tox_get_savedata(tox, temp_data); - - /* encrypt */ - return tox_pass_key_encrypt(temp_data, temp_size, key, data); + return tox_pass_key_encrypt(data, data_len, key, out, error); } /* This is the inverse of tox_pass_key_encrypt, also using only keys produced by * tox_derive_key_from_pass. * - * returns the length of the output data (== data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH) on success - * returns -1 on failure + * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH + * + * returns true on success */ -int tox_pass_key_decrypt(const uint8_t *data, uint32_t length, const uint8_t *key, uint8_t *out) +bool tox_pass_key_decrypt(const uint8_t *data, size_t length, const uint8_t *key, uint8_t *out, TOX_ERR_DECRYPTION *error) { - if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH - || 0 != memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH)) - return -1; + if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH); + return 0; + } + if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT); + return 0; + } data += TOX_ENC_SAVE_MAGIC_LENGTH; - uint32_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; + size_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; //uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; uint8_t nonce[crypto_box_NONCEBYTES]; @@ -257,20 +229,29 @@ int tox_pass_key_decrypt(const uint8_t *data, uint32_t length, const uint8_t *ke /* decrypt the data */ if (decrypt_data_symmetric(key, nonce, data, decrypt_length + crypto_box_MACBYTES, out) != decrypt_length) { - return -1; + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_FAILED); + return 0; } - return decrypt_length; + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_OK); + return 1; } /* Decrypts the given data with the given passphrase. The output array must be - * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. + * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates + * to tox_pass_key_decrypt. + * + * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH * - * returns the length of the output data (== data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH) on success - * returns -1 on failure + * returns true on success */ -int tox_pass_decrypt(const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength, uint8_t *out) +bool tox_pass_decrypt(const uint8_t *data, size_t length, uint8_t *passphrase, size_t pplength, uint8_t *out, TOX_ERR_DECRYPTION *error) { + if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT); + return 0; + } + uint8_t passkey[crypto_hash_sha256_BYTES]; crypto_hash_sha256(passkey, passphrase, pplength); @@ -286,60 +267,18 @@ int tox_pass_decrypt(const uint8_t *data, uint32_t length, uint8_t *passphrase, crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { /* out of memory most likely */ - return -1; + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED); + return 0; } sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ - return tox_pass_key_decrypt(data, length, key, out); -} - -/* Load the new messenger from encrypted data of size length. - * All other arguments are like toxcore/tox_new(). - * - * returns NULL on failure; see the documentation in toxcore/tox.h. - */ -Tox *tox_encrypted_new(const struct Tox_Options *options, const uint8_t *data, size_t length, uint8_t *passphrase, - size_t pplength, TOX_ERR_ENCRYPTED_NEW *error) -{ - uint32_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; - uint8_t temp_data[decrypt_length]; - - if (tox_pass_decrypt(data, length, passphrase, pplength, temp_data) - != decrypt_length) { - SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED); - return NULL; - } - - return tox_new(options, temp_data, decrypt_length, error); -} - -/* Load the messenger from encrypted data of size length, with key from tox_derive_key. - * All other arguments are like toxcore/tox_new(). - * - * returns NULL on failure; see the documentation in toxcore/tox.h. - */ -Tox *tox_encrypted_key_new(const struct Tox_Options *options, const uint8_t *data, size_t length, uint8_t *key, - TOX_ERR_ENCRYPTED_NEW *error) -{ - uint32_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; - uint8_t temp_data[decrypt_length]; - - if (tox_pass_key_decrypt(data, length, key, temp_data) - != decrypt_length) { - SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED); - return NULL; - } - - return tox_new(options, temp_data, decrypt_length, error); + return tox_pass_key_decrypt(data, length, key, out, error); } /* Determines whether or not the given data is encrypted (by checking the magic number) - * - * returns 1 if it is encrypted - * returns 0 otherwise */ -int tox_is_data_encrypted(const uint8_t *data) +bool tox_is_data_encrypted(const uint8_t *data) { if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) return 1; diff --git a/toxencryptsave/toxencryptsave.h b/toxencryptsave/toxencryptsave.h index db272592..ef1dfb5e 100644 --- a/toxencryptsave/toxencryptsave.h +++ b/toxencryptsave/toxencryptsave.h @@ -30,6 +30,7 @@ extern "C" { #include #include +#include #ifndef TOX_DEFINED #define TOX_DEFINED @@ -37,21 +38,11 @@ typedef struct Tox Tox; struct Tox_Options; #endif -// these functions provide access to these defines in toxencryptsave.c, which -// otherwise aren't actually available in clients... -int tox_pass_encryption_extra_length(); +#define TOX_PASS_SALT_LENGTH 32 +#define TOX_PASS_KEY_LENGTH 64 +#define TOX_PASS_ENCRYPTION_EXTRA_LENGTH 80 -int tox_pass_key_length(); - -int tox_pass_salt_length(); - -/* return size of the messenger data (for encrypted Messenger saving). */ -uint32_t tox_encrypted_size(const Tox *tox); - -/* This "module" provides functions analogous to tox_load and tox_save in toxcore, - * as well as functions for encryption of arbitrary client data (e.g. chat logs). - * - * It is conceptually organized into two parts. The first part are the functions +/* This module is conceptually organized into two parts. The first part are the functions * with "key" in the name. To use these functions, first derive an encryption key * from a password with tox_derive_key_from_pass, and use the returned key to * encrypt the data. The second part takes the password itself instead of the key, @@ -61,114 +52,100 @@ uint32_t tox_encrypted_size(const Tox *tox); * favor using the first part intead of the second part. * * The encrypted data is prepended with a magic number, to aid validity checking - * (no guarantees are made of course). + * (no guarantees are made of course). Any data to be decrypted must start with + * the magic number. * * Clients should consider alerting their users that, unlike plain data, if even one bit * becomes corrupted, the data will be entirely unrecoverable. * Ditto if they forget their password, there is no way to recover the data. */ - -/******************************* BEGIN PART 2 ******************************* - * For simplicty, the second part of the module is presented first. The API for - * the first part is analgous, with some extra functions for key handling. If - * your code spends too much time using these functions, consider using the part - * 1 functions instead. - */ - -/* Encrypts the given data with the given passphrase. The output array must be - * at least data_len + tox_pass_encryption_extra_length() bytes long. This delegates - * to tox_derive_key_from_pass and tox_pass_key_encrypt. - * - * tox_encrypted_save() is a good example of how to use this function. - * - * returns 0 on success - * returns -1 on failure - */ -int tox_pass_encrypt(const uint8_t *data, uint32_t data_len, uint8_t *passphrase, uint32_t pplength, uint8_t *out); - -/* Save the messenger data encrypted with the given password. - * data must be at least tox_encrypted_size(). - * - * NOTE: Unlike tox_save(), this function may fail. Be sure to check its return - * value. - * - * returns 0 on success - * returns -1 on failure - */ -int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength); - -/* Decrypts the given data with the given passphrase. The output array must be - * at least data_len - tox_pass_encryption_extra_length() bytes long. This delegates - * to tox_pass_key_decrypt. - * - * tox_encrypted_load() is a good example of how to use this function. - * - * returns the length of the output data (== data_len - tox_pass_encryption_extra_length()) on success - * returns -1 on failure - */ -int tox_pass_decrypt(const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength, uint8_t *out); - -typedef enum TOX_ERR_ENCRYPTED_NEW { - TOX_ERR_ENCRYPTED_NEW_OK, - TOX_ERR_ENCRYPTED_NEW_NULL, +typedef enum TOX_ERR_KEY_DERIVATION { + TOX_ERR_KEY_DERIVATION_OK, /** - * The function was unable to allocate enough memory to store the internal - * structures for the Tox object. + * Some input data, or maybe the output pointer, was null. */ - TOX_ERR_ENCRYPTED_NEW_MALLOC, + TOX_ERR_KEY_DERIVATION_NULL, /** - * The function was unable to bind to a port. This may mean that all ports - * have already been bound, e.g. by other Tox instances, or it may mean - * a permission error. You may be able to gather more information from errno. + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. */ - TOX_ERR_ENCRYPTED_NEW_PORT_ALLOC, + TOX_ERR_KEY_DERIVATION_FAILED +} TOX_ERR_KEY_DERIVATION; + +typedef enum TOX_ERR_ENCRYPTION { + TOX_ERR_ENCRYPTION_OK, /** - * proxy_type was invalid. + * Some input data, or maybe the output pointer, was null. */ - TOX_ERR_ENCRYPTED_NEW_PROXY_BAD_TYPE, + TOX_ERR_ENCRYPTION_NULL, /** - * proxy_type was valid but the proxy_host passed had an invalid format - * or was NULL. + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. */ - TOX_ERR_ENCRYPTED_NEW_PROXY_BAD_HOST, + TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED, /** - * proxy_type was valid, but the proxy_port was invalid. + * The encryption itself failed. */ - TOX_ERR_ENCRYPTED_NEW_PROXY_BAD_PORT, + TOX_ERR_ENCRYPTION_FAILED +} TOX_ERR_ENCRYPTION; + +typedef enum TOX_ERR_DECRYPTION { + TOX_ERR_DECRYPTION_OK, + /** + * Some input data, or maybe the output pointer, was null. + */ + TOX_ERR_DECRYPTION_NULL, /** - * The proxy host passed could not be resolved. + * The input data was shorter than TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes */ - TOX_ERR_ENCRYPTED_NEW_PROXY_NOT_FOUND, + TOX_ERR_DECRYPTION_INVALID_LENGTH, /** - * The byte array to be loaded contained an encrypted save. + * The input data is missing the magic number (i.e. wasn't created by this + * module, or is corrupted) */ - TOX_ERR_ENCRYPTED_NEW_LOAD_ENCRYPTED, + TOX_ERR_DECRYPTION_BAD_FORMAT, /** - * The data format was invalid. This can happen when loading data that was - * saved by an older version of Tox, or when the data has been corrupted. - * When loading from badly formatted data, some data may have been loaded, - * and the rest is discarded. Passing an invalid length parameter also - * causes this error. + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. */ - TOX_ERR_ENCRYPTED_NEW_LOAD_BAD_FORMAT, + TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED, /** * The encrypted byte array could not be decrypted. Either the data was * corrupt or the password/key was incorrect. - * - * NOTE: This error code is only set by tox_encrypted_new() and - * tox_encrypted_key_new(), in the toxencryptsave module. */ - TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED -} TOX_ERR_ENCRYPTED_NEW; + TOX_ERR_DECRYPTION_FAILED +} TOX_ERR_DECRYPTION; + + +/******************************* BEGIN PART 2 ******************************* + * For simplicty, the second part of the module is presented first. The API for + * the first part is analgous, with some extra functions for key handling. If + * your code spends too much time using these functions, consider using the part + * 1 functions instead. + */ + +/* Encrypts the given data with the given passphrase. The output array must be + * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates + * to tox_derive_key_from_pass and tox_pass_key_encrypt. + * + * returns true on success + */ +bool tox_pass_encrypt(const uint8_t *data, size_t data_len, uint8_t *passphrase, size_t pplength, uint8_t *out, TOX_ERR_ENCRYPTION *error); -/* Load the new messenger from encrypted data of size length. - * All other arguments are like toxcore/tox_new(). + +/* Decrypts the given data with the given passphrase. The output array must be + * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates + * to tox_pass_key_decrypt. + * + * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH * - * returns NULL on failure; see the documentation in toxcore/tox.h. + * returns true on success */ -Tox *tox_encrypted_new(const struct Tox_Options *options, const uint8_t *data, size_t length, uint8_t *passphrase, - size_t pplength, TOX_ERR_ENCRYPTED_NEW *error); +bool tox_pass_decrypt(const uint8_t *data, size_t length, uint8_t *passphrase, size_t pplength, uint8_t *out, TOX_ERR_DECRYPTION *error); /******************************* BEGIN PART 1 ******************************* @@ -177,7 +154,7 @@ Tox *tox_encrypted_new(const struct Tox_Options *options, const uint8_t *data, s */ /* Generates a secret symmetric key from the given passphrase. out_key must be at least - * tox_pass_key_length() bytes long. + * TOX_PASS_KEY_LENGTH bytes long. * Be sure to not compromise the key! Only keep it in memory, do not write to disk. * The password is zeroed after key derivation. * The key should only be used with the other functions in this module, as it @@ -185,72 +162,49 @@ Tox *tox_encrypted_new(const struct Tox_Options *options, const uint8_t *data, s * Note that this function is not deterministic; to derive the same key from a * password, you also must know the random salt that was used. See below. * - * returns 0 on success - * returns -1 on failure + * returns true on success */ -int tox_derive_key_from_pass(uint8_t *passphrase, uint32_t pplength, uint8_t *out_key); +bool tox_derive_key_from_pass(uint8_t *passphrase, size_t pplength, uint8_t *out_key, TOX_ERR_KEY_DERIVATION *error); /* Same as above, except with use the given salt for deterministic key derivation. * The salt must be tox_salt_length() bytes in length. */ -int tox_derive_key_with_salt(uint8_t *passphrase, uint32_t pplength, uint8_t *salt, uint8_t *out_key); +bool tox_derive_key_with_salt(uint8_t *passphrase, size_t pplength, uint8_t *salt, uint8_t *out_key, TOX_ERR_KEY_DERIVATION *error); /* This retrieves the salt used to encrypt the given data, which can then be passed to * derive_key_with_salt to produce the same key as was previously used. Any encrpyted * data with this module can be used as input. * - * returns -1 if the magic number is wrong - * returns 0 otherwise (no guarantee about validity of data) + * returns true if magic number matches + * success does not say anything about the validity of the data, only that data of + * the appropriate size was copied */ -int tox_get_salt(uint8_t *data, uint8_t *salt); +bool tox_get_salt(const uint8_t *data, uint8_t *salt); /* Now come the functions that are analogous to the part 2 functions. */ -/* Encrypt arbitrary with a key produced by tox_derive_key_. The output - * array must be at least data_len + tox_pass_encryption_extra_length() bytes long. - * key must be tox_pass_key_length() bytes. +/* Encrypt arbitrary with a key produced by tox_derive_key_*. The output + * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. + * key must be TOX_PASS_KEY_LENGTH bytes. * If you already have a symmetric key from somewhere besides this module, simply * call encrypt_data_symmetric in toxcore/crypto_core directly. * - * returns 0 on success - * returns -1 on failure - */ -int tox_pass_key_encrypt(const uint8_t *data, uint32_t data_len, const uint8_t *key, uint8_t *out); - -/* Save the messenger data encrypted with the given key from tox_derive_key. - * data must be at least tox_encrypted_size(). - * - * NOTE: Unlike tox_save(), this function may fail. Be sure to check its return - * value. - * - * returns 0 on success - * returns -1 on failure + * returns true on success */ -int tox_encrypted_key_save(const Tox *tox, uint8_t *data, uint8_t *key); +bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const uint8_t *key, uint8_t *out, TOX_ERR_ENCRYPTION *error); /* This is the inverse of tox_pass_key_encrypt, also using only keys produced by * tox_derive_key_from_pass. * - * returns the length of the output data (== data_len - tox_pass_encryption_extra_length()) on success - * returns -1 on failure - */ -int tox_pass_key_decrypt(const uint8_t *data, uint32_t length, const uint8_t *key, uint8_t *out); - -/* Load the messenger from encrypted data of size length, with key from tox_derive_key. - * All other arguments are like toxcore/tox_new(). + * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH * - * returns NULL on failure; see the documentation in toxcore/tox.h. + * returns true on success */ -Tox *tox_encrypted_key_new(const struct Tox_Options *options, const uint8_t *data, size_t length, uint8_t *key, - TOX_ERR_ENCRYPTED_NEW *error); - +bool tox_pass_key_decrypt(const uint8_t *data, size_t length, const uint8_t *key, uint8_t *out, TOX_ERR_DECRYPTION *error); /* Determines whether or not the given data is encrypted (by checking the magic number) - * - * returns 1 if it is encrypted - * returns 0 otherwise */ -int tox_is_data_encrypted(const uint8_t *data); +bool tox_is_data_encrypted(const uint8_t *data); #ifdef __cplusplus } -- cgit v1.2.3