mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-21 00:55:09 -07:00
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
* [Security] Use a CSPRNG for salts, tokens, and RNG seeding Password salts and activation tokens were generated with the global SFMT RNG, which was seeded from a 32-bit timestamp, making registration salts and activation tokens predictable. The game RNG used the same timestamp seed across restarts. Add CryptoUtil backed by OpenSSL RAND_bytes and use it for salt/token generation and to seed RNG_SFMT with a 64-bit CSPRNG value in both the client and server. Link libcockatrice_utility against OpenSSL::Crypto. Took 30 seconds Took 25 minutes * Lint. Took 4 minutes Took 36 seconds --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
54 lines
1.7 KiB
C++
54 lines
1.7 KiB
C++
#include "passwordhasher.h"
|
|
|
|
#include <QCryptographicHash>
|
|
#include <libcockatrice/utility/cryptoutil.h>
|
|
|
|
QString PasswordHasher::computeHash(const QString &password, const QString &salt)
|
|
{
|
|
QCryptographicHash::Algorithm algo = QCryptographicHash::Sha512;
|
|
const int rounds = 1000;
|
|
|
|
QByteArray hash = (salt + password).toUtf8();
|
|
for (int i = 0; i < rounds; ++i) {
|
|
hash = QCryptographicHash::hash(hash, algo);
|
|
}
|
|
QString hashedPass = salt + QString(hash.toBase64());
|
|
return hashedPass;
|
|
}
|
|
|
|
QString PasswordHasher::generateRandomSalt(const int len)
|
|
{
|
|
static const char alphanum[] = "0123456789"
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
"abcdefghijklmnopqrstuvwxyz";
|
|
const int size = sizeof(alphanum) - 1;
|
|
|
|
// Two bytes per character, corrected for modulo bias via rejection sampling.
|
|
const int bucketSize = 65536 / size;
|
|
const int limit = bucketSize * size;
|
|
|
|
QString ret;
|
|
ret.reserve(len);
|
|
QByteArray random = CryptoUtil::randomBytes(len * 2);
|
|
int bytesUsed = 0;
|
|
for (int i = 0; i < len; ++i) {
|
|
unsigned int value;
|
|
do {
|
|
if (bytesUsed >= random.size()) {
|
|
random = CryptoUtil::randomBytes(len * 2);
|
|
bytesUsed = 0;
|
|
}
|
|
value = static_cast<unsigned int>(static_cast<unsigned char>(random.at(bytesUsed))) << 8 |
|
|
static_cast<unsigned int>(static_cast<unsigned char>(random.at(bytesUsed + 1)));
|
|
bytesUsed += 2;
|
|
} while (value >= limit);
|
|
ret.append(alphanum[value / bucketSize]);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
QString PasswordHasher::generateActivationToken()
|
|
{
|
|
return QString(CryptoUtil::randomBytes(16).toBase64().left(16));
|
|
}
|