Пример #1
0
/**
 * @brief Get a contact's avatar from cache, with a specified profile password.
 * @param ownerId Friend ID to load avatar.
 * @param password Profile password to decrypt data.
 * @return Avatar as QByteArray.
 */
QByteArray Profile::loadAvatarData(const QString& ownerId, const QString& password)
{
    QString path = avatarPath(ownerId);
    bool encrypted = !password.isEmpty();

    // If the encrypted avatar isn't found, try loading the unencrypted one for the same ID
    if (!password.isEmpty() && !QFile::exists(path))
    {
        encrypted = false;
        path = avatarPath(ownerId, true);
    }

    QFile file(path);
    if (!file.open(QIODevice::ReadOnly))
    {
        return {};
    }

    QByteArray pic = file.readAll();
    if (encrypted && !pic.isEmpty())
    {
        uint8_t salt[TOX_PASS_SALT_LENGTH];
        tox_get_salt(reinterpret_cast<uint8_t*>(pic.data()), salt);
        auto passkey = core->createPasskey(password, salt);
        pic = core->decryptData(pic, *passkey);
    }

    return pic;
}
Пример #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;
}
Пример #3
0
bool Core::loadEncryptedSave(QByteArray& data)
{
    if (!Settings::getInstance().getEncryptTox())
        GUI::showWarning(tr("Encryption error"), tr("The .tox file is encrypted, but encryption was not checked, continuing regardless."));

    size_t fileSize = data.size();
    int error = -1;
    QString a(tr("Please enter the password for the %1 profile.", "used in load() when no pw is already set").arg(Settings::getInstance().getCurrentProfile()));
    QString b(tr("The previous password is incorrect; please try again:", "used on retries in load()"));
    QString dialogtxt;

    if (pwsaltedkeys[ptMain]) // password set, try it
    {
        QByteArray newData(fileSize-TOX_PASS_ENCRYPTION_EXTRA_LENGTH, 0);
        if (tox_pass_key_decrypt((uint8_t*)data.data(), fileSize, pwsaltedkeys[ptMain],
                                 (uint8_t*)newData.data(), nullptr))
        {
            data = newData;
            Settings::getInstance().setEncryptTox(true);
            return true;
        }

        dialogtxt = tr("The profile password failed. Please try another?", "used only when pw set before load() doesn't work");
    }
    else
    {
        dialogtxt = a;
    }

    uint8_t salt[TOX_PASS_SALT_LENGTH];
    tox_get_salt(reinterpret_cast<uint8_t *>(data.data()), salt);

    do
    {
        QString pw = GUI::passwordDialog(tr("Change profile"), dialogtxt);

        if (pw.isEmpty())
        {
            clearPassword(ptMain);
            return false;
        }
        else
        {
            setPassword(pw, ptMain, salt);
        }

        QByteArray newData(fileSize-TOX_PASS_ENCRYPTION_EXTRA_LENGTH, 0);
        error = !tox_pass_key_decrypt((uint8_t*)data.data(), data.size(), pwsaltedkeys[ptMain],
                                 (uint8_t*)newData.data(), nullptr);
        if (!error)
            data = newData;

        dialogtxt = a + "\n" + b;
    } while (error != 0);

    Settings::getInstance().setEncryptTox(true);
    return true;
}
Пример #4
0
END_TEST

START_TEST(test_keys)
{
    TOX_ERR_ENCRYPTION encerr;
    TOX_ERR_DECRYPTION decerr;
    TOX_ERR_KEY_DERIVATION 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);
    ck_assert_msg(ret, "generic failure 2: %u", encerr);

    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];

    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(memcmp(out2, string, 44) == 0, "decryption 2 failed");

    // test that pass_decrypt can decrypt things from pass_key_encrypt
    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(tox_get_salt(encrypted, salt), "couldn't get salt");
    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, sizeof(TOX_PASS_KEY)), "salt comparison failed");
}
Пример #5
0
QByteArray Core::getSaltFromFile(QString filename)
{
    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly))
    {
        qWarning() << "file" << filename << "doesn't exist";
        return QByteArray();
    }
    QByteArray data = file.read(TOX_PASS_ENCRYPTION_EXTRA_LENGTH);
    file.close();

    uint8_t salt[TOX_PASS_SALT_LENGTH];
    if (!tox_get_salt(reinterpret_cast<uint8_t *>(data.data()), salt, nullptr))
    {
        qWarning() << "can't get salt from" << filename << "header";
        return QByteArray();
    }

    QByteArray res(reinterpret_cast<const char*>(salt), TOX_PASS_SALT_LENGTH);
    return res;
}
Пример #6
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;
}
Пример #7
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);
}