added password hash
This commit is contained in:
parent
16a8b446ed
commit
8097895361
@ -45,6 +45,7 @@ include_directories(
|
|||||||
add_executable(${TARGET_NAME}
|
add_executable(${TARGET_NAME}
|
||||||
# sqlite3
|
# sqlite3
|
||||||
modules/cpp-libraries/src/sqlite3.c
|
modules/cpp-libraries/src/sqlite3.c
|
||||||
|
modules/cpp-libraries/src/monocypher.c
|
||||||
|
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/utils.hpp
|
src/utils.hpp
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit 6f1d51cabccb8b2758de2441be0efa907d8b10f9
|
Subproject commit 70b723bfc10ae6988725ea55cc97ba508ba00892
|
||||||
@ -87,7 +87,8 @@ inline auto make_database() {
|
|||||||
auto storage = sqlite_orm::make_storage(Database::dbFile,
|
auto storage = sqlite_orm::make_storage(Database::dbFile,
|
||||||
sqlite_orm::make_table("users",
|
sqlite_orm::make_table("users",
|
||||||
sqlite_orm::make_column("id", &login::User::id, sqlite_orm::primary_key()),
|
sqlite_orm::make_column("id", &login::User::id, sqlite_orm::primary_key()),
|
||||||
sqlite_orm::make_column("username", &login::User::username, sqlite_orm::not_null()),
|
sqlite_orm::make_column("username", &login::User::username, sqlite_orm::unique() ),
|
||||||
|
sqlite_orm::make_column("salt", &login::User::salt, sqlite_orm::not_null()),
|
||||||
sqlite_orm::make_column("password_hash", &login::User::password_hash, sqlite_orm::not_null()),
|
sqlite_orm::make_column("password_hash", &login::User::password_hash, sqlite_orm::not_null()),
|
||||||
sqlite_orm::make_column("created_at", &login::User::created_at, sqlite_orm::default_value("CURRENT_TIMESTAMP"))
|
sqlite_orm::make_column("created_at", &login::User::created_at, sqlite_orm::default_value("CURRENT_TIMESTAMP"))
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,38 +1,14 @@
|
|||||||
#include <sodium.h>
|
|
||||||
#include "login.hpp"
|
#include "login.hpp"
|
||||||
#include "crow/http_response.h"
|
#include "crow/http_response.h"
|
||||||
#include "databasepool.h"
|
#include "databasepool.h"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include "SessionHandler.hpp"
|
#include "SessionHandler.hpp"
|
||||||
|
|
||||||
namespace login
|
namespace login
|
||||||
{
|
{
|
||||||
|
|
||||||
SessionHandler sessionHandler;
|
SessionHandler sessionHandler;
|
||||||
|
|
||||||
std::string hashPassword(const std::string& password)
|
|
||||||
{
|
|
||||||
// Allocate storage for the hash
|
|
||||||
char hash[crypto_pwhash_STRBYTES];
|
|
||||||
|
|
||||||
// Hash the password using Argon2id
|
|
||||||
if (crypto_pwhash_str(
|
|
||||||
hash,
|
|
||||||
password.c_str(),
|
|
||||||
password.size(),
|
|
||||||
crypto_pwhash_OPSLIMIT_INTERACTIVE,
|
|
||||||
crypto_pwhash_MEMLIMIT_INTERACTIVE
|
|
||||||
) != 0) {
|
|
||||||
CROW_LOG_ERROR << "Out of memory while hashing password!";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool verifyHashWithPassword(const std::string& hash, std::string const& password)
|
|
||||||
{
|
|
||||||
return crypto_pwhash_str_verify(hash.c_str(), password.c_str(), password.size()) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getSessionId(const crow::request& req) {
|
std::string getSessionId(const crow::request& req) {
|
||||||
auto cookie_header = req.get_header_value("Cookie");
|
auto cookie_header = req.get_header_value("Cookie");
|
||||||
std::string prefix = "session_id=";
|
std::string prefix = "session_id=";
|
||||||
@ -51,23 +27,15 @@ bool isLoggedIn(const crow::request& req) {
|
|||||||
|
|
||||||
std::optional<std::string> loginUser(const std::string& username, const std::string& password)
|
std::optional<std::string> loginUser(const std::string& username, const std::string& password)
|
||||||
{
|
{
|
||||||
auto user = getUser(username);
|
auto user = getVerifiedUser(username, password);
|
||||||
if (user.has_value()) {
|
if (user.has_value()) {
|
||||||
if (verifyHashWithPassword(user.value().password_hash, password))
|
|
||||||
{
|
|
||||||
return sessionHandler.createSession(user.value().id);
|
return sessionHandler.createSession(user.value().id);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool initLogin(crow::SimpleApp& app)
|
bool initLogin(crow::SimpleApp& app)
|
||||||
{
|
{
|
||||||
if (sodium_init() < 0) {
|
|
||||||
CROW_LOG_ERROR << "Failed to Init Sodium";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// createUser("lukas", "Trollar4928");
|
// createUser("lukas", "Trollar4928");
|
||||||
|
|
||||||
CROW_ROUTE(app, "/login").methods("POST"_method)
|
CROW_ROUTE(app, "/login").methods("POST"_method)
|
||||||
|
|||||||
@ -1,13 +1,60 @@
|
|||||||
#include "loginDb.hpp"
|
#include "loginDb.hpp"
|
||||||
#include "databasepool.h"
|
#include "databasepool.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
extern "C" {
|
||||||
|
#include "monocypher.h"
|
||||||
|
}
|
||||||
using namespace sqlite_orm;
|
using namespace sqlite_orm;
|
||||||
|
|
||||||
namespace login {
|
namespace login {
|
||||||
|
|
||||||
int createUser(const std::string& username, const std::string& password_hash){
|
constexpr uint32_t SALT_SIZE = 16;
|
||||||
if (username.empty() || password_hash.empty())
|
constexpr uint32_t PASSWORD_HASH_SIZE = 32;
|
||||||
|
|
||||||
|
static std::vector<char> getPasswordHash(const std::vector<char>& salt, const std::string password){
|
||||||
|
std::vector<char> password_hash;
|
||||||
|
password_hash.resize(PASSWORD_HASH_SIZE);
|
||||||
|
|
||||||
|
crypto_argon2_config config = {
|
||||||
|
.algorithm = CRYPTO_ARGON2_I, /* Argon2i */
|
||||||
|
.nb_blocks = 100000, /* 100 megabytes */
|
||||||
|
.nb_passes = 3, /* 3 iterations */
|
||||||
|
.nb_lanes = 1 /* Single-threaded */
|
||||||
|
};
|
||||||
|
crypto_argon2_inputs inputs = {
|
||||||
|
.pass = (uint8_t*)(password.data()), /* User password */
|
||||||
|
.salt = (uint8_t*)salt.data(), /* Salt for the password */
|
||||||
|
.pass_size = static_cast<uint32_t>(password.size()), /* Password length */
|
||||||
|
.salt_size = 16
|
||||||
|
};
|
||||||
|
crypto_argon2_extras extras = {0}; /* Extra parameters unused */
|
||||||
|
|
||||||
|
void *work_area = malloc((size_t)config.nb_blocks * 1024);
|
||||||
|
crypto_argon2((uint8_t*)password_hash.data(), PASSWORD_HASH_SIZE, work_area,
|
||||||
|
config, inputs, extras);
|
||||||
|
free(work_area);
|
||||||
|
return password_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void createPasswordHash(User& user, const std::string password){
|
||||||
|
user.salt.resize(SALT_SIZE);
|
||||||
|
user.password_hash.resize(PASSWORD_HASH_SIZE);
|
||||||
|
|
||||||
|
arc4random_buf(user.salt.data(), SALT_SIZE);
|
||||||
|
user.password_hash = getPasswordHash(user.salt, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool verifyUser(const User& user, std::string const& password)
|
||||||
|
{
|
||||||
|
const auto hash = getPasswordHash(user.salt, password);
|
||||||
|
return crypto_verify32((uint8_t*)hash.data(), (uint8_t*)user.password_hash.data()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int createUser(const std::string& username, const std::string& password){
|
||||||
|
if (username.empty() || password.empty())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int64_t id;
|
int64_t id;
|
||||||
@ -20,8 +67,9 @@ int createUser(const std::string& username, const std::string& password_hash){
|
|||||||
if (user.has_value()) {
|
if (user.has_value()) {
|
||||||
id = user.value().id;
|
id = user.value().id;
|
||||||
} else {
|
} else {
|
||||||
auto c = newUser(username, password_hash);
|
User usr = newUser(username);
|
||||||
id = db->insert(c);
|
createPasswordHash(usr, password);
|
||||||
|
id = db->insert(usr);
|
||||||
}
|
}
|
||||||
dbpool.release(db);
|
dbpool.release(db);
|
||||||
return id;
|
return id;
|
||||||
@ -35,4 +83,16 @@ std::optional<User> getUser(const std::string& username){
|
|||||||
dbpool.release(db);
|
dbpool.release(db);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<User> getVerifiedUser(const std::string& username, const std::string& password){
|
||||||
|
auto user = getUser(username);
|
||||||
|
if (!user.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (verifyUser(user.value(), password)){
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -16,19 +16,20 @@ namespace login
|
|||||||
struct User {
|
struct User {
|
||||||
int id;
|
int id;
|
||||||
std::string username;
|
std::string username;
|
||||||
std::string password_hash;
|
std::vector<char> salt;
|
||||||
|
std::vector<char> password_hash;
|
||||||
std::string last_login;
|
std::string last_login;
|
||||||
std::string created_at; // SQLite stores DATETIME as TEXT
|
std::string created_at; // SQLite stores DATETIME as TEXT
|
||||||
};
|
};
|
||||||
|
|
||||||
inline User newUser(const std::string& username, std::string password_hash){
|
inline User newUser(const std::string& username){
|
||||||
return User {-1, username, password_hash, utils::currentTime(), utils::currentTime()};
|
return User {-1, username, {}, {}, utils::currentTime(), utils::currentTime()};
|
||||||
}
|
}
|
||||||
|
|
||||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(User, id, username, password_hash, last_login, created_at)
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(User, id, username, salt, password_hash, last_login, created_at)
|
||||||
|
|
||||||
int createUser(const std::string& username, const std::string& password_hash);
|
int createUser(const std::string& username, const std::string& password);
|
||||||
std::optional<User> getUser(const std::string& username);
|
std::optional<User> getUser(const std::string& username);
|
||||||
|
std::optional<User> getVerifiedUser(const std::string& username, const std::string& password);
|
||||||
}
|
}
|
||||||
#endif // __LOGINDB_H__
|
#endif // __LOGINDB_H__
|
||||||
Loading…
x
Reference in New Issue
Block a user