18 #include "credentialpassword_p.h"
19 #include "authenticationrealm.h"
21 #include <QLoggingCategory>
22 #include <QMessageAuthenticationCode>
28 Q_LOGGING_CATEGORY(C_CREDENTIALPASSWORD,
"cutelyst.plugin.credentialpassword", QtWarningMsg)
31 , d_ptr(new CredentialPasswordPrivate)
36 CredentialPassword::~CredentialPassword()
47 if (d->checkPassword(_user, authinfo)) {
50 qCDebug(C_CREDENTIALPASSWORD) <<
"Password didn't match";
53 qCDebug(C_CREDENTIALPASSWORD) <<
"Unable to locate a user matching user info provided in realm";
61 return d->passwordField;
67 d->passwordField = fieldName;
73 return d->passwordType;
79 d->passwordType = type;
85 return d->passwordPreSalt;
97 return d->passwordPostSalt;
107 bool slowEquals(
const QByteArray &a,
const QByteArray &b)
109 int diff = a.size() ^ b.size();
110 for(
int i = 0; i < a.size() && i < b.size(); i++) {
116 #define HASH_SECTIONS 4
117 #define HASH_ALGORITHM_INDEX 0
118 #define HASH_ITERATION_INDEX 1
119 #define HASH_SALT_INDEX 2
120 #define HASH_PBKDF2_INDEX 3
124 if (params.size() < HASH_SECTIONS) {
128 int method = CredentialPasswordPrivate::cryptoStrToEnum(params.at(HASH_ALGORITHM_INDEX));
133 QByteArray pbkdf2Hash = QByteArray::fromBase64(params.at(HASH_PBKDF2_INDEX));
137 static_cast<QCryptographicHash::Algorithm
>(method),
139 params.at(HASH_SALT_INDEX),
140 params.at(HASH_ITERATION_INDEX).toInt(),
150 QFile random(QStringLiteral(
"/dev/urandom"));
151 if (random.open(QIODevice::ReadOnly)) {
152 salt = random.read(saltByteSize).toBase64();
155 salt = QUuid::createUuid().toRfc4122().toBase64();
160 const QByteArray methodStr = CredentialPasswordPrivate::cryptoEnumToStr(method);
161 return methodStr +
':' + QByteArray::number(iterations) +
':' + salt +
':' +
173 return createPassword(password, QCryptographicHash::Sha512, 10000, 16, 16);
180 QByteArray
CredentialPassword::pbkdf2(QCryptographicHash::Algorithm method,
const QByteArray &password,
const QByteArray &salt,
int rounds,
int keyLength)
184 if (rounds <= 0 || keyLength <= 0) {
185 qCCritical(C_CREDENTIALPASSWORD,
"PBKDF2 ERROR: Invalid parameters.");
189 if (salt.size() == 0 || salt.size() > std::numeric_limits<int>::max() - 4) {
192 key.reserve(keyLength);
194 int saltSize = salt.size();
195 QByteArray asalt = salt;
196 asalt.resize(saltSize + 4);
200 QMessageAuthenticationCode code(method, password);
202 for (
int count = 1, remainingBytes = keyLength; remainingBytes > 0; ++count) {
203 asalt[saltSize + 0] =
static_cast<char>((count >> 24) & 0xff);
204 asalt[saltSize + 1] =
static_cast<char>((count >> 16) & 0xff);
205 asalt[saltSize + 2] =
static_cast<char>((count >> 8) & 0xff);
206 asalt[saltSize + 3] =
static_cast<char>(count & 0xff);
210 obuf = d1 = code.result();
212 for (
int i = 1; i < rounds; ++i) {
216 auto it = obuf.begin();
217 auto d1It = d1.cbegin();
218 while (d1It != d1.cend()) {
226 remainingBytes -= obuf.size();
229 key = key.mid(0, keyLength);
235 return QMessageAuthenticationCode::hash(key, message, method);
240 QString password = authinfo.
value(passwordField);
241 const QString storedPassword = user.value(passwordField).toString();
243 if (Q_LIKELY(passwordType == CredentialPassword::Hashed)) {
244 if (!passwordPreSalt.isEmpty()) {
245 password.prepend(password);
248 if (!passwordPostSalt.isEmpty()) {
249 password.append(password);
253 }
else if (passwordType == CredentialPassword::Clear) {
254 return storedPassword == password;
255 }
else if (passwordType == CredentialPassword::None) {
256 qCDebug(C_CREDENTIALPASSWORD) <<
"CredentialPassword is set to ignore password check";
263 QByteArray CredentialPasswordPrivate::cryptoEnumToStr(QCryptographicHash::Algorithm method)
265 QByteArray hashmethod;
267 #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
268 if (method == QCryptographicHash::Md4) {
269 hashmethod = QByteArrayLiteral(
"Md4");
270 }
else if (method == QCryptographicHash::Md5) {
271 hashmethod = QByteArrayLiteral(
"Md5");
274 if (method == QCryptographicHash::Sha1) {
275 hashmethod = QByteArrayLiteral(
"Sha1");
277 #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
278 if (method == QCryptographicHash::Sha224) {
279 hashmethod = QByteArrayLiteral(
"Sha224");
280 }
else if (method == QCryptographicHash::Sha256) {
281 hashmethod = QByteArrayLiteral(
"Sha256");
282 }
else if (method == QCryptographicHash::Sha384) {
283 hashmethod = QByteArrayLiteral(
"Sha384");
284 }
else if (method == QCryptographicHash::Sha512) {
285 hashmethod = QByteArrayLiteral(
"Sha512");
286 }
else if (method == QCryptographicHash::Sha3_224) {
287 hashmethod = QByteArrayLiteral(
"Sha3_224");
288 }
else if (method == QCryptographicHash::Sha3_256) {
289 hashmethod = QByteArrayLiteral(
"Sha3_256");
290 }
else if (method == QCryptographicHash::Sha3_384) {
291 hashmethod = QByteArrayLiteral(
"Sha3_384");
292 }
else if (method == QCryptographicHash::Sha3_512) {
293 hashmethod = QByteArrayLiteral(
"Sha3_512");
300 int CredentialPasswordPrivate::cryptoStrToEnum(
const QByteArray &hashMethod)
302 QByteArray hashmethod = hashMethod;
305 #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
306 if (hashmethod ==
"Md4") {
307 method = QCryptographicHash::Md4;
308 }
else if (hashmethod ==
"Md5") {
309 method = QCryptographicHash::Md5;
312 if (hashmethod ==
"Sha1") {
313 method = QCryptographicHash::Sha1;
315 #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
316 if (hashmethod ==
"Sha224") {
317 method = QCryptographicHash::Sha224;
318 }
else if (hashmethod ==
"Sha256") {
319 method = QCryptographicHash::Sha256;
320 }
else if (hashmethod ==
"Sha384") {
321 method = QCryptographicHash::Sha384;
322 }
else if (hashmethod ==
"Sha512") {
323 method = QCryptographicHash::Sha512;
324 }
else if (hashmethod ==
"Sha3_224") {
325 method = QCryptographicHash::Sha3_224;
326 }
else if (hashmethod ==
"Sha3_256") {
327 method = QCryptographicHash::Sha3_256;
328 }
else if (hashmethod ==
"Sha3_384") {
329 method = QCryptographicHash::Sha3_384;
330 }
else if (hashmethod ==
"Sha3_512") {
331 method = QCryptographicHash::Sha3_512;
338 #include "moc_credentialpassword.cpp"