diff --git a/auto_tests/encryptsave_test.c b/auto_tests/encryptsave_test.c index 13e06db4..a239bcee 100644 --- a/auto_tests/encryptsave_test.c +++ b/auto_tests/encryptsave_test.c @@ -93,19 +93,19 @@ START_TEST(test_save_friend) 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); + TOX_PASS_KEY key; + memcpy(key.salt, salt, 32); + memcpy(key.key, known_key2, crypto_box_BEFORENMBYTES); size2 = size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH; uint8_t encdata2[size2]; - ret = tox_pass_key_encrypt(data2, size, key, encdata2, &error1); + 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]; 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); + 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"); @@ -130,13 +130,13 @@ START_TEST(test_keys) 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); + TOX_PASS_KEY key; + 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]; - ret = tox_pass_key_encrypt(string, 44, key, encrypted, &encerr); + ret = tox_pass_key_encrypt(string, 44, &key, encrypted, &encerr); ck_assert_msg(ret, "generic failure 2: %u", encerr); uint8_t encrypted2[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH]; @@ -146,12 +146,12 @@ START_TEST(test_keys) uint8_t out1[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH]; uint8_t out2[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH]; - ret = tox_pass_key_decrypt(encrypted, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, key, out1, &decerr); + 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"); 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(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 @@ -161,10 +161,10 @@ START_TEST(test_keys) 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); + TOX_PASS_KEY key2; + 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"); + ck_assert_msg(0 == memcmp(&key, &key2, sizeof(TOX_PASS_KEY)), "salt comparison failed"); } END_TEST diff --git a/toxencryptsave/toxencryptsave.c b/toxencryptsave/toxencryptsave.c index 9b202f49..e2f28a58 100644 --- a/toxencryptsave/toxencryptsave.c +++ b/toxencryptsave/toxencryptsave.c @@ -28,7 +28,6 @@ #include "toxencryptsave.h" #include "defines.h" #include "../toxcore/crypto_core.h" -#include "../toxcore/tox.h" #define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}} #ifdef VANILLA_NACL @@ -41,8 +40,8 @@ #error TOX_PASS_SALT_LENGTH is assumed to be equal to crypto_pwhash_scryptsalsa208sha256_SALTBYTES #endif -#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) +#if TOX_PASS_KEY_LENGTH != crypto_box_KEYBYTES +#error TOX_PASS_KEY_LENGTH is assumed to be equal to crypto_box_KEYBYTES #endif #if TOX_PASS_ENCRYPTION_EXTRA_LENGTH != (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH) @@ -83,7 +82,8 @@ bool tox_get_salt(const uint8_t *data, uint8_t *salt) * * returns true on success */ -bool tox_derive_key_from_pass(uint8_t *passphrase, size_t pplength, uint8_t *out_key, TOX_ERR_KEY_DERIVATION *error) +bool tox_derive_key_from_pass(uint8_t *passphrase, size_t pplength, TOX_PASS_KEY *out_key, + TOX_ERR_KEY_DERIVATION *error) { uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; randombytes(salt, sizeof salt); @@ -91,9 +91,9 @@ bool tox_derive_key_from_pass(uint8_t *passphrase, size_t pplength, uint8_t *out } /* Same as above, except with use the given salt for deterministic key derivation. - * The salt must be tox_salt_length() bytes in length. + * The salt must be TOX_PASS_SALT_LENGTH bytes in length. */ -bool tox_derive_key_with_salt(uint8_t *passphrase, size_t pplength, uint8_t *salt, uint8_t *out_key, +bool tox_derive_key_with_salt(uint8_t *passphrase, size_t pplength, uint8_t *salt, TOX_PASS_KEY *out_key, TOX_ERR_KEY_DERIVATION *error) { if (pplength == 0 || !passphrase || !salt || !out_key) { @@ -120,8 +120,8 @@ bool tox_derive_key_with_salt(uint8_t *passphrase, size_t pplength, uint8_t *sal } 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); + memcpy(out_key->salt, salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); + memcpy(out_key->key, key, crypto_box_KEYBYTES); SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_OK); return 1; } @@ -134,7 +134,7 @@ bool tox_derive_key_with_salt(uint8_t *passphrase, size_t pplength, uint8_t *sal * * returns true on success */ -bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const uint8_t *key, uint8_t *out, +bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const TOX_PASS_KEY *key, uint8_t *out, TOX_ERR_ENCRYPTION *error) { if (data_len == 0 || !data || !key || !out) { @@ -155,8 +155,7 @@ bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const uint8_t *k out += TOX_ENC_SAVE_MAGIC_LENGTH; /* then add the rest prefix */ - memcpy(out, key, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); - key += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; + memcpy(out, key->salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); out += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; uint8_t nonce[crypto_box_NONCEBYTES]; @@ -165,7 +164,7 @@ bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const uint8_t *k out += crypto_box_NONCEBYTES; /* now encrypt */ - if (encrypt_data_symmetric(key, nonce, data, data_len, out) + if (encrypt_data_symmetric(key->key, nonce, data, data_len, out) != data_len + crypto_box_MACBYTES) { SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_FAILED); return 0; @@ -184,10 +183,10 @@ bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const uint8_t *k 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_PASS_KEY key; TOX_ERR_KEY_DERIVATION _error; - if (!tox_derive_key_from_pass(passphrase, pplength, key, &_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) { @@ -197,7 +196,7 @@ bool tox_pass_encrypt(const uint8_t *data, size_t data_len, uint8_t *passphrase, return 0; } - return tox_pass_key_encrypt(data, data_len, key, out, error); + 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 @@ -207,7 +206,7 @@ bool tox_pass_encrypt(const uint8_t *data, size_t data_len, uint8_t *passphrase, * * returns true on success */ -bool tox_pass_key_decrypt(const uint8_t *data, size_t length, const uint8_t *key, uint8_t *out, +bool tox_pass_key_decrypt(const uint8_t *data, size_t length, const TOX_PASS_KEY *key, uint8_t *out, TOX_ERR_DECRYPTION *error) { if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) { @@ -215,25 +214,27 @@ bool tox_pass_key_decrypt(const uint8_t *data, size_t length, const uint8_t *key return 0; } + if (!data || !key || !out) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_NULL); + 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; + data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; // salt only affects key derivation size_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; - //uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; - uint8_t nonce[crypto_box_NONCEBYTES]; - //memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); - key += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; // ignore the salt, which is only needed for kdf - data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; + uint8_t nonce[crypto_box_NONCEBYTES]; memcpy(nonce, data, crypto_box_NONCEBYTES); data += crypto_box_NONCEBYTES; /* decrypt the data */ - if (decrypt_data_symmetric(key, nonce, data, decrypt_length + crypto_box_MACBYTES, out) + if (decrypt_data_symmetric(key->key, nonce, data, decrypt_length + crypto_box_MACBYTES, out) != decrypt_length) { SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_FAILED); return 0; @@ -254,33 +255,34 @@ bool tox_pass_key_decrypt(const uint8_t *data, size_t length, const uint8_t *key 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 (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH || pplength == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH); + return 0; + } + + if (!data || !passphrase || !out) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_NULL); + 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; } - uint8_t passkey[crypto_hash_sha256_BYTES]; - crypto_hash_sha256(passkey, passphrase, pplength); - uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; memcpy(salt, data + TOX_ENC_SAVE_MAGIC_LENGTH, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); /* derive the key */ - uint8_t key[crypto_box_KEYBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; + TOX_PASS_KEY key; - if (crypto_pwhash_scryptsalsa208sha256( - key + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, - crypto_box_KEYBYTES, (char *)passkey, sizeof(passkey), salt, - crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ - crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { + if (!tox_derive_key_with_salt(passphrase, pplength, salt, &key, NULL)) { /* out of memory most likely */ 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, 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) diff --git a/toxencryptsave/toxencryptsave.h b/toxencryptsave/toxencryptsave.h index 2ee4af46..c077d899 100644 --- a/toxencryptsave/toxencryptsave.h +++ b/toxencryptsave/toxencryptsave.h @@ -39,7 +39,7 @@ struct Tox_Options; #endif #define TOX_PASS_SALT_LENGTH 32 -#define TOX_PASS_KEY_LENGTH 64 +#define TOX_PASS_KEY_LENGTH 32 #define TOX_PASS_ENCRYPTION_EXTRA_LENGTH 80 /* This module is conceptually organized into two parts. The first part are the functions @@ -60,6 +60,15 @@ struct Tox_Options; * Ditto if they forget their password, there is no way to recover the data. */ +/* Since apparently no one actually bothered to learn about the module previously, + * the recently removed functions tox_encrypted_new and tox_get_encrypted_savedata + * may be trivially replaced by calls to tox_pass_decrypt -> tox_new or + * tox_get_savedata -> tox_pass_encrypt as appropriate. The removed functions + * were never more than 5 line wrappers of the other public API functions anyways. + * (As has always been, tox_pass_decrypt and tox_pass_encrypt are interchangeable + * with tox_pass_key_decrypt and tox_pass_key_encrypt, as the client program requires.) + */ + typedef enum TOX_ERR_KEY_DERIVATION { TOX_ERR_KEY_DERIVATION_OK, /** @@ -155,6 +164,14 @@ bool tox_pass_decrypt(const uint8_t *data, size_t length, uint8_t *passphrase, s * intensive than part one. The first 3 functions are for key handling. */ +/* This key structure's internals should not be used by any client program, even + * if they are straightforward here. + */ +typedef struct { + uint8_t salt[TOX_PASS_SALT_LENGTH]; + uint8_t key[TOX_PASS_KEY_LENGTH]; +} TOX_PASS_KEY; + /* 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. @@ -166,12 +183,13 @@ bool tox_pass_decrypt(const uint8_t *data, size_t length, uint8_t *passphrase, s * * returns true on success */ -bool tox_derive_key_from_pass(uint8_t *passphrase, size_t pplength, uint8_t *out_key, TOX_ERR_KEY_DERIVATION *error); +bool tox_derive_key_from_pass(uint8_t *passphrase, size_t pplength, TOX_PASS_KEY *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. +/* Same as above, except use the given salt for deterministic key derivation. + * The salt must be TOX_PASS_SALT_LENGTH bytes in length. */ -bool tox_derive_key_with_salt(uint8_t *passphrase, size_t pplength, uint8_t *salt, uint8_t *out_key, +bool tox_derive_key_with_salt(uint8_t *passphrase, size_t pplength, uint8_t *salt, TOX_PASS_KEY *out_key, TOX_ERR_KEY_DERIVATION *error); /* This retrieves the salt used to encrypt the given data, which can then be passed to @@ -194,7 +212,7 @@ bool tox_get_salt(const uint8_t *data, uint8_t *salt); * * returns true on success */ -bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const uint8_t *key, uint8_t *out, +bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const TOX_PASS_KEY *key, uint8_t *out, TOX_ERR_ENCRYPTION *error); /* This is the inverse of tox_pass_key_encrypt, also using only keys produced by @@ -204,7 +222,7 @@ bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const uint8_t *k * * returns true on success */ -bool tox_pass_key_decrypt(const uint8_t *data, size_t length, const uint8_t *key, uint8_t *out, +bool tox_pass_key_decrypt(const uint8_t *data, size_t length, const TOX_PASS_KEY *key, uint8_t *out, TOX_ERR_DECRYPTION *error); /* Determines whether or not the given data is encrypted (by checking the magic number)