2014-11-18 12:18:24 +08:00
/*
2015-06-06 09:40:08 +08:00
Copyright © 2014 - 2015 by The qTox Project
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
2015-06-06 09:40:08 +08:00
qTox 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 .
2015-06-06 09:40:08 +08:00
qTox is distributed in the hope that it will be useful ,
2014-11-18 12:18:24 +08:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2015-06-06 09:40:08 +08:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2014-11-18 12:18:24 +08:00
2015-06-06 09:40:08 +08:00
You should have received a copy of the GNU General Public License
along with qTox . If not , see < http : //www.gnu.org/licenses/>.
2014-11-18 12:18:24 +08:00
*/
/* 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"
2015-06-06 07:44:47 +08:00
# include "src/persistence/settings.h"
# include "src/core/cstring.h"
# include "src/persistence/historykeeper.h"
2015-06-04 20:19:18 +08:00
# include "src/nexus.h"
2015-06-06 07:44:47 +08:00
# include "src/persistence/profile.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-28 03:14:35 +08:00
std : : unique_ptr < TOX_PASS_KEY > Core : : createPasskey ( const QString & password , uint8_t * salt )
2014-11-18 12:18:24 +08:00
{
2015-06-28 03:14:35 +08:00
std : : unique_ptr < TOX_PASS_KEY > encryptionKey ( new TOX_PASS_KEY ) ;
2014-11-18 12:18:24 +08:00
CString str ( password ) ;
if ( salt )
2015-06-28 03:14:35 +08:00
tox_derive_key_with_salt ( str . data ( ) , str . size ( ) , salt , encryptionKey . get ( ) , nullptr ) ;
2014-11-18 12:18:24 +08:00
else
2015-06-28 03:14:35 +08:00
tox_derive_key_from_pass ( str . data ( ) , str . size ( ) , encryptionKey . get ( ) , nullptr ) ;
return encryptionKey ;
2014-11-18 12:18:24 +08:00
}
2015-06-28 03:14:35 +08:00
QByteArray Core : : encryptData ( const QByteArray & data )
2014-11-27 23:38:23 +08:00
{
2015-06-28 03:14:35 +08:00
return encryptData ( data , Nexus : : getProfile ( ) - > getPasskey ( ) ) ;
2014-11-18 12:18:24 +08:00
}
2015-06-28 03:14:35 +08:00
QByteArray Core : : encryptData ( const QByteArray & data , const TOX_PASS_KEY & encryptionKey )
2014-11-18 12:18:24 +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 ( ) ,
2015-06-28 03:14:35 +08:00
& encryptionKey , 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
}
2015-06-28 03:14:35 +08:00
QByteArray Core : : decryptData ( const QByteArray & data )
2014-11-18 12:18:24 +08:00
{
2015-06-28 03:14:35 +08:00
return decryptData ( data , Nexus : : getProfile ( ) - > getPasskey ( ) ) ;
}
2015-04-20 15:58:06 +08:00
2015-06-28 03:14:35 +08:00
QByteArray Core : : decryptData ( const QByteArray & data , const TOX_PASS_KEY & encryptionKey )
{
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 ( ) ,
2015-06-28 03:14:35 +08:00
& encryptionKey , 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 ) ;
}
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 ( ) ;
2015-06-05 00:51:57 +08:00
bool exists = QFile : : exists ( path ) & & QFile ( path ) . size ( ) > 0 ;
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! " ) ) ;
2015-01-28 07:25:41 +08:00
HistoryKeeper : : resetInstance ( ) ;
2014-11-18 14:34:31 +08:00
return ;
}
2015-06-28 03:14:35 +08:00
auto passkey = createPasskey ( Nexus : : getProfile ( ) - > getPassword ( ) , reinterpret_cast < uint8_t * > ( salt . data ( ) ) ) ;
2015-06-04 21:16:25 +08:00
2015-06-04 20:19:18 +08:00
QString a ( tr ( " Please enter the password for the chat history for the profile \" %1 \" . " , " used in load() when no hist pw set " ).arg(Nexus::getProfile()->getName())) ;
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 ;
2015-04-20 15:58:06 +08:00
2015-06-28 03:14:35 +08:00
if ( ! exists | | HistoryKeeper : : checkPassword ( * passkey ) )
2015-06-04 21:16:25 +08:00
return ;
2015-04-20 15:58:06 +08:00
2015-06-04 21:16:25 +08:00
dialogtxt = tr ( " The chat history password failed. Please try another? " , " used only when pw set before load() doesn't work " ) ;
2015-02-04 08:22:05 +08:00
dialogtxt + = " \n " + c ;
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
{
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
{
2015-06-28 03:14:35 +08:00
passkey = createPasskey ( pw , reinterpret_cast < uint8_t * > ( salt . data ( ) ) ) ;
2015-03-21 16:59:28 +08:00
}
2014-11-18 14:34:31 +08:00
2015-06-28 03:14:35 +08:00
error = exists & & ! HistoryKeeper : : checkPassword ( * passkey ) ;
2015-02-04 08:22:05 +08:00
dialogtxt = a + " \n " + c + " \n " + b ;
2014-11-18 14:34:31 +08:00
} while ( error ) ;
}