Пример #1
0
int save_data(Tox *m, const char *path)
{
    if (path == NULL)
        goto on_error;

    FILE *fp = fopen(path, "wb");

    if (fp == NULL)
        return -1;

    size_t data_len = tox_get_savedata_size(m);
    char *data = malloc(data_len);

    if (data == NULL)
        goto on_error;

    tox_get_savedata(m, (uint8_t *) data);

    if (fwrite(data, data_len, 1, fp) != 1) {
        free(data);
        fclose(fp);
        goto on_error;
    }

    free(data);
    fclose(fp);
    return 0;

on_error:
    fprintf(stderr, "Warning: save_data failed\n");
    return -1;
}
Пример #2
0
/**
 * @brief Returns the unencrypted tox save data
 */
QByteArray Core::getToxSaveData()
{
    uint32_t fileSize = tox_get_savedata_size(tox);
    QByteArray data;
    data.resize(fileSize);
    tox_get_savedata(tox, (uint8_t*)data.data());
    return data;
}
Пример #3
0
static void r2tox_save() {
	struct Tor *t = tox;
	int sz = tox_get_savedata_size (t);
	uint8_t *buf = (uint8_t *)calloc (sz, 1);
	tox_get_savedata (t, buf);
	printf ("Saving tox.data %d\n", sz);
	FILE *fd = fopen("tox.data", "w");
	fwrite(buf, sz, 1, fd);
	fclose(fd);
}
Пример #4
0
void Tox_Dispatcher::save_save_data()
{
    std::string sdf = Platform::get_instance()->get_save_data_file();
    std::ofstream os;
    os.open(sdf, std::ios::out | std::ios::binary);
    if (os.good()) {
        LOG(INFO) << "Saving tox data";
        const size_t len = tox_get_savedata_size(tox);
        std::vector<uint8_t> save_data(len, 0);
        tox_get_savedata(tox, save_data.data());
        os.write((char *) save_data.data(), len);
    }
    os.close();
}
Пример #5
0
int store_data(Tox *m, const char *path)
{
    if (path == NULL)
        return -1;

    FILE *fp = fopen(TEMP_PROFILE_SAVE_NAME, "wb");

    if (fp == NULL)
        return -1;

    size_t data_len = tox_get_savedata_size(m);
    char data[data_len];

    tox_get_savedata(m, (uint8_t *) data);

    if (user_password.data_is_encrypted && !arg_opts.unencrypt_data) {
        size_t enc_len = data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
        char enc_data[enc_len];

        TOX_ERR_ENCRYPTION err;
        tox_pass_encrypt((uint8_t *) data, data_len, (uint8_t *) user_password.pass, user_password.len,
                         (uint8_t *) enc_data, &err);

        if (err != TOX_ERR_ENCRYPTION_OK) {
            fprintf(stderr, "tox_pass_encrypt() failed with error %d\n", err);
            fclose(fp);
            return -1;
        }

        if (fwrite(enc_data, enc_len, 1, fp) != 1) {
            fclose(fp);
            return -1;
        }
    } else {  /* data will not be encrypted */
        if (fwrite(data, data_len, 1, fp) != 1) {
            fclose(fp);
            return -1;
        }
    }

    fclose(fp);

    if (rename(TEMP_PROFILE_SAVE_NAME, path) != 0)
        return -1;

    return 0;
}
Пример #6
0
/* Save tox identity to a file */
static void write_save(Tox *tox)
{
    void *data;
    uint32_t size;
    uint8_t path_tmp[512], path_real[512], *p;
    FILE *file;

    size = tox_get_savedata_size(tox);
    data = malloc(size);
    tox_get_savedata(tox, data);

    strncpy(path_real, config_path, sizeof(config_path));

    p = path_real + strlen(path_real);
    memcpy(p, "tox_save", sizeof("tox_save"));

    unsigned int path_len = (p - path_real) + sizeof("tox_save");
    memcpy(path_tmp, path_real, path_len);
    memcpy(path_tmp + (path_len - 1), ".tmp", sizeof(".tmp"));

    file = fopen((char*)path_tmp, "wb");
    if(file) {
        fwrite(data, size, 1, file);
        fflush(file);
        fclose(file);
        if (rename((char*)path_tmp, (char*)path_real) != 0) {
            log_printf(L_WARNING, "Failed to rename file. %s to %s deleting and trying again\n", path_tmp, path_real);
            if(remove((const char *)path_real) < 0) {
                log_printf(L_WARNING, "Failed to remove old save file %s\n", path_real);
            }
            if (rename((char*)path_tmp, (char*)path_real) != 0) {
                log_printf(L_WARNING, "Saving Failed\n");
            } else {
                log_printf(L_DEBUG, "Saved data\n");
            }
        } else {
            log_printf(L_DEBUG, "Saved data\n");
        }
    }
    else
    {
        log_printf(L_WARNING, "Could not open save file\n");
    }

    free(data);
}
Пример #7
0
void CToxProto::SaveToxProfile(CToxThread *toxThread)
{
	mir_cslock locker(profileLock);

	if (!toxThread)
		return;

	size_t size = tox_get_savedata_size(toxThread->Tox());
	uint8_t *data = (uint8_t*)mir_calloc(size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH);
	tox_get_savedata(toxThread->Tox(), data);

	pass_ptrA password(mir_utf8encodeW(pass_ptrT(getTStringA("Password"))));
	if (password && mir_strlen(password))
	{
		TOX_ERR_ENCRYPTION coreEncryptError;
		if (!tox_pass_encrypt(data, size, (uint8_t*)(char*)password, mir_strlen(password), data, &coreEncryptError))
		{
			debugLogA(__FUNCTION__": failed to encrypt tox profile");
			mir_free(data);
			return;
		}
		size += TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
	}

	ptrT profilePath(GetToxProfilePath());
	FILE *profile = _tfopen(profilePath, _T("wb"));
	if (profile == NULL)
	{
		debugLogA(__FUNCTION__": failed to open tox profile");
		mir_free(data);
		return;
	}

	size_t written = fwrite(data, sizeof(char), size, profile);
	if (size != written)
	{
		debugLogA(__FUNCTION__": failed to write tox profile");
	}

	fclose(profile);
	mir_free(data);
}
Пример #8
0
void CToxProto::SaveToxProfile()
{
	mir_cslock locker(profileLock);

	size_t size = tox_get_savedata_size(tox);
	uint8_t *data = (uint8_t*)mir_calloc(size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH);
	tox_get_savedata(tox, data);

	size_t passwordLen = mir_strlen(password);
	if (password && passwordLen)
	{
		TOX_ERR_ENCRYPTION coreEncryptError;
		if (!tox_pass_encrypt(data, size, (uint8_t*)password, passwordLen, data, &coreEncryptError))
		{
			debugLogA(__FUNCTION__": failed to encrypt tox profile");
			mir_free(data);
			return;
		}
		size += TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
	}

	std::tstring profilePath = GetToxProfilePath();
	FILE *profile = _tfopen(profilePath.c_str(), _T("wb"));
	if (profile == NULL)
	{
		debugLogA(__FUNCTION__": failed to open tox profile");
		mir_free(data);
		return;
	}

	size_t written = fwrite(data, sizeof(char), size, profile);
	if (size != written)
	{
		debugLogA(__FUNCTION__": failed to write tox profile");
	}

	fclose(profile);
	mir_free(data);
}
Пример #9
0
void Core::saveConfiguration(const QString& path)
{
    if (QThread::currentThread() != coreThread)
        return (void) QMetaObject::invokeMethod(this, "saveConfiguration", Q_ARG(const QString&, path));

    if (!isReady())
    {
        qWarning() << "saveConfiguration: Tox not started, aborting!";
        return;
    }

    QSaveFile configurationFile(path);
    if (!configurationFile.open(QIODevice::WriteOnly))
    {
        qCritical() << "File " << path << " cannot be opened";
        return;
    }

    qDebug() << "writing tox_save to " << path;

    uint32_t fileSize = tox_get_savedata_size(tox);
    bool encrypt = Settings::getInstance().getEncryptTox();

    if (fileSize > 0 && fileSize <= std::numeric_limits<int32_t>::max())
    {
        uint8_t *data = new uint8_t[fileSize];

        if (encrypt)
        {
            if (!pwsaltedkeys[ptMain])
            {
                // probably zero chance event
                GUI::showWarning(tr("NO Password"), tr("Local file encryption is enabled, but there is no password! It will be disabled."));
                Settings::getInstance().setEncryptTox(false);
                tox_get_savedata(tox, data);
            }
            else
            {
                tox_get_savedata(tox, data);
                uint8_t* newData = new uint8_t[fileSize+TOX_PASS_ENCRYPTION_EXTRA_LENGTH];
                if (tox_pass_key_encrypt(data, fileSize, pwsaltedkeys[ptMain], newData, nullptr))
                {
                    delete[] data;
                    data = newData;
                    fileSize+=TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
                }
                else
                {
                    delete[] newData;
                    delete[] data;
                    qCritical() << "Core::saveConfiguration(QString): Encryption failed, couldn't save";
                    configurationFile.cancelWriting();
                    return;
                }
            }
        }
        else
        {
            tox_get_savedata(tox, data);
        }

        configurationFile.write(reinterpret_cast<char *>(data), fileSize);
        configurationFile.commit();
        delete[] data;
    }

    Settings::getInstance().save();
}
Пример #10
0
static void test_one(void)
{
    uint8_t name[TOX_MAX_NAME_LENGTH];
    uint8_t status_message[TOX_MAX_STATUS_MESSAGE_LENGTH];

    uint8_t name2[TOX_MAX_NAME_LENGTH];
    uint8_t status_message2[TOX_MAX_STATUS_MESSAGE_LENGTH];

    uint32_t index[] = { 1, 2 };
    Tox *tox1 = tox_new_log(nullptr, nullptr, &index[0]);
    set_random_name_and_status_message(tox1, name, status_message);
    Tox *tox2 = tox_new_log(nullptr, nullptr, &index[1]);
    set_random_name_and_status_message(tox2, name2, status_message2);

    uint8_t address[TOX_ADDRESS_SIZE];
    tox_self_get_address(tox1, address);
    Tox_Err_Friend_Add error;
    uint32_t ret = tox_friend_add(tox1, address, (const uint8_t *)"m", 1, &error);
    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_OWN_KEY, "Adding own address worked.");

    tox_self_get_address(tox2, address);
    uint8_t message[TOX_MAX_FRIEND_REQUEST_LENGTH + 1];
    ret = tox_friend_add(tox1, address, nullptr, 0, &error);
    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_NULL, "Sending request with no message worked.");
    ret = tox_friend_add(tox1, address, message, 0, &error);
    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_NO_MESSAGE, "Sending request with no message worked.");
    ret = tox_friend_add(tox1, address, message, sizeof(message), &error);
    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_TOO_LONG,
                  "TOX_MAX_FRIEND_REQUEST_LENGTH is too big.");

    address[0]++;
    ret = tox_friend_add(tox1, address, (const uint8_t *)"m", 1, &error);
    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_BAD_CHECKSUM,
                  "Adding address with bad checksum worked.");

    tox_self_get_address(tox2, address);
    ret = tox_friend_add(tox1, address, message, TOX_MAX_FRIEND_REQUEST_LENGTH, &error);
    ck_assert_msg(ret == 0 && error == TOX_ERR_FRIEND_ADD_OK, "Failed to add friend.");
    ret = tox_friend_add(tox1, address, message, TOX_MAX_FRIEND_REQUEST_LENGTH, &error);
    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_ALREADY_SENT, "Adding friend twice worked.");

    tox_self_set_name(tox1, name, sizeof(name), nullptr);
    ck_assert_msg(tox_self_get_name_size(tox1) == sizeof(name), "Can't set name of TOX_MAX_NAME_LENGTH");

    tox_self_set_status_message(tox1, status_message, sizeof(status_message), nullptr);
    ck_assert_msg(tox_self_get_status_message_size(tox1) == sizeof(status_message),
                  "Can't set status message of TOX_MAX_STATUS_MESSAGE_LENGTH");

    tox_self_get_address(tox1, address);
    size_t save_size = tox_get_savedata_size(tox1);
    VLA(uint8_t, data, save_size);
    tox_get_savedata(tox1, data);

    tox_kill(tox2);
    Tox_Err_New err_n;

    struct Tox_Options *options = tox_options_new(nullptr);
    tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
    tox_options_set_savedata_data(options, data, save_size);
    tox2 = tox_new_log(options, &err_n, &index[1]);
    ck_assert_msg(err_n == TOX_ERR_NEW_OK, "Load failed");

    ck_assert_msg(tox_self_get_name_size(tox2) == sizeof name, "Wrong name size.");
    ck_assert_msg(tox_self_get_status_message_size(tox2) == sizeof status_message, "Wrong status message size");

    uint8_t name_loaded[TOX_MAX_NAME_LENGTH] = { 0 };
    tox_self_get_name(tox2, name_loaded);
    ck_assert_msg(!memcmp(name, name_loaded, sizeof name), "Wrong name.");

    uint8_t status_message_loaded[TOX_MAX_STATUS_MESSAGE_LENGTH] = { 0 };
    tox_self_get_status_message(tox2, status_message_loaded);
    ck_assert_msg(!memcmp(status_message, status_message_loaded, sizeof status_message_loaded), "Wrong status message.");

    uint8_t address2[TOX_ADDRESS_SIZE] = { 0 };
    tox_self_get_address(tox2, address2);
    ck_assert_msg(memcmp(address2, address, TOX_ADDRESS_SIZE) == 0, "Wrong address.");
    uint8_t new_name[TOX_MAX_NAME_LENGTH] = { 0 };
    tox_self_get_name(tox2, new_name);
    ck_assert_msg(memcmp(name, new_name, TOX_MAX_NAME_LENGTH) == 0, "Wrong name");

    uint8_t sk[TOX_SECRET_KEY_SIZE];
    tox_self_get_secret_key(tox2, sk);
    tox_kill(tox2);

    tox_options_default(options);
    tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_SECRET_KEY);
    tox_options_set_savedata_data(options, sk, sizeof(sk));
    tox2 = tox_new_log(options, &err_n, &index[1]);
    ck_assert_msg(err_n == TOX_ERR_NEW_OK, "Load failed");
    uint8_t address3[TOX_ADDRESS_SIZE];
    tox_self_get_address(tox2, address3);
    ck_assert_msg(memcmp(address3, address, TOX_PUBLIC_KEY_SIZE) == 0, "Wrong public key.");
    uint8_t pk[TOX_PUBLIC_KEY_SIZE];
    tox_self_get_public_key(tox2, pk);
    ck_assert_msg(memcmp(pk, address, TOX_PUBLIC_KEY_SIZE) == 0, "Wrong public key.");

    tox_options_free(options);
    tox_kill(tox1);
    tox_kill(tox2);
}
Пример #11
0
int main(void)
{
    setvbuf(stdout, nullptr, _IONBF, 0);

    Tox *const tox1 = tox_new_log(nullptr, nullptr, nullptr);
    Tox *const tox2 = tox_new_log(nullptr, nullptr, nullptr);

    printf("bootstrapping tox2 off tox1\n");
    uint8_t dht_key[TOX_PUBLIC_KEY_SIZE];
    tox_self_get_dht_id(tox1, dht_key);
    const uint16_t dht_port = tox_self_get_udp_port(tox1, nullptr);

    tox_bootstrap(tox2, "localhost", dht_port, dht_key, nullptr);

    struct test_data to_compare = {{0}};

    uint8_t public_key[TOX_PUBLIC_KEY_SIZE];
    tox_self_get_public_key(tox1, public_key);
    tox_friend_add_norequest(tox2, public_key, nullptr);
    tox_self_get_public_key(tox2, public_key);
    tox_friend_add_norequest(tox1, public_key, nullptr);

    uint8_t reference_name[TOX_MAX_NAME_LENGTH] = { 0 };
    uint8_t reference_status[TOX_MAX_STATUS_MESSAGE_LENGTH] = { 0 };

    set_random(tox1, tox_self_set_name, TOX_MAX_NAME_LENGTH);
    set_random(tox2, tox_self_set_name, TOX_MAX_NAME_LENGTH);
    set_random(tox1, tox_self_set_status_message, TOX_MAX_STATUS_MESSAGE_LENGTH);
    set_random(tox2, tox_self_set_status_message, TOX_MAX_STATUS_MESSAGE_LENGTH);

    tox_self_get_name(tox2, reference_name);
    tox_self_get_status_message(tox2, reference_status);

    tox_callback_friend_name(tox1, namechange_callback);
    tox_callback_friend_status_message(tox1, statuschange_callback);

    while (true) {
        if (tox_self_get_connection_status(tox1) &&
                tox_self_get_connection_status(tox2) &&
                tox_friend_get_connection_status(tox1, 0, nullptr) == TOX_CONNECTION_UDP) {
            printf("Connected.\n");
            break;
        }

        tox_iterate(tox1, &to_compare);
        tox_iterate(tox2, nullptr);

        c_sleep(tox_iteration_interval(tox1));
    }

    while (true) {
        if (to_compare.received_name && to_compare.received_status_message) {
            printf("Exchanged names and status messages.\n");
            break;
        }

        tox_iterate(tox1, &to_compare);
        tox_iterate(tox2, nullptr);

        c_sleep(tox_iteration_interval(tox1));
    }

    size_t save_size = tox_get_savedata_size(tox1);
    VLA(uint8_t, savedata, save_size);
    tox_get_savedata(tox1, savedata);

    struct Tox_Options *const options = tox_options_new(nullptr);
    tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
    tox_options_set_savedata_data(options, savedata, save_size);

    Tox *const tox_to_compare = tox_new_log(options, nullptr, nullptr);

    tox_friend_get_name(tox_to_compare, 0, to_compare.name, nullptr);
    tox_friend_get_status_message(tox_to_compare, 0, to_compare.status_message, nullptr);

    ck_assert_msg(memcmp(reference_name, to_compare.name, TOX_MAX_NAME_LENGTH) == 0,
                  "incorrect name: should be all zeroes");
    ck_assert_msg(memcmp(reference_status, to_compare.status_message, TOX_MAX_STATUS_MESSAGE_LENGTH) == 0,
                  "incorrect status message: should be all zeroes");

    tox_options_free(options);
    tox_kill(tox1);
    tox_kill(tox2);
    tox_kill(tox_to_compare);

    return 0;
}
Пример #12
0
int store_data(Tox *m, const char *path)
{
    if (path == NULL) {
        return -1;
    }

    char temp_path[strlen(path) + strlen(TEMP_PROFILE_EXT) + 1];
    snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_PROFILE_EXT);

    FILE *fp = fopen(temp_path, "wb");

    if (fp == NULL) {
        return -1;
    }

    size_t data_len = tox_get_savedata_size(m);
    char *data = malloc(data_len * sizeof(char));

    if (data == NULL) {
        fclose(fp);
        return -1;
    }

    tox_get_savedata(m, (uint8_t *) data);

    if (user_password.data_is_encrypted && !arg_opts.unencrypt_data) {
        size_t enc_len = data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
        char *enc_data = malloc(enc_len * sizeof(char));

        if (enc_data == NULL) {
            fclose(fp);
            free(data);
            return -1;
        }

        TOX_ERR_ENCRYPTION err;
        tox_pass_encrypt((uint8_t *) data, data_len, (uint8_t *) user_password.pass, user_password.len,
                         (uint8_t *) enc_data, &err);

        if (err != TOX_ERR_ENCRYPTION_OK) {
            fprintf(stderr, "tox_pass_encrypt() failed with error %d\n", err);
            fclose(fp);
            free(data);
            free(enc_data);
            return -1;
        }

        if (fwrite(enc_data, enc_len, 1, fp) != 1) {
            fprintf(stderr, "Failed to write profile data.\n");
            fclose(fp);
            free(data);
            free(enc_data);
            return -1;
        }

        free(enc_data);
    } else {  /* data will not be encrypted */
        if (fwrite(data, data_len, 1, fp) != 1) {
            fprintf(stderr, "Failed to write profile data.\n");
            fclose(fp);
            free(data);
            return -1;
        }
    }

    fclose(fp);
    free(data);

    if (rename(temp_path, path) != 0) {
        return -1;
    }

    return 0;
}
Пример #13
0
int main(int argc, char *argv[])
{
    Tox *tox1 = tox_new_log(0, 0, 0);
    Tox *tox2 = tox_new_log(0, 0, 0);

    struct test_data to_compare = { { 0 } };

    uint8_t public_key[TOX_PUBLIC_KEY_SIZE];
    tox_self_get_public_key(tox1, public_key);
    tox_friend_add_norequest(tox2, public_key, NULL);
    tox_self_get_public_key(tox2, public_key);
    tox_friend_add_norequest(tox1, public_key, NULL);

    uint8_t reference_name[TOX_MAX_NAME_LENGTH] = { 0 };
    uint8_t reference_status[TOX_MAX_STATUS_MESSAGE_LENGTH] = { 0 };

    set_random(tox1, tox_self_set_name, TOX_MAX_NAME_LENGTH);
    set_random(tox2, tox_self_set_name, TOX_MAX_NAME_LENGTH);
    set_random(tox1, tox_self_set_status_message, TOX_MAX_STATUS_MESSAGE_LENGTH);
    set_random(tox2, tox_self_set_status_message, TOX_MAX_STATUS_MESSAGE_LENGTH);

    tox_self_get_name(tox2, reference_name);
    tox_self_get_status_message(tox2, reference_status);

    tox_callback_friend_name(tox1, namechange_callback);
    tox_callback_friend_status_message(tox1, statuschange_callback);

    while (true) {
        if (tox_self_get_connection_status(tox1) &&
                tox_self_get_connection_status(tox2) &&
                tox_friend_get_connection_status(tox1, 0, 0) == TOX_CONNECTION_UDP) {
            printf("Connected.\n");
            break;
        }

        tox_iterate(tox1, &to_compare);
        tox_iterate(tox2, NULL);

        c_sleep(tox_iteration_interval(tox1));
    }

    while (true) {
        if (to_compare.received_name && to_compare.received_status_message) {
            printf("Exchanged names and status messages.\n");
            break;
        }

        tox_iterate(tox1, &to_compare);
        tox_iterate(tox2, NULL);

        c_sleep(tox_iteration_interval(tox1));
    }

    size_t save_size = tox_get_savedata_size(tox1);
    VLA(uint8_t, savedata, save_size);
    tox_get_savedata(tox1, savedata);

    struct Tox_Options *options = tox_options_new(NULL);
    tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
    tox_options_set_savedata_data(options, savedata, save_size);

    Tox *tox_to_compare = tox_new(options, 0);

    tox_friend_get_name(tox_to_compare, 0, to_compare.name, 0);
    tox_friend_get_status_message(tox_to_compare, 0, to_compare.status_message, 0);

    assert(memcmp(reference_name, to_compare.name, TOX_MAX_NAME_LENGTH) == 0);
    assert(memcmp(reference_status, to_compare.status_message, TOX_MAX_STATUS_MESSAGE_LENGTH) == 0);

    tox_options_free(options);
    tox_kill(tox1);
    tox_kill(tox2);
    tox_kill(tox_to_compare);

    return 0;
}
Пример #14
0
END_TEST

