@ -91,15 +91,55 @@
@@ -91,15 +91,55 @@
* @ param password If empty , the database will be opened unencrypted .
* Otherwise we will use toxencryptsave to derive a key and encrypt the database .
*/
RawDatabase : : RawDatabase ( const QString & path , const QString & password )
: workerThread { new QThread } , path { path } , currentHexKey { deriveKey ( password ) }
RawDatabase : : RawDatabase ( const QString & path , const QString & password , const QByteArray & salt )
: workerThread { new QThread }
, path { path }
, currentSalt { salt } // we need the salt later if a new password should be set
, currentHexKey { deriveKey ( password , salt ) }
{
workerThread - > setObjectName ( " qTox Database " ) ;
moveToThread ( workerThread . get ( ) ) ;
workerThread - > start ( ) ;
if ( ! open ( path , currentHexKey ) )
// first try with the new salt
if ( open ( path , currentHexKey ) )
{
return ;
}
// avoid opening the same db twice
close ( ) ;
// create a backup before trying to upgrade to new salt
bool upgrade = true ;
if ( ! QFile : : copy ( path , path + " .bak " ) )
{
qDebug ( ) < < " Couldn't create the backup of the database, won't upgrade " ;
upgrade = false ;
}
// fall back to the old salt
currentHexKey = deriveKey ( password ) ;
if ( open ( path , currentHexKey ) )
{
// upgrade only if backup successful
if ( upgrade )
{
// still using old salt, upgrade
if ( setPassword ( password ) )
{
qDebug ( ) < < " Successfully upgraded to dynamic salt " ;
}
else
{
qWarning ( ) < < " Failed to set password with new salt " ;
}
}
}
else
{
qDebug ( ) < < " Failed to open database with old salt " ;
}
}
RawDatabase : : ~ RawDatabase ( )
@ -313,7 +353,7 @@ bool RawDatabase::setPassword(const QString& password)
@@ -313,7 +353,7 @@ bool RawDatabase::setPassword(const QString& password)
if ( ! password . isEmpty ( ) )
{
QString newHexKey = deriveKey ( password ) ;
QString newHexKey = deriveKey ( password , currentSalt ) ;
if ( ! currentHexKey . isEmpty ( ) )
{
if ( ! execNow ( " PRAGMA rekey = \" x' " + newHexKey + " ' \" " ) )
@ -445,6 +485,7 @@ bool RawDatabase::remove()
@@ -445,6 +485,7 @@ bool RawDatabase::remove()
* @ brief Derives a 256 bit key from the password and returns it hex - encoded
* @ param password Password to decrypt database
* @ return String representation of key
* @ deprecated deprecated on 2016 - 11 - 06 , kept for compatibility , replaced by the salted version
*/
QString RawDatabase : : deriveKey ( const QString & password )
{
@ -457,8 +498,39 @@ QString RawDatabase::deriveKey(const QString &password)
@@ -457,8 +498,39 @@ QString RawDatabase::deriveKey(const QString &password)
static const uint8_t expandConstant [ TOX_PASS_SALT_LENGTH + 1 ] = " L'ignorance est le pire des maux " ;
TOX_PASS_KEY key ;
tox_derive_key_with_salt ( ( uint8_t * ) passData . data ( ) , passData . size ( ) , expandConstant , & key , nullptr ) ;
return QByteArray ( ( char * ) key . key , 32 ) . toHex ( ) ;
tox_derive_key_with_salt ( reinterpret_cast < uint8_t * > ( passData . data ( ) ) ,
static_cast < std : : size_t > ( passData . size ( ) ) , expandConstant , & key , nullptr ) ;
return QByteArray ( reinterpret_cast < char * > ( key . key ) , 32 ) . toHex ( ) ;
}
/**
* @ brief Derives a 256 bit key from the password and returns it hex - encoded
* @ param password Password to decrypt database
* @ param salt Salt to improve password strength , must be TOX_PASS_SALT_LENGTH bytes
* @ return String representation of key
*/
QString RawDatabase : : deriveKey ( const QString & password , const QByteArray & salt )
{
if ( password . isEmpty ( ) )
{
return { } ;
}
if ( salt . length ( ) ! = TOX_PASS_SALT_LENGTH )
{
qWarning ( ) < < " Salt length doesn't match toxencryptsave expections " ;
return { } ;
}
QByteArray passData = password . toUtf8 ( ) ;
static_assert ( TOX_PASS_KEY_LENGTH > = 32 , " toxcore must provide 256bit or longer keys " ) ;
TOX_PASS_KEY key ;
tox_derive_key_with_salt ( reinterpret_cast < uint8_t * > ( passData . data ( ) ) ,
static_cast < std : : size_t > ( passData . size ( ) ) ,
reinterpret_cast < const uint8_t * > ( salt . constData ( ) ) , & key , nullptr ) ;
return QByteArray ( reinterpret_cast < char * > ( key . key ) , 32 ) . toHex ( ) ;
}
/**
@ -500,7 +572,8 @@ void RawDatabase::process()
@@ -500,7 +572,8 @@ void RawDatabase::process()
for ( Query & query : trans . queries )
{
assert ( query . statements . isEmpty ( ) ) ;
// sqlite3_prepare_v2 only compiles one statement at a time in the query, we need to loop over them all
// sqlite3_prepare_v2 only compiles one statement at a time in the query,
// we need to loop over them all
int curParam = 0 ;
const char * compileTail = query . query . data ( ) ;
do {