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" QString passwordPostSalt() const
Returns the salt string to be appended to the password.
virtual AuthenticationUser findUser(Context *c, const ParamsMultiMap &userinfo)
Tries to find the user with authinfo returning a non null AuthenticationUser on success.
void setPasswordPreSalt(const QString &passwordPreSalt)
Sets the salt string to be prepended to the password.
bool isNull() const
Returns true if the object is null.
static QByteArray hmac(QCryptographicHash::Algorithm method, const QByteArray &key, const QByteArray &message)
Generates the Hash-based message authentication code.
void setPasswordType(PasswordType type)
Sets the type of password this class will be dealing with.
static QByteArray createPassword(const QByteArray &password, QCryptographicHash::Algorithm method, int iterations, int saltByteSize, int hashByteSize)
Creates a password hash string.
QString passwordField() const
Returns the field to look for when authenticating the user.
QString passwordPreSalt() const
Returns the salt string to be prepended to the password.
The Cutelyst namespace holds all public Cutelyst API.
void setPasswordField(const QString &fieldName)
Sets the field to look for when authenticating the user.
PasswordType passwordType() const
Returns the type of password this class will be dealing with.
static QByteArray pbkdf2(QCryptographicHash::Algorithm method, const QByteArray &password, const QByteArray &salt, int rounds, int keyLength)
Generates a pbkdf2 string for the given password.
void setPasswordPostSalt(const QString &passwordPostSalt)
Sets the salt string to be appended to the password.
AuthenticationUser authenticate(Context *c, AuthenticationRealm *realm, const ParamsMultiMap &authinfo) final
Tries to authenticate the authinfo using the give realm.
static bool validatePassword(const QByteArray &password, const QByteArray &correctHash)
Validates the given password against the correct hash.
const T value(const Key &key, const T &defaultValue) const const