START_TEST(test_save_friend)
{
    Tox *tox1 = tox_new(0, 0);
    Tox *tox2 = tox_new(0, 0);
    ck_assert_msg(tox1 || tox2, "Failed to create 2 tox instances");
    uint32_t to_compare = 974536;
    tox_callback_friend_request(tox2, accept_friend_request, &to_compare);
    uint8_t address[TOX_ADDRESS_SIZE];
    tox_self_get_address(tox2, address);
    uint32_t test = tox_friend_add(tox1, address, (uint8_t *)"Gentoo", 7, 0);
    ck_assert_msg(test != UINT32_MAX, "Failed to add friend");

    size_t size = tox_get_savedata_size(tox1);
    uint8_t data[size];
    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");

    struct Tox_Options options;
    tox_options_default(&options);
    options.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
    options.savedata_data = enc_data;
    options.savedata_length = size2;

    TOX_ERR_NEW err2;
    Tox *tox3 = tox_new(&options, &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);
    options.savedata_data = dec_data;
    options.savedata_length = size;
    tox3 = tox_new(&options, &err2);
    ck_assert_msg(err2 == TOX_ERR_NEW_OK, "failed to load from decrypted data: %u", err2);
    uint8_t address2[TOX_PUBLIC_KEY_SIZE];
    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_get_savedata_size(tox3);
    uint8_t data2[size];
    tox_get_savedata(tox3, data2);
    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);
    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);
    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)
    options.savedata_data = out1;
    options.savedata_length = size;
    Tox *tox4 = tox_new(&options, &err2);
    ck_assert_msg(err2 == TOX_ERR_NEW_OK, "failed to new the third");
    uint8_t address5[TOX_PUBLIC_KEY_SIZE];
    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);
}