mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-21 00:55:09 -07:00
[Security] Use a CSPRNG for salts, tokens, and RNG seeding (#7192)
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
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>
This commit is contained in:
parent
3ec62df3e7
commit
d6fbfb32a1
19 changed files with 109 additions and 37 deletions
|
|
@ -8,6 +8,7 @@ RUN pacman --sync --refresh --sysupgrade --needed --noconfirm \
|
||||||
gtest \
|
gtest \
|
||||||
mariadb-libs \
|
mariadb-libs \
|
||||||
ninja \
|
ninja \
|
||||||
|
openssl \
|
||||||
protobuf \
|
protobuf \
|
||||||
qt6-base \
|
qt6-base \
|
||||||
qt6-declarative \
|
qt6-declarative \
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ RUN apt-get update && \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt6multimedia6 \
|
libqt6multimedia6 \
|
||||||
libqt6sql6-mysql \
|
libqt6sql6-mysql \
|
||||||
|
libssl-dev \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt6-image-formats-plugins \
|
qt6-image-formats-plugins \
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ RUN apt-get update && \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt6multimedia6 \
|
libqt6multimedia6 \
|
||||||
libqt6sql6-mysql \
|
libqt6sql6-mysql \
|
||||||
|
libssl-dev \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt6-image-formats-plugins \
|
qt6-image-formats-plugins \
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ RUN dnf install -y \
|
||||||
git \
|
git \
|
||||||
mariadb-devel \
|
mariadb-devel \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
|
openssl-devel \
|
||||||
protobuf-devel \
|
protobuf-devel \
|
||||||
qt6-{qtdeclarative,qtshadertools,qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
qt6-{qtdeclarative,qtshadertools,qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
||||||
qt6-qtimageformats \
|
qt6-qtimageformats \
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ RUN dnf install -y \
|
||||||
git \
|
git \
|
||||||
mariadb-devel \
|
mariadb-devel \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
|
openssl-devel \
|
||||||
protobuf-devel \
|
protobuf-devel \
|
||||||
qt6-{qtdeclarative,qtshadertools,qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
qt6-{qtdeclarative,qtshadertools,qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
||||||
qt6-qtimageformats \
|
qt6-qtimageformats \
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ RUN apt-get update && \
|
||||||
libmariadb-dev-compat \
|
libmariadb-dev-compat \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt6sql6-mysql \
|
libqt6sql6-mysql \
|
||||||
|
libssl-dev \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt6-tools-dev \
|
qt6-tools-dev \
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ RUN apt-get update && \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt6multimedia6 \
|
libqt6multimedia6 \
|
||||||
libqt6sql6-mysql \
|
libqt6sql6-mysql \
|
||||||
|
libssl-dev \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt6-image-formats-plugins \
|
qt6-image-formats-plugins \
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ RUN apt-get update && \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt6multimedia6 \
|
libqt6multimedia6 \
|
||||||
libqt6sql6-mysql \
|
libqt6sql6-mysql \
|
||||||
|
libssl-dev \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt6-image-formats-plugins \
|
qt6-image-formats-plugins \
|
||||||
|
|
|
||||||
|
|
@ -245,11 +245,6 @@ if(WIN32)
|
||||||
find_package(OpenSSL REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
if(OPENSSL_FOUND)
|
if(OPENSSL_FOUND)
|
||||||
include_directories(${OPENSSL_INCLUDE_DIRS})
|
include_directories(${OPENSSL_INCLUDE_DIRS})
|
||||||
else()
|
|
||||||
message(
|
|
||||||
WARNING
|
|
||||||
"Could not find OpenSSL runtime libraries. They are not required for compiling, but needs to be available at runtime."
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ RUN apt-get update \
|
||||||
libmariadb-dev-compat \
|
libmariadb-dev-compat \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt6sql6-mysql \
|
libqt6sql6-mysql \
|
||||||
|
libssl-dev \
|
||||||
qt6-websockets-dev \
|
qt6-websockets-dev \
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt6-tools-dev \
|
qt6-tools-dev \
|
||||||
|
|
@ -42,6 +43,7 @@ RUN apt-get update \
|
||||||
libprotobuf32t64 \
|
libprotobuf32t64 \
|
||||||
libqt6sql6-mysql \
|
libqt6sql6-mysql \
|
||||||
libqt6websockets6 \
|
libqt6websockets6 \
|
||||||
|
libssl3 \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@
|
||||||
#include <libcockatrice/settings/interface_settings.h>
|
#include <libcockatrice/settings/interface_settings.h>
|
||||||
#include <libcockatrice/settings/network_settings.h>
|
#include <libcockatrice/settings/network_settings.h>
|
||||||
#include <libcockatrice/settings/personal_settings.h>
|
#include <libcockatrice/settings/personal_settings.h>
|
||||||
|
#include <libcockatrice/utility/cryptoutil.h>
|
||||||
|
|
||||||
QTranslator *translator, *qtTranslator;
|
QTranslator *translator, *qtTranslator;
|
||||||
RNG_Abstract *rng;
|
RNG_Abstract *rng;
|
||||||
|
|
@ -292,7 +293,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rng = new RNG_SFMT;
|
rng = new RNG_SFMT(CryptoUtil::randomUInt64());
|
||||||
themeManager = new ThemeManager;
|
themeManager = new ThemeManager;
|
||||||
soundEngine = new SoundEngine;
|
soundEngine = new SoundEngine;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
#include "rng_sfmt.h"
|
#include "rng_sfmt.h"
|
||||||
|
|
||||||
#include <QDateTime>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
@ -11,10 +10,11 @@
|
||||||
#define UINT64_MAX (~(uint64_t)0)
|
#define UINT64_MAX (~(uint64_t)0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
RNG_SFMT::RNG_SFMT(QObject *parent) : RNG_Abstract(parent)
|
RNG_SFMT::RNG_SFMT(uint64_t seed, QObject *parent) : RNG_Abstract(parent)
|
||||||
{
|
{
|
||||||
// initialize the random number generator with a 32bit integer seed (timestamp)
|
// initialize the random number generator with a 64bit seed, e.g. from a CSPRNG
|
||||||
sfmt_init_gen_rand(&sfmt, QDateTime::currentDateTime().toSecsSinceEpoch());
|
uint32_t seedArray[2] = {static_cast<uint32_t>(seed), static_cast<uint32_t>(seed >> 32)};
|
||||||
|
sfmt_init_by_array(&sfmt, seedArray, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ private:
|
||||||
unsigned int cdf(unsigned int min, unsigned int max);
|
unsigned int cdf(unsigned int min, unsigned int max);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit RNG_SFMT(QObject *parent = nullptr);
|
explicit RNG_SFMT(uint64_t seed, QObject *parent = nullptr);
|
||||||
unsigned int rand(int min, int max) override;
|
unsigned int rand(int min, int max) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,15 @@ set(CMAKE_AUTOUIC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
set(UTILITY_SOURCES
|
set(UTILITY_SOURCES
|
||||||
libcockatrice/utility/expression.cpp libcockatrice/utility/levenshtein.cpp libcockatrice/utility/passwordhasher.cpp
|
libcockatrice/utility/cryptoutil.cpp libcockatrice/utility/expression.cpp libcockatrice/utility/levenshtein.cpp
|
||||||
libcockatrice/utility/server_rate_limiter.cpp libcockatrice/utility/warning_categories.cpp
|
libcockatrice/utility/passwordhasher.cpp libcockatrice/utility/server_rate_limiter.cpp
|
||||||
|
libcockatrice/utility/warning_categories.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(UTILITY_HEADERS
|
set(UTILITY_HEADERS
|
||||||
libcockatrice/utility/card_ref.h
|
libcockatrice/utility/card_ref.h
|
||||||
libcockatrice/utility/color.h
|
libcockatrice/utility/color.h
|
||||||
|
libcockatrice/utility/cryptoutil.h
|
||||||
libcockatrice/utility/expression.h
|
libcockatrice/utility/expression.h
|
||||||
libcockatrice/utility/levenshtein.h
|
libcockatrice/utility/levenshtein.h
|
||||||
libcockatrice/utility/macros.h
|
libcockatrice/utility/macros.h
|
||||||
|
|
@ -32,7 +34,9 @@ add_library(libcockatrice_utility STATIC ${UTILITY_SOURCES} ${UTILITY_HEADERS})
|
||||||
|
|
||||||
target_include_directories(libcockatrice_utility PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(libcockatrice_utility PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
target_link_libraries(libcockatrice_utility PUBLIC libcockatrice_rng ${QT_CORE_MODULE})
|
find_package(OpenSSL REQUIRED)
|
||||||
|
|
||||||
|
target_link_libraries(libcockatrice_utility PUBLIC libcockatrice_rng OpenSSL::Crypto ${QT_CORE_MODULE})
|
||||||
|
|
||||||
set(ORACLE_LIBS)
|
set(ORACLE_LIBS)
|
||||||
|
|
||||||
|
|
|
||||||
25
libcockatrice_utility/libcockatrice/utility/cryptoutil.cpp
Normal file
25
libcockatrice_utility/libcockatrice/utility/cryptoutil.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include "cryptoutil.h"
|
||||||
|
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
|
namespace CryptoUtil
|
||||||
|
{
|
||||||
|
QByteArray randomBytes(int count)
|
||||||
|
{
|
||||||
|
QByteArray bytes(count, '\0');
|
||||||
|
if (RAND_bytes(reinterpret_cast<unsigned char *>(bytes.data()), count) != 1) {
|
||||||
|
// Randomness failure is fatal: never fall back to a predictable source.
|
||||||
|
qFatal("CryptoUtil::randomBytes: RAND_bytes failed");
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 randomUInt64()
|
||||||
|
{
|
||||||
|
quint64 value;
|
||||||
|
if (RAND_bytes(reinterpret_cast<unsigned char *>(&value), sizeof(value)) != 1) {
|
||||||
|
qFatal("CryptoUtil::randomUInt64: RAND_bytes failed");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
} // namespace CryptoUtil
|
||||||
13
libcockatrice_utility/libcockatrice/utility/cryptoutil.h
Normal file
13
libcockatrice_utility/libcockatrice/utility/cryptoutil.h
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef CRYPTOUTIL_H
|
||||||
|
#define CRYPTOUTIL_H
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
namespace CryptoUtil
|
||||||
|
{
|
||||||
|
QByteArray randomBytes(int count);
|
||||||
|
quint64 randomUInt64();
|
||||||
|
} // namespace CryptoUtil
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include "passwordhasher.h"
|
#include "passwordhasher.h"
|
||||||
|
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <libcockatrice/rng/rng_sfmt.h>
|
#include <libcockatrice/utility/cryptoutil.h>
|
||||||
|
|
||||||
QString PasswordHasher::computeHash(const QString &password, const QString &salt)
|
QString PasswordHasher::computeHash(const QString &password, const QString &salt)
|
||||||
{
|
{
|
||||||
|
|
@ -21,12 +21,28 @@ QString PasswordHasher::generateRandomSalt(const int len)
|
||||||
static const char alphanum[] = "0123456789"
|
static const char alphanum[] = "0123456789"
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
"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;
|
QString ret;
|
||||||
int size = sizeof(alphanum) - 1;
|
ret.reserve(len);
|
||||||
|
QByteArray random = CryptoUtil::randomBytes(len * 2);
|
||||||
|
int bytesUsed = 0;
|
||||||
for (int i = 0; i < len; ++i) {
|
for (int i = 0; i < len; ++i) {
|
||||||
ret.append(alphanum[rng->rand(0, size)]);
|
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;
|
return ret;
|
||||||
|
|
@ -34,5 +50,5 @@ QString PasswordHasher::generateRandomSalt(const int len)
|
||||||
|
|
||||||
QString PasswordHasher::generateActivationToken()
|
QString PasswordHasher::generateActivationToken()
|
||||||
{
|
{
|
||||||
return QCryptographicHash::hash(generateRandomSalt().toUtf8(), QCryptographicHash::Md5).toBase64().left(16);
|
return QString(CryptoUtil::randomBytes(16).toBase64().left(16));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <libcockatrice/rng/rng_sfmt.h>
|
#include <libcockatrice/rng/rng_sfmt.h>
|
||||||
|
#include <libcockatrice/utility/cryptoutil.h>
|
||||||
#include <libcockatrice/utility/passwordhasher.h>
|
#include <libcockatrice/utility/passwordhasher.h>
|
||||||
|
|
||||||
RNG_Abstract *rng;
|
RNG_Abstract *rng;
|
||||||
|
|
@ -169,7 +170,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
signalhandler = new SignalHandler();
|
signalhandler = new SignalHandler();
|
||||||
|
|
||||||
rng = new RNG_SFMT;
|
rng = new RNG_SFMT(CryptoUtil::randomUInt64());
|
||||||
|
|
||||||
std::cerr << "Servatrice " << VERSION_STRING << " starting." << std::endl;
|
std::cerr << "Servatrice " << VERSION_STRING << " starting." << std::endl;
|
||||||
std::cerr << "-------------------------" << std::endl;
|
std::cerr << "-------------------------" << std::endl;
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,9 @@
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include <libcockatrice/rng/rng_abstract.h>
|
#include <cstring>
|
||||||
#include <libcockatrice/rng/rng_sfmt.h>
|
|
||||||
#include <libcockatrice/utility/passwordhasher.h>
|
#include <libcockatrice/utility/passwordhasher.h>
|
||||||
|
|
||||||
RNG_Abstract *rng;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class PasswordHashTest : public ::testing::Test
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
void SetUp() override
|
|
||||||
{
|
|
||||||
rng = new RNG_SFMT;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown() override
|
|
||||||
{
|
|
||||||
delete rng;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(PasswordHashTest, RegressionTest)
|
TEST(PasswordHashTest, RegressionTest)
|
||||||
{
|
{
|
||||||
|
|
@ -29,6 +13,29 @@ TEST(PasswordHashTest, RegressionTest)
|
||||||
QString hash = PasswordHasher::computeHash(password, salt);
|
QString hash = PasswordHasher::computeHash(password, salt);
|
||||||
ASSERT_EQ(hash, salt + expected) << "The computed hash value remains the same";
|
ASSERT_EQ(hash, salt + expected) << "The computed hash value remains the same";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(PasswordHashTest, SaltUsesAlphanumericCharset)
|
||||||
|
{
|
||||||
|
static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
|
const QString salt = PasswordHasher::generateRandomSalt();
|
||||||
|
ASSERT_EQ(salt.size(), 16);
|
||||||
|
for (const QChar &c : salt) {
|
||||||
|
ASSERT_NE(strchr(alphanum, c.toLatin1()), nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PasswordHashTest, SaltsAreUnique)
|
||||||
|
{
|
||||||
|
const QString salt1 = PasswordHasher::generateRandomSalt();
|
||||||
|
const QString salt2 = PasswordHasher::generateRandomSalt();
|
||||||
|
ASSERT_NE(salt1, salt2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PasswordHashTest, TokenHasExpectedLength)
|
||||||
|
{
|
||||||
|
const QString token = PasswordHasher::generateActivationToken();
|
||||||
|
ASSERT_EQ(token.size(), 16);
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue