Example #1
0
END_TEST

START_TEST(test_save_friend)
{
    Tox *tox1 = tox_new(0);
    Tox *tox2 = tox_new(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_FRIEND_ADDRESS_SIZE];
    tox_get_address(tox2, address);
    int test = tox_add_friend(tox1, address, (uint8_t *)"Gentoo", 7);
    ck_assert_msg(test == 0, "Failed to add friend error code: %i", test);
    uint32_t size = tox_encrypted_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_data_encrypted(data) == 1, "magic number missing");
    Tox *tox3 = tox_new(0);
    test = tox_encrypted_load(tox3, data, size, "correcthorsebatterystaple", 25);
    ck_assert_msg(test == 0, "failed to encrypted load");
    uint8_t address2[TOX_CLIENT_ID_SIZE];
    test = tox_get_client_id(tox3, 0, address2);
    ck_assert_msg(test == 0, "no friends!");
    ck_assert_msg(memcmp(address, address2, TOX_CLIENT_ID_SIZE) == 0, "addresses don't match!");
}
Example #2
0
QByteArray Profile::loadToxSave()
{
    assert(!isRemoved);

    /// TODO: Cache the data, invalidate it only when we save
    QByteArray data;

    QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox";
    QFile saveFile(path);
    qint64 fileSize;
    qDebug() << "Loading tox save "<<path;

    if (!saveFile.exists())
    {
        qWarning() << "The tox save file "<<path<<" was not found";
        goto fail;
    }

    if (!saveFile.open(QIODevice::ReadOnly))
    {
        qCritical() << "The tox save file " << path << " couldn't' be opened";
        goto fail;
    }

    fileSize = saveFile.size();
    if (fileSize <= 0)
    {
        qWarning() << "The tox save file"<<path<<" is empty!";
        goto fail;
    }

    data = saveFile.readAll();
    if (tox_is_data_encrypted((uint8_t*)data.data()))
    {
        if (password.isEmpty())
        {
            qCritical() << "The tox save file is encrypted, but we don't have a password!";
            data.clear();
            goto fail;
        }

        uint8_t salt[TOX_PASS_SALT_LENGTH];
        tox_get_salt(reinterpret_cast<uint8_t *>(data.data()), salt);
        passkey = *core->createPasskey(password, salt);

        data = core->decryptData(data, passkey);
        if (data.isEmpty())
            qCritical() << "Failed to decrypt the tox save file";
    }
    else
    {
        if (!password.isEmpty())
            qWarning() << "We have a password, but the tox save file is not encrypted";
    }

fail:
    saveFile.close();
    return data;
}
Example #3
0
/**
@brief Checks if the file is serialized settings.
@param filePath Path to file to check.
@return False on error, true otherwise.
*/
bool SettingsSerializer::isSerializedFormat(QString filePath)
{
    QFile f(filePath);
    if (!f.open(QIODevice::ReadOnly))
        return false;
    char fmagic[8];
    if (f.read(fmagic, sizeof(fmagic)) != sizeof(fmagic))
        return false;
    return !memcmp(fmagic, magic, 4) || tox_is_data_encrypted(reinterpret_cast<uint8_t*>(fmagic));
}
Example #4
0
bool Profile::isEncrypted(QString name)
{
    uint8_t data[encryptHeaderSize] = {0};
    QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox";
    QFile saveFile(path);
    if (!saveFile.open(QIODevice::ReadOnly))
    {
        qWarning() << "Couldn't open tox save "<<path;
        return false;
    }

    saveFile.read((char*)data, encryptHeaderSize);
    saveFile.close();

    return tox_is_data_encrypted(data);
}
Example #5
0
void SettingsSerializer::readSerialized()
{
    QFile f(path);
    if (!f.open(QIODevice::ReadOnly))
    {
        qWarning() << "Couldn't open file";
        return;
    }
    QByteArray data = f.readAll();
    f.close();

    // Decrypt
    if (tox_is_data_encrypted(reinterpret_cast<uint8_t*>(data.data())))
    {
        if (password.isEmpty())
        {
            qCritical() << "The settings file is encrypted, but we don't have a password!";
            return;
        }

        Core* core = Nexus::getCore();

        uint8_t salt[TOX_PASS_SALT_LENGTH];
        tox_get_salt(reinterpret_cast<uint8_t *>(data.data()), salt);
        auto passkey = core->createPasskey(password, salt);

        data = core->decryptData(data, *passkey);
        if (data.isEmpty())
        {
            qCritical() << "Failed to decrypt the settings file";
            return;
        }
    }
    else
    {
        if (!password.isEmpty())
            qWarning() << "We have a password, but the settings file is not encrypted";
    }

    if (memcmp(data.data(), magic, 4))
    {
        qWarning() << "Bad magic!";
        return;
    }
    data = data.mid(4);

    QDataStream stream(&data, QIODevice::ReadOnly);
    stream.setVersion(QDataStream::Qt_5_0);

    while (!stream.atEnd())
    {
        RecordTag tag;
        readStream(stream, tag);
        if (tag == RecordTag::Value)
        {
            QByteArray key;
            QByteArray value;
            readStream(stream, key);
            readStream(stream, value);
            setValue(QString::fromUtf8(key), QVariant(QString::fromUtf8(value)));
        }
        else if (tag == RecordTag::GroupStart)
        {
            QByteArray prefix;
            readStream(stream, prefix);
            beginGroup(QString::fromUtf8(prefix));
        }
        else if (tag == RecordTag::ArrayStart)
        {
            QByteArray prefix;
            readStream(stream, prefix);
            beginReadArray(QString::fromUtf8(prefix));
            QByteArray sizeData;
            readStream(stream, sizeData);
            if (sizeData.isEmpty())
            {
                qWarning("The personal save file is corrupted!");
                return;
            }
            int size = dataToVInt(sizeData);
            arrays[array].size = qMax(size, arrays[array].size);
        }
        else if (tag == RecordTag::ArrayValue)
        {
            QByteArray indexData;
            readStream(stream, indexData);
            if (indexData.isEmpty())
            {
                qWarning("The personal save file is corrupted!");
                return;
            }
            setArrayIndex(dataToVInt(indexData));
            QByteArray key;
            QByteArray value;
            readStream(stream, key);
            readStream(stream, value);
            setValue(QString::fromUtf8(key), QVariant(QString::fromUtf8(value)));
        }
        else if (tag == RecordTag::ArrayEnd)
        {
            endArray();
        }
    }

    group = array = -1;
}
Example #6
0
bool CToxProto::LoadToxProfile(Tox_Options *options)
{
	debugLogA(__FUNCTION__": loading tox profile");

	mir_cslock locker(profileLock);
	
	ptrT profilePath(GetToxProfilePath());
	if (!IsFileExists(profilePath))
		return false;

	FILE *profile = _tfopen(profilePath, _T("rb"));
	if (profile == NULL)
	{
		ShowNotification(TranslateT("Unable to open Tox profile"), MB_ICONERROR);
		debugLogA(__FUNCTION__": failed to open tox profile");
		return false;
	}

	fseek(profile, 0, SEEK_END);
	long size = ftell(profile);
	rewind(profile);
	if (size < 0)
	{
		fclose(profile);
		return false;
	}
	
	if (size == 0)
	{
		fclose(profile);
		return true;
	}

	uint8_t *data = (uint8_t*)mir_calloc(size);
	if (fread((char*)data, sizeof(char), size, profile) != (size_t)size)
	{
		fclose(profile);
		ShowNotification(TranslateT("Unable to read Tox profile"), MB_ICONERROR);
		debugLogA(__FUNCTION__": failed to read tox profile");
		mir_free(data);
		return false;
	}
	fclose(profile);

	if (tox_is_data_encrypted(data))
	{
		pass_ptrA password(mir_utf8encodeW(pass_ptrT(getTStringA("Password"))));
		if (password == NULL || mir_strlen(password) == 0)
		{
			CToxPasswordEditor passwordEditor(this);
			if (!passwordEditor.DoModal())
			{
				mir_free(data);
				return false;
			}
		}
		uint8_t *encryptedData = (uint8_t*)mir_calloc(size - TOX_PASS_ENCRYPTION_EXTRA_LENGTH);
		TOX_ERR_DECRYPTION coreDecryptError;
		if (!tox_pass_decrypt(data, size, (uint8_t*)(char*)password, mir_strlen(password), encryptedData, &coreDecryptError))
		{
			ShowNotification(TranslateT("Unable to decrypt Tox profile"), MB_ICONERROR);
			debugLogA(__FUNCTION__": failed to decrypt tox profile (%d)", coreDecryptError);
			mir_free(data);
			return false;
		}
		mir_free(data);
		data = encryptedData;
		size -= TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
	}

	if (data)
	{
		options->savedata_data = data;
		options->savedata_length = size;
		options->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
		return true;
	}

	return false;
}
Example #7
0
/* Returns a new Tox object on success.
 * If object fails to initialize the toxic process will terminate.
 */
static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW *new_err)
{
    Tox *m = NULL;

    FILE *fp = fopen(data_path, "rb");

    if (fp != NULL) {   /* Data file exists */
        off_t len = file_size(data_path);

        if (len == 0) {
            fclose(fp);
            exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
        }

        char data[len];

        if (fread(data, sizeof(data), 1, fp) != 1) {
            fclose(fp);
            exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
        }

        bool is_encrypted = tox_is_data_encrypted((uint8_t *) data);

        /* attempt to encrypt an already encrypted data file */
        if (arg_opts.encrypt_data && is_encrypted) {
            fclose(fp);
            exit_toxic_err("failed in load_tox", FATALERR_ENCRYPT);
        }

        if (arg_opts.unencrypt_data && is_encrypted)
            queue_init_message("Data file '%s' has been unencrypted", data_path);
        else if (arg_opts.unencrypt_data)
            queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", data_path);

        if (is_encrypted) {
            if (!arg_opts.unencrypt_data)
                user_password.data_is_encrypted = true;

            size_t pwlen = 0;
            int pweval = user_settings->password_eval[0];

            if (!pweval) {
                system("clear");   // TODO: is this portable?
                printf("Enter password (q to quit) ");
            }

            size_t plain_len = len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
            char plain[plain_len];

            while (true) {
                if (pweval) {
                    pwlen = password_eval(user_password.pass, sizeof(user_password.pass));
                } else {
                    pwlen = password_prompt(user_password.pass, sizeof(user_password.pass));
                }

                user_password.len = pwlen;

                if (strcasecmp(user_password.pass, "q") == 0) {
                    fclose(fp);
                    exit(0);
                }

                if (pwlen < MIN_PASSWORD_LEN) {
                    system("clear");
                    sleep(1);
                    printf("Invalid password. Try again. ");
                    pweval = 0;
                    continue;
                }

                TOX_ERR_DECRYPTION pwerr;
                tox_pass_decrypt((uint8_t *) data, len, (uint8_t *) user_password.pass, pwlen,
                                 (uint8_t *) plain, &pwerr);

                if (pwerr == TOX_ERR_DECRYPTION_OK) {
                    tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
                    tox_opts->savedata_data = (uint8_t *) plain;
                    tox_opts->savedata_length = plain_len;

                    m = tox_new(tox_opts, new_err);

                    if (m == NULL) {
                        fclose(fp);
                        return NULL;
                    }

                    break;
                } else if (pwerr == TOX_ERR_DECRYPTION_FAILED) {
                    system("clear");
                    sleep(1);
                    printf("Invalid password. Try again. ");
                    pweval = 0;
                } else {
                    fclose(fp);
                    exit_toxic_err("tox_pass_decrypt() failed", pwerr);
                }
            }
        } else {   /* data is not encrypted */
            tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
            tox_opts->savedata_data = (uint8_t *) data;
            tox_opts->savedata_length = len;

            m = tox_new(tox_opts, new_err);

            if (m == NULL) {
                fclose(fp);
                return NULL;
            }
        }

        fclose(fp);
    } else {   /* Data file does not/should not exist */
        if (file_exists(data_path))
            exit_toxic_err("failed in load_tox", FATALERR_FILEOP);

        tox_opts->savedata_type = TOX_SAVEDATA_TYPE_NONE;

        m = tox_new(tox_opts, new_err);

        if (m == NULL)
            return NULL;

        if (store_data(m, data_path) == -1)
            exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
    }

    return m;
}
Example #8
0
Profile* Profile::loadProfile(QString name, QString password)
{
    if (ProfileLocker::hasLock())
    {
        qCritical() << "Tried to load profile "<<name<<", but another profile is already locked!";
        return nullptr;
    }

    if (!ProfileLocker::lock(name))
    {
        qWarning() << "Failed to lock profile "<<name;
        return nullptr;
    }

    // Check password
    {
        QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox";
        QFile saveFile(path);
        qDebug() << "Loading tox save "<<path;

        if (!saveFile.exists())
        {
            qWarning() << "The tox save file "<<path<<" was not found";
            ProfileLocker::unlock();
            return nullptr;
        }

        if (!saveFile.open(QIODevice::ReadOnly))
        {
            qCritical() << "The tox save file " << path << " couldn't' be opened";
            ProfileLocker::unlock();
            return nullptr;
        }

        qint64 fileSize = saveFile.size();
        if (fileSize <= 0)
        {
            qWarning() << "The tox save file"<<path<<" is empty!";
            ProfileLocker::unlock();
            return nullptr;
        }

        QByteArray data = saveFile.readAll();
        if (tox_is_data_encrypted((uint8_t*)data.data()))
        {
            if (password.isEmpty())
            {
                qCritical() << "The tox save file is encrypted, but we don't have a password!";
                ProfileLocker::unlock();
                return nullptr;
            }

            uint8_t salt[TOX_PASS_SALT_LENGTH];
            tox_get_salt(reinterpret_cast<uint8_t *>(data.data()), salt);
            auto tmpkey = *Core::createPasskey(password, salt);

            data = Core::decryptData(data, tmpkey);
            if (data.isEmpty())
            {
                qCritical() << "Failed to decrypt the tox save file";
                ProfileLocker::unlock();
                return nullptr;
            }
        }
        else
        {
            if (!password.isEmpty())
                qWarning() << "We have a password, but the tox save file is not encrypted";
        }
    }

    return new Profile(name, password, false);
}
Example #9
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);
}
Example #10
0
QByteArray Core::loadToxSave(QString path)
{
    QByteArray data;
    loadPath = ""; // if not empty upon return, then user forgot a password and is switching

    // If we can't get a lock, then another instance is already using that profile
    while (!ProfileLocker::lock(QFileInfo(path).baseName()))
    {
        qWarning() << "Profile "<<QFileInfo(path).baseName()<<" is already in use, pick another";
        GUI::showWarning(tr("Profile already in use"),
                         tr("Your profile is already used by another qTox\n"
                            "Please select another profile"));
        QString tmppath = Settings::getInstance().askProfiles();
        if (tmppath.isEmpty())
            continue;
        Settings::getInstance().switchProfile(tmppath);
        path = QDir(Settings::getSettingsDirPath()).filePath(tmppath + TOX_EXT);
        HistoryKeeper::resetInstance();
    }

    QFile configurationFile(path);
    qDebug() << "Core::loadConfiguration: reading from " << path;

    if (!configurationFile.exists())
    {
        qWarning() << "The Tox configuration file "<<path<<" was not found";
        return data;
    }

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

    qint64 fileSize = configurationFile.size();
    if (fileSize > 0)
    {
        data = configurationFile.readAll();
        if (tox_is_data_encrypted((uint8_t*)data.data()))
        {
            if (!loadEncryptedSave(data))
            {
                configurationFile.close();

                QString profile;
                do {
                    profile = Settings::getInstance().askProfiles();
                } while (profile.isEmpty());

                if (!profile.isEmpty())
                {
                    Settings::getInstance().switchProfile(profile);
                    HistoryKeeper::resetInstance();
                    return loadToxSave(QDir(Settings::getSettingsDirPath()).filePath(profile + TOX_EXT));
                }
                return QByteArray();
            }
        }
    }
    configurationFile.close();

    return data;
}