diff --git a/common/protocol.h b/common/protocol.h index d0210381..e95c2189 100644 --- a/common/protocol.h +++ b/common/protocol.h @@ -59,7 +59,7 @@ private: static void initializeHashAuto(); bool receiverMayDelete; public: - static const int protocolVersion = 12; + static const int protocolVersion = 13; static void initializeHash(); virtual int getItemId() const = 0; bool getReceiverMayDelete() const { return receiverMayDelete; } diff --git a/servatrice/servatrice.pro b/servatrice/servatrice.pro index a8de8ad3..ab7dc853 100755 --- a/servatrice/servatrice.pro +++ b/servatrice/servatrice.pro @@ -8,6 +8,7 @@ DEPENDPATH += . src ../common INCLUDEPATH += . src ../common MOC_DIR = build OBJECTS_DIR = build +LIBS += -lgcrypt CONFIG += qt debug QT += network sql @@ -18,6 +19,7 @@ HEADERS += src/main.h \ src/serversocketinterface.h \ src/server_logger.h \ src/serversocketthread.h \ + src/passwordhasher.h \ ../common/color.h \ ../common/serializable_item.h \ ../common/decklist.h \ @@ -42,6 +44,7 @@ SOURCES += src/main.cpp \ src/serversocketinterface.cpp \ src/server_logger.cpp \ src/serversocketthread.cpp \ + src/passwordhasher.cpp \ ../common/serializable_item.cpp \ ../common/decklist.cpp \ ../common/protocol.cpp \ diff --git a/servatrice/src/main.cpp b/servatrice/src/main.cpp index 247111be..02da15df 100644 --- a/servatrice/src/main.cpp +++ b/servatrice/src/main.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include "passwordhasher.h" #include "servatrice.h" #include "server_logger.h" #include "rng_sfmt.h" @@ -68,6 +70,17 @@ void testRNG() std::cerr << std::endl << std::endl; } +void testHash() +{ + const int n = 5000; + std::cerr << "Benchmarking password hash function (n =" << n << ")..." << std::endl; + QDateTime startTime = QDateTime::currentDateTime(); + for (int i = 0; i < n; ++i) + PasswordHasher::computeHash("aaaaaa", "aaaaaaaaaaaaaaaa"); + QDateTime endTime = QDateTime::currentDateTime(); + std::cerr << startTime.secsTo(endTime) << "secs" << std::endl; +} + void myMessageOutput(QtMsgType /*type*/, const char *msg) { logger->logMessage(msg); @@ -93,6 +106,7 @@ int main(int argc, char *argv[]) QStringList args = app.arguments(); bool testRandom = args.contains("--test-random"); + bool testHashFunction = args.contains("--test-hash"); qRegisterMetaType >("QList"); @@ -128,6 +142,8 @@ int main(int argc, char *argv[]) if (testRandom) testRNG(); + if (testHashFunction) + testHash(); Servatrice *server = new Servatrice(settings); QObject::connect(server, SIGNAL(destroyed()), &app, SLOT(quit()), Qt::QueuedConnection); diff --git a/servatrice/src/passwordhasher.cpp b/servatrice/src/passwordhasher.cpp new file mode 100644 index 00000000..48fe7b66 --- /dev/null +++ b/servatrice/src/passwordhasher.cpp @@ -0,0 +1,21 @@ +#include "passwordhasher.h" +#include +#include +#include + +QString PasswordHasher::computeHash(const QString &password, const QString &salt) +{ + const int algo = GCRY_MD_SHA512; + const int rounds = 1000; + + QByteArray passwordBuffer = (salt + password).toAscii(); + int hashLen = gcry_md_get_algo_dlen(algo); + char hash[hashLen], tmp[hashLen]; + gcry_md_hash_buffer(algo, hash, passwordBuffer.data(), passwordBuffer.size()); + for (int i = 1; i < rounds; ++i) { + memcpy(tmp, hash, hashLen); + gcry_md_hash_buffer(algo, hash, tmp, hashLen); + } + return salt + QString(QByteArray(hash, hashLen).toBase64()); +} + diff --git a/servatrice/src/passwordhasher.h b/servatrice/src/passwordhasher.h new file mode 100644 index 00000000..2487b322 --- /dev/null +++ b/servatrice/src/passwordhasher.h @@ -0,0 +1,11 @@ +#ifndef PASSWORDHASHER_H +#define PASSWORDHASHER_H + +#include + +class PasswordHasher { +public: + static QString computeHash(const QString &password, const QString &salt); +}; + +#endif diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index 6933e83b..16aee489 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -28,6 +28,7 @@ #include "protocol.h" #include "server_logger.h" #include "main.h" +#include "passwordhasher.h" void Servatrice_TcpServer::incomingConnection(int socketDescriptor) { @@ -185,7 +186,7 @@ AuthenticationResult Servatrice::checkUserPassword(Server_ProtocolHandler *handl checkSql(); QSqlQuery query; - query.prepare("select a.password, time_to_sec(timediff(now(), date_add(b.time_from, interval b.minutes minute))) < 0, b.minutes <=> 0 from " + dbPrefix + "_users a left join " + dbPrefix + "_bans b on b.id_user = a.id and b.time_from = (select max(c.time_from) from " + dbPrefix + "_bans c where c.id_user = a.id) where a.name = :name and a.active = 1"); + query.prepare("select a.password_sha512, time_to_sec(timediff(now(), date_add(b.time_from, interval b.minutes minute))) < 0, b.minutes <=> 0 from " + dbPrefix + "_users a left join " + dbPrefix + "_bans b on b.id_user = a.id and b.time_from = (select max(c.time_from) from " + dbPrefix + "_bans c where c.id_user = a.id) where a.name = :name and a.active = 1"); query.bindValue(":name", user); if (!execSqlQuery(query)) { qDebug("Login denied: SQL error"); @@ -197,7 +198,7 @@ AuthenticationResult Servatrice::checkUserPassword(Server_ProtocolHandler *handl qDebug("Login denied: banned"); return PasswordWrong; } - if (query.value(0).toString() == password) { + if (query.value(0).toString() == PasswordHasher::computeHash(password, query.value(0).toString().left(16))) { qDebug("Login accepted: password right"); return PasswordRight; } else { @@ -423,4 +424,4 @@ void Servatrice::shutdownTimeout() deleteLater(); } -const QString Servatrice::versionString = "Servatrice 0.20110803"; +const QString Servatrice::versionString = "Servatrice 0.20110921";