Quassel IRC  Pre-Release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
storage.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2015 by the Quassel Project *
3  * devel@quassel-irc.org *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) version 3. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19  ***************************************************************************/
20 
21 #include "storage.h"
22 
23 #include <QCryptographicHash>
24 #include <random>
25 
26 #if QT_VERSION < 0x050000
27 # include "../../3rdparty/sha512/sha512.h"
28 #endif
29 
30 Storage::Storage(QObject *parent)
31  : QObject(parent)
32 {
33 }
34 
35 QString Storage::hashPassword(const QString &password)
36 {
37  return hashPasswordSha2_512(password);
38 }
39 
40 bool Storage::checkHashedPassword(const UserId user, const QString &password, const QString &hashedPassword, const Storage::HashVersion version)
41 {
42  bool passwordCorrect = false;
43 
44  switch (version) {
45  case Storage::HashVersion::Sha1:
46  passwordCorrect = checkHashedPasswordSha1(password, hashedPassword);
47  break;
48 
49  case Storage::HashVersion::Sha2_512:
50  passwordCorrect = checkHashedPasswordSha2_512(password, hashedPassword);
51  break;
52 
53  default:
54  qWarning() << "Password hash version" << QString(version) << "is not supported, please reset password";
55  }
56 
57  if (passwordCorrect && version < Storage::HashVersion::Latest) {
58  updateUser(user, password);
59  }
60 
61  return passwordCorrect;
62 }
63 
64 QString Storage::hashPasswordSha1(const QString &password)
65 {
66  return QString(QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha1).toHex());
67 }
68 
69 bool Storage::checkHashedPasswordSha1(const QString &password, const QString &hashedPassword)
70 {
71  return hashPasswordSha1(password) == hashedPassword;
72 }
73 
74 QString Storage::hashPasswordSha2_512(const QString &password)
75 {
76  // Generate a salt of 512 bits (64 bytes) using the Mersenne Twister
77  std::random_device seed;
78  std::mt19937 generator(seed());
79  std::uniform_int_distribution<int> distribution(0, 255);
80  QByteArray saltBytes;
81  saltBytes.resize(64);
82  for (int i = 0; i < 64; i++) {
83  saltBytes[i] = (unsigned char) distribution(generator);
84  }
85  QString salt(saltBytes.toHex());
86 
87  // Append the salt to the password, hash the result, and append the salt value
88  return sha2_512(password + salt) + ":" + salt;
89 }
90 
91 bool Storage::checkHashedPasswordSha2_512(const QString &password, const QString &hashedPassword)
92 {
93  QRegExp colonSplitter("\\:");
94  QStringList hashedPasswordAndSalt = hashedPassword.split(colonSplitter);
95 
96  if (hashedPasswordAndSalt.size() == 2){
97  return sha2_512(password + hashedPasswordAndSalt[1]) == hashedPasswordAndSalt[0];
98  }
99  else {
100  qWarning() << "Password hash and salt were not in the correct format";
101  return false;
102  }
103 }
104 
105 QString Storage::sha2_512(const QString &input)
106 {
107 #if QT_VERSION >= 0x050000
108  return QString(QCryptographicHash::hash(input.toUtf8(), QCryptographicHash::Sha512).toHex());
109 #else
110  QByteArray inputBytes = input.toUtf8();
111  unsigned char output[64];
112  sha512((unsigned char*) inputBytes.constData(), inputBytes.size(), output, false);
113  return QString(QByteArray::fromRawData((char*) output, 64).toHex());
114 #endif
115 }