添加 hash 加盐和验证功能
This commit is contained in:
parent
d3efc643f5
commit
9cc9b48c18
10
include/hash/hash.hpp
Normal file
10
include/hash/hash.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef HASH_HPP
|
||||
#define HASH_HPP
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
auto generate_hash(const std::string_view password, std::size_t rounds) -> std::string;
|
||||
auto validate_password(const std::string_view password, const std::string_view hash) -> bool;
|
||||
|
||||
#endif // HASH_HPP
|
@ -6,11 +6,11 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
char* create_token(const char* user, const char* secret);
|
||||
auto create_token(const char* user_id, const char* secret) noexcept -> char*;
|
||||
|
||||
char* get_payload(const char* token);
|
||||
auto get_payload(const char* token) noexcept -> char*;
|
||||
|
||||
int verify_token(const char* token, const char* secret);
|
||||
auto verify_token(const char* token, const char* secret) noexcept -> int;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
91
src/hash/hash.cpp
Normal file
91
src/hash/hash.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
#include <hash.hpp>
|
||||
|
||||
#include <cryptopp/algparam.h>
|
||||
#include <cryptopp/cryptlib.h>
|
||||
#include <cryptopp/filters.h>
|
||||
#include <cryptopp/hex.h>
|
||||
#include <cryptopp/modes.h>
|
||||
#include <cryptopp/osrng.h>
|
||||
#include <cryptopp/pwdbased.h>
|
||||
#include <cryptopp/sha.h>
|
||||
|
||||
#include <array>
|
||||
#include <format>
|
||||
#include <vector>
|
||||
|
||||
using namespace CryptoPP;
|
||||
|
||||
auto to_byte_ptr(auto* p) noexcept -> const byte*
|
||||
{
|
||||
return reinterpret_cast<const byte*>(p);
|
||||
}
|
||||
|
||||
auto generate_salt(size_t length = 16) -> std::string
|
||||
{
|
||||
auto prng = AutoSeededRandomPool{};
|
||||
auto salt = std::vector<byte>(length);
|
||||
prng.GenerateBlock(salt.data(), length);
|
||||
auto salt_str = std::string{};
|
||||
auto encoder = HexEncoder{new StringSink(salt_str)};
|
||||
encoder.Put(salt.data(), length);
|
||||
encoder.MessageEnd();
|
||||
return salt_str;
|
||||
}
|
||||
|
||||
auto hash_password_with_pbkdf2(const std::string_view password, const std::string_view salt, std::size_t iterations)
|
||||
-> std::string
|
||||
{
|
||||
auto decoded_salt = std::string{};
|
||||
auto decoder = HexDecoder{};
|
||||
decoder.Attach(new StringSink(decoded_salt));
|
||||
decoder.Put(to_byte_ptr(salt.data()), salt.size());
|
||||
decoder.MessageEnd();
|
||||
auto pbkdf2 = PKCS5_PBKDF2_HMAC<SHA256>{};
|
||||
auto derived_key = std::array<byte, SHA256::DIGESTSIZE>{};
|
||||
pbkdf2.DeriveKey(derived_key.data(),
|
||||
derived_key.size(),
|
||||
0,
|
||||
to_byte_ptr(password.data()),
|
||||
password.size(),
|
||||
to_byte_ptr(decoded_salt.data()),
|
||||
decoded_salt.size(),
|
||||
iterations,
|
||||
0);
|
||||
auto hashed_password = std::string{};
|
||||
auto encoder = HexEncoder{new StringSink(hashed_password)};
|
||||
encoder.Put(derived_key.data(), derived_key.size());
|
||||
encoder.MessageEnd();
|
||||
return hashed_password;
|
||||
}
|
||||
|
||||
auto generate_hash(const std::string_view password, std::size_t rounds) -> std::string
|
||||
{
|
||||
auto salt = generate_salt();
|
||||
auto hashed_password = hash_password_with_pbkdf2(password, salt, rounds);
|
||||
return std::format("{}${}${}", salt, rounds, hashed_password);
|
||||
}
|
||||
|
||||
auto validate_password(const std::string_view password, const std::string_view hash) -> bool
|
||||
{
|
||||
auto first_delimiter = hash.find('$');
|
||||
auto second_delimiter = hash.find('$', first_delimiter + 1);
|
||||
|
||||
if (first_delimiter == std::string::npos || second_delimiter == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto stored_salt = hash.substr(0, first_delimiter);
|
||||
auto stored_rounds = std::size_t{};
|
||||
{
|
||||
auto first = hash.data() + first_delimiter + 1;
|
||||
auto last = hash.data() + second_delimiter;
|
||||
auto [ptr, ec] = std::from_chars(first, last, stored_rounds);
|
||||
if (ec != std::errc{}) return false;
|
||||
}
|
||||
auto stored_hashed_password = hash.substr(second_delimiter + 1);
|
||||
|
||||
auto entered_hashed_password = hash_password_with_pbkdf2(password, stored_salt, stored_rounds);
|
||||
|
||||
return entered_hashed_password == stored_hashed_password;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ using namespace std::literals::chrono_literals;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
char* create_token(const char* user_id, const char* secret)
|
||||
auto create_token(const char* user_id, const char* secret) noexcept -> char*
|
||||
{
|
||||
auto token = jwt::create()
|
||||
.set_type("JWS")
|
||||
@ -21,14 +21,14 @@ extern "C"
|
||||
return strdup(token.c_str());
|
||||
}
|
||||
|
||||
char* get_payload(const char* token)
|
||||
auto get_payload(const char* token) noexcept -> char*
|
||||
{
|
||||
auto decoded_token = jwt::decode(token);
|
||||
auto payload = decoded_token.get_payload_claim("user_id").as_string();
|
||||
return strdup(payload.c_str());
|
||||
}
|
||||
|
||||
int verify_token(const char* token, const char* secret)
|
||||
auto verify_token(const char* token, const char* secret) noexcept -> int
|
||||
{
|
||||
try {
|
||||
auto decoded_token = jwt::decode(token);
|
||||
|
Loading…
Reference in New Issue
Block a user