2014-11-18 12:18:24 +08:00
/*
2014-12-04 02:00:37 +08:00
This file is part of qTox , a Qt - based graphical interface for Tox .
2014-11-18 12:18:24 +08:00
2014-12-04 02:00:37 +08:00
This program is libre software : you can redistribute it and / or modify
2014-11-18 12:18:24 +08:00
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the COPYING file for more details .
*/
/* This file is part of the Core class, but was separated for my sanity */
2014-12-04 02:00:37 +08:00
/* The load function delegates to loadEncrypted here, and the save function */
/* was permanently moved here to handle encryption */
2014-11-18 12:18:24 +08:00
# include "core.h"
2015-02-07 02:01:31 +08:00
# include "src/widget/gui.h"
2014-11-18 12:18:24 +08:00
# include "src/misc/settings.h"
2015-04-24 08:32:09 +08:00
# include "src/misc/cstring.h"
# include "src/historykeeper.h"
2015-04-20 05:12:44 +08:00
# include <tox/tox.h>
# include <tox/toxencryptsave.h>
2014-11-18 12:18:24 +08:00
# include <QApplication>
# include <QDebug>
# include <QSaveFile>
# include <QFile>
2015-01-28 08:28:44 +08:00
# include <QThread>
2015-04-20 05:12:44 +08:00
# include <algorithm>
# include <cassert>
2014-11-18 12:18:24 +08:00
2015-06-04 08:43:07 +08:00
void Core : : setPassword ( const QString & password , PasswordType passtype , uint8_t * salt )
2014-11-18 12:18:24 +08:00
{
2014-12-09 06:40:20 +08:00
clearPassword ( passtype ) ;
2014-11-18 12:18:24 +08:00
if ( password . isEmpty ( ) )
return ;
2014-12-09 06:40:20 +08:00
2015-04-20 05:12:44 +08:00
pwsaltedkeys [ passtype ] = new TOX_PASS_KEY ;
2014-11-18 12:18:24 +08:00
CString str ( password ) ;
if ( salt )
2015-04-20 05:12:44 +08:00
tox_derive_key_with_salt ( str . data ( ) , str . size ( ) , salt , pwsaltedkeys [ passtype ] , nullptr ) ;
2014-11-18 12:18:24 +08:00
else
2015-04-20 05:12:44 +08:00
tox_derive_key_from_pass ( str . data ( ) , str . size ( ) , pwsaltedkeys [ passtype ] , nullptr ) ;
2014-11-18 12:18:24 +08:00
}
2014-11-27 23:38:23 +08:00
void Core : : useOtherPassword ( PasswordType type )
{
clearPassword ( type ) ;
2015-04-20 05:12:44 +08:00
pwsaltedkeys [ type ] = new TOX_PASS_KEY ;
2015-01-16 11:41:10 +08:00
PasswordType other = ( type = = ptMain ) ? ptHistory : ptMain ;
2015-04-24 04:59:12 +08:00
std : : copy ( pwsaltedkeys [ other ] , pwsaltedkeys [ other ] + 1 , pwsaltedkeys [ type ] ) ;
2014-11-27 23:38:23 +08:00
}
2014-11-18 12:18:24 +08:00
void Core : : clearPassword ( PasswordType passtype )
{
2015-04-24 04:59:12 +08:00
delete pwsaltedkeys [ passtype ] ;
2014-12-10 09:06:09 +08:00
pwsaltedkeys [ passtype ] = nullptr ;
2014-11-18 12:18:24 +08:00
}
QByteArray Core : : encryptData ( const QByteArray & data , PasswordType passtype )
{
if ( ! pwsaltedkeys [ passtype ] )
return QByteArray ( ) ;
2015-04-20 15:58:06 +08:00
2015-04-20 05:12:44 +08:00
uint8_t encrypted [ data . size ( ) + TOX_PASS_ENCRYPTION_EXTRA_LENGTH ] ;
if ( ! tox_pass_key_encrypt ( reinterpret_cast < const uint8_t * > ( data . data ( ) ) , data . size ( ) ,
pwsaltedkeys [ passtype ] , encrypted , nullptr ) )
2014-11-18 12:18:24 +08:00
{
2015-06-04 07:30:17 +08:00
qWarning ( ) < < " Encryption failed " ;
2014-11-18 12:18:24 +08:00
return QByteArray ( ) ;
}
2015-04-20 05:12:44 +08:00
return QByteArray ( reinterpret_cast < char * > ( encrypted ) , data . size ( ) + TOX_PASS_ENCRYPTION_EXTRA_LENGTH ) ;
2014-11-18 12:18:24 +08:00
}
QByteArray Core : : decryptData ( const QByteArray & data , PasswordType passtype )
{
if ( ! pwsaltedkeys [ passtype ] )
return QByteArray ( ) ;
2015-04-20 15:58:06 +08:00
2015-04-20 05:12:44 +08:00
int sz = data . size ( ) - TOX_PASS_ENCRYPTION_EXTRA_LENGTH ;
2014-11-18 12:18:24 +08:00
uint8_t decrypted [ sz ] ;
2015-04-20 05:12:44 +08:00
if ( ! tox_pass_key_decrypt ( reinterpret_cast < const uint8_t * > ( data . data ( ) ) , data . size ( ) ,
pwsaltedkeys [ passtype ] , decrypted , nullptr ) )
2014-11-18 12:18:24 +08:00
{
2015-06-04 07:30:17 +08:00
qWarning ( ) < < " Decryption failed " ;
2014-11-18 12:18:24 +08:00
return QByteArray ( ) ;
}
return QByteArray ( reinterpret_cast < char * > ( decrypted ) , sz ) ;
}
bool Core : : isPasswordSet ( PasswordType passtype )
{
if ( pwsaltedkeys [ passtype ] )
return true ;
return false ;
}
QByteArray Core : : getSaltFromFile ( QString filename )
{
QFile file ( filename ) ;
2014-12-10 08:08:38 +08:00
if ( ! file . open ( QIODevice : : ReadOnly ) )
{
2015-05-11 20:54:03 +08:00
qWarning ( ) < < " file " < < filename < < " doesn't exist " ;
2014-12-10 08:08:38 +08:00
return QByteArray ( ) ;
}
2015-04-20 05:12:44 +08:00
QByteArray data = file . read ( TOX_PASS_ENCRYPTION_EXTRA_LENGTH ) ;
2014-11-18 12:18:24 +08:00
file . close ( ) ;
2015-04-20 05:12:44 +08:00
uint8_t * salt = new uint8_t [ TOX_PASS_SALT_LENGTH ] ;
2015-04-24 07:08:34 +08:00
if ( ! tox_get_salt ( reinterpret_cast < uint8_t * > ( data . data ( ) ) , salt ) )
2014-11-18 12:18:24 +08:00
{
2015-05-11 20:54:03 +08:00
qWarning ( ) < < " can't get salt from " < < filename < < " header " ;
2014-11-18 12:18:24 +08:00
return QByteArray ( ) ;
}
2015-04-24 07:10:42 +08:00
QByteArray res ( reinterpret_cast < const char * > ( salt ) , TOX_PASS_SALT_LENGTH ) ;
2015-03-22 04:58:26 +08:00
delete [ ] salt ;
2014-11-18 12:18:24 +08:00
return res ;
}
2014-11-18 14:34:31 +08:00
void Core : : checkEncryptedHistory ( )
{
2015-01-20 11:49:41 +08:00
QString path = HistoryKeeper : : getHistoryPath ( ) ;
bool exists = QFile : : exists ( path ) ;
2014-11-18 14:34:31 +08:00
2015-01-20 11:49:41 +08:00
QByteArray salt = getSaltFromFile ( path ) ;
if ( exists & & salt . size ( ) = = 0 )
2014-11-18 14:34:31 +08:00
{ // maybe we should handle this better
2015-02-07 02:01:31 +08:00
GUI : : showWarning ( tr ( " Encrypted chat history " ) , tr ( " No encrypted chat history file found, or it was corrupted. \n History will be disabled! " ) ) ;
2014-11-18 14:34:31 +08:00
Settings : : getInstance ( ) . setEncryptLogs ( false ) ;
Settings : : getInstance ( ) . setEnableLogging ( false ) ;
2015-01-28 07:25:41 +08:00
HistoryKeeper : : resetInstance ( ) ;
2014-11-18 14:34:31 +08:00
return ;
}
2015-02-04 01:58:37 +08:00
QString a ( tr ( " Please enter the password for the chat history for the %1 profile. " , " used in load() when no hist pw set " ).arg(Settings::getInstance().getCurrentProfile())) ;
2014-11-18 14:34:31 +08:00
QString b ( tr ( " The previous password is incorrect; please try again: " , " used on retries in load() " ) ) ;
2015-02-05 06:11:21 +08:00
QString c ( tr ( " \n Disabling chat history now will leave the encrypted history intact (but not usable) ; if you later remember the password , you may re - enable encryption from the Privacy tab with the correct password to use the history . " , " part of history password dialog " ));
2014-11-18 14:34:31 +08:00
QString dialogtxt ;
if ( pwsaltedkeys [ ptHistory ] )
{
2015-01-20 11:49:41 +08:00
if ( ! exists | | HistoryKeeper : : checkPassword ( ) )
2014-11-18 14:34:31 +08:00
return ;
2015-04-20 15:58:06 +08:00
2015-02-04 01:58:37 +08:00
dialogtxt = tr ( " The chat history password failed. Please try another? " , " used only when pw set before load() doesn't work " ) ;
2014-11-18 14:34:31 +08:00
}
else
2015-04-24 19:01:50 +08:00
{
2014-11-18 14:34:31 +08:00
dialogtxt = a ;
2015-04-24 19:01:50 +08:00
}
2015-04-20 15:58:06 +08:00
2015-02-04 08:22:05 +08:00
dialogtxt + = " \n " + c ;
2014-11-18 14:34:31 +08:00
2014-12-10 08:40:05 +08:00
if ( pwsaltedkeys [ ptMain ] )
{
useOtherPassword ( ptHistory ) ;
2015-01-20 11:49:41 +08:00
if ( ! exists | | HistoryKeeper : : checkPassword ( ) )
{
2015-05-11 20:54:03 +08:00
qDebug ( ) < < " using main password for chat history " ;
2014-12-10 08:40:05 +08:00
return ;
2015-01-20 11:49:41 +08:00
}
2014-12-10 08:40:05 +08:00
clearPassword ( ptHistory ) ;
}
2014-11-18 14:34:31 +08:00
bool error = true ;
do
{
2015-02-07 02:01:31 +08:00
QString pw = GUI : : passwordDialog ( tr ( " Disable chat history " ) , dialogtxt ) ;
2014-11-18 14:34:31 +08:00
2014-12-06 08:18:43 +08:00
if ( pw . isEmpty ( ) )
2014-11-18 14:34:31 +08:00
{
clearPassword ( ptHistory ) ;
Settings : : getInstance ( ) . setEncryptLogs ( false ) ;
Settings : : getInstance ( ) . setEnableLogging ( false ) ;
2015-01-28 07:25:41 +08:00
HistoryKeeper : : resetInstance ( ) ;
2014-11-18 14:34:31 +08:00
return ;
}
2014-12-06 08:18:43 +08:00
else
2015-03-21 16:59:28 +08:00
{
2014-12-06 08:18:43 +08:00
setPassword ( pw , ptHistory , reinterpret_cast < uint8_t * > ( salt . data ( ) ) ) ;
2015-03-21 16:59:28 +08:00
}
2014-11-18 14:34:31 +08:00
2015-01-20 11:49:41 +08:00
error = exists & & ! HistoryKeeper : : checkPassword ( ) ;
2015-02-04 08:22:05 +08:00
dialogtxt = a + " \n " + c + " \n " + b ;
2014-11-18 14:34:31 +08:00
} while ( error ) ;
}