1
0
This commit is contained in:
Sytnyk Yehor
2025-05-15 13:11:19 +03:00
parent 4c01c2fe11
commit 9fb9f66f27
26 changed files with 730 additions and 0 deletions

View File

@ -0,0 +1,17 @@
CompileFlags:
Add: [-Wall, -Wextra, -std=c++23, -DBUILD_SHARED]
CompilationDatabase: build/
Diagnostics:
UnusedIncludes: Strict
InlayHints:
Enabled: Yes
ParameterNames: Yes
DeducedTypes: Yes
Index:
Background: Build
Hover:
ShowAKA: Yes

View File

@ -0,0 +1,15 @@
CXX := clang++
CXXFLAGS := -std=c++23 -Iinclude -Wall -Wextra
LDFLAGS := -lcrypto
TARGET := build/app
SRC := main.cpp
.PHONY: all clean
all:
@mkdir -p $(dir $(TARGET))
@$(CXX) $(CXXFLAGS) $(SRC) -o $(TARGET) $(LDFLAGS)
clean:
rm -rf build

View File

@ -0,0 +1,37 @@
#pragma once
#ifndef CACHE_LRU_HPP
#define CACHE_LRU_HPP
#include <cstdint>
#include <list>
#include <unordered_map>
#include <vector>
namespace cache {
class lru {
public:
lru(int32_t line_count, int32_t associativity);
~lru() = default;
bool access(uint64_t address);
private:
struct block_entry {
uint64_t tag;
};
int32_t _lines;
int32_t _assoc;
std::vector<std::list<block_entry>> _cache_lines;
std::vector<std::unordered_map<uint64_t, std::list<block_entry>::iterator>>
_lookup;
};
} // namespace cache
#include "../src/cache.cpp"
#endif

View File

@ -0,0 +1,84 @@
#pragma once
#ifndef SEC_LOCKED_BUFFER_HPP
#define SEC_LOCKED_BUFFER_HPP
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <sys/mman.h>
#include <unistd.h>
namespace sec {
template <typename T, std::size_t N> class locked_buffer {
public:
locked_buffer() {
this->size_ = N * sizeof(T);
this->ptr_ = static_cast<T *>(std::malloc(this->size_));
if (!this->ptr_)
throw std::bad_alloc();
if (mlock(this->ptr_, this->size_) != 0) {
std::free(this->ptr_);
throw std::runtime_error("mlock failed");
}
}
~locked_buffer() noexcept {
cleanse();
if (this->ptr_) {
munlock(this->ptr_, this->size_);
std::free(this->ptr_);
}
}
locked_buffer(const locked_buffer &) = delete;
locked_buffer &operator=(const locked_buffer &) = delete;
locked_buffer(locked_buffer &&other) noexcept
: ptr_(other.ptr_), size_(other.size_) {
other.ptr_ = nullptr;
other.size_ = 0;
}
locked_buffer &operator=(locked_buffer &&other) noexcept {
if (this != &other) {
cleanse();
if (this->ptr_) {
munlock(this->ptr_, this->size_);
std::free(this->ptr_);
}
this->ptr_ = other.ptr_;
this->size_ = other.size_;
other.ptr_ = nullptr;
other.size_ = 0;
}
return *this;
}
T *data() noexcept { return this->ptr_; }
const T *data() const noexcept { return this->ptr_; }
std::size_t size() const noexcept { return N; }
T &operator[](std::size_t i) { return this->ptr_[i]; }
const T &operator[](std::size_t i) const { return this->ptr_[i]; }
T *begin() noexcept { return this->ptr_; }
T *end() noexcept { return this->ptr_ + N; }
const T *begin() const noexcept { return this->ptr_; }
const T *end() const noexcept { return this->ptr_ + N; }
private:
void cleanse() noexcept {
if (this->ptr_) {
std::memset(this->ptr_, 0, this->size_);
}
}
T *ptr_{nullptr};
std::size_t size_{0};
};
} // namespace sec
#endif

View File

@ -0,0 +1,44 @@
#pragma once
#ifndef PAGE_REPLACEMENT_HPP
#define PAGE_REPLACEMENT_HPP
#include <cstdint>
#include <vector>
namespace paging {
class replacer {
public:
explicit replacer(int32_t frame_count) : _frames(frame_count) {}
virtual ~replacer() = default;
virtual int32_t run(const std::vector<int32_t> &pages) = 0;
protected:
int32_t _frames;
};
class optimal_replacer : public replacer {
public:
using replacer::replacer;
int32_t run(const std::vector<int32_t> &pages) override;
};
class clock_replacer : public replacer {
public:
using replacer::replacer;
int32_t run(const std::vector<int32_t> &pages) override;
};
class lru_replacer : public replacer {
public:
using replacer::replacer;
int32_t run(const std::vector<int32_t> &pages) override;
};
} // namespace paging
#include "../src/paging.cpp"
#endif

View File

@ -0,0 +1,68 @@
#pragma once
#ifndef PASSWORD_HPP
#define PASSWORD_HPP
#include <cstdint>
#include <string>
#include <string_view>
#include "locked_buffer.hpp"
namespace sec {
enum class strength_t : uint8_t {
very_weak = 0,
weak,
moderate,
strong,
very_strong
};
class password_hash;
class password {
public:
explicit password(std::string pass);
std::string_view view() const noexcept;
static sec::password from_console();
static sec::password from_string(const std::string &pass);
sec::password_hash to_hash() const;
private:
sec::locked_buffer<char, 128> _buf;
std::size_t _len{};
};
class password_hash {
public:
explicit password_hash(std::string hash);
const std::string &get() const noexcept;
bool verify(const sec::password &pwd) const;
private:
std::string _hash;
};
class manager {
public:
static bool has_lower(const sec::password &pwd);
static bool has_upper(const sec::password &pwd);
static bool has_digit(const sec::password &pwd);
static bool has_spec_symbol(const sec::password &pwd);
static std::string hash_password(const sec::password &pwd);
static sec::strength_t evaluate_strength(const sec::password &pwd);
static uint64_t time_to_crack(const sec::password &pwd);
static std::string format_duration(uint64_t seconds);
};
} // namespace sec
#include "../src/password.cpp"
#endif

View File

@ -0,0 +1,73 @@
#include <iostream>
#include <print>
#include <vector>
#include "include/cache.hpp"
#include "include/paging.hpp"
#include "include/password.hpp"
#include <openssl/sha.h>
int main() {
std::vector<int> pages = {7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3};
int frames = 3;
paging::optimal_replacer opt(frames);
paging::clock_replacer clk(frames);
paging::lru_replacer lru(frames);
std::println("Optimal faults: {}", opt.run(pages));
std::println("Clock faults: {}", clk.run(pages));
std::println("LRU faults: {}", lru.run(pages));
std::println("\nCache LRU Simulation:");
cache::lru cache(128, 4);
std::vector<uint64_t> addresses = {
0, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192,
};
int32_t hits = 0, misses = 0;
for (auto addr : addresses) {
if (cache.access(addr)) {
++hits;
std::println("Address 0x{:x}:\t HIT", addr);
} else {
++misses;
std::println("Address 0x{:x}:\t MISS", addr);
}
}
std::println("Hits: {}, Misses: {}\n", hits, misses);
auto pwd = sec::password::from_console();
auto strength = sec::manager::evaluate_strength(pwd);
auto crack_time = sec::manager::time_to_crack(pwd);
auto crack_str = sec::manager::format_duration(crack_time);
std::print("Password strength: ");
switch (strength) {
case sec::strength_t::very_weak:
std::print("Very Weak");
break;
case sec::strength_t::weak:
std::print("Weak");
break;
case sec::strength_t::moderate:
std::print("Moderate");
break;
case sec::strength_t::strong:
std::print("Strong");
break;
case sec::strength_t::very_strong:
std::print("Very Strong");
break;
}
std::print("\nEstimated time to crack: {} secs\n({})\n", crack_time,
crack_str);
std::string input;
std::print("\nEnter password to verify: ");
std::getline(std::cin, input);
auto input_pwd = sec::password::from_string(input);
if (pwd.to_hash().verify(input_pwd)) {
std::print("Password verified successfully.\n");
}
}

View File

@ -0,0 +1,38 @@
#pragma once
#include "../include/cache.hpp"
#include <cmath>
namespace cache {
cache::lru::lru(int32_t line_count, int32_t associativity)
: _lines(line_count), _assoc(associativity), _cache_lines(line_count),
_lookup(line_count) {}
bool cache::lru::access(uint64_t address) {
uint64_t line = (address >> 6) % this->_lines;
uint64_t tag =
address >> (6 + static_cast<uint64_t>(std::log2(this->_lines)));
auto &line_list = this->_cache_lines[line];
auto &line_map = this->_lookup[line];
auto it = line_map.find(tag);
if (it != line_map.end()) {
line_list.splice(line_list.begin(), line_list, it->second);
line_map[tag] = line_list.begin();
return true;
}
if (static_cast<int32_t>(line_list.size()) >= this->_assoc) {
auto last = line_list.back();
line_map.erase(last.tag);
line_list.pop_back();
}
line_list.push_front({tag});
line_map[tag] = line_list.begin();
return false;
}
} // namespace cache

View File

@ -0,0 +1,115 @@
#pragma once
#include "../include/paging.hpp"
#include <algorithm>
#include <limits>
#include <ranges>
#include <unordered_map>
namespace paging {
int32_t paging::optimal_replacer::run(const std::vector<int32_t> &pages) {
int32_t faults = 0;
std::vector<int32_t> frames;
frames.reserve(static_cast<size_t>(this->_frames));
for (size_t i : std::views::iota(size_t(0), pages.size())) {
int32_t p = pages[i];
if (std::find(frames.begin(), frames.end(), p) != frames.end())
continue;
++faults;
if (static_cast<int32_t>(frames.size()) < this->_frames) {
frames.push_back(p);
} else {
int32_t idx_to_replace = 0;
size_t farthest = 0;
for (int32_t j : std::views::iota(0, this->_frames)) {
size_t k = i + 1;
while (k < pages.size() && pages[k] != frames[j])
++k;
size_t dist =
(k < pages.size() ? k : std::numeric_limits<size_t>::max());
if (dist > farthest) {
farthest = dist;
idx_to_replace = j;
}
}
frames[idx_to_replace] = p;
}
}
return faults;
}
int32_t paging::clock_replacer::run(const std::vector<int32_t> &pages) {
int32_t faults = 0;
struct entry {
int32_t page;
bool ref;
};
std::vector<entry> frames;
frames.reserve(static_cast<size_t>(this->_frames));
int32_t hand = 0;
for (int32_t p : pages) {
bool hit = false;
for (auto &e : frames) {
if (e.page == p) {
e.ref = true;
hit = true;
break;
}
}
if (hit)
continue;
++faults;
if (static_cast<int32_t>(frames.size()) < this->_frames) {
frames.push_back({p, true});
} else {
while (true) {
if (!frames[hand].ref) {
frames[hand] = {p, true};
hand = (hand + 1) % this->_frames;
break;
}
frames[hand].ref = false;
hand = (hand + 1) % this->_frames;
}
}
}
return faults;
}
int32_t paging::lru_replacer::run(const std::vector<int32_t> &pages) {
int32_t faults = 0;
std::vector<int32_t> frames;
std::unordered_map<int32_t, int32_t> last_used;
frames.reserve(static_cast<size_t>(this->_frames));
for (int32_t i : std::views::iota(0, static_cast<int32_t>(pages.size()))) {
int32_t p = pages[i];
if (std::find(frames.begin(), frames.end(), p) != frames.end()) {
last_used[p] = i;
continue;
}
++faults;
if (static_cast<int32_t>(frames.size()) < this->_frames) {
frames.push_back(p);
} else {
int32_t lru_page = frames[0];
int32_t min_idx = last_used[lru_page];
for (int32_t q : frames) {
if (last_used[q] < min_idx) {
min_idx = last_used[q];
lru_page = q;
}
}
auto it = std::find(frames.begin(), frames.end(), lru_page);
if (it != frames.end())
*it = p;
}
last_used[p] = i;
}
return faults;
}
} // namespace paging

View File

@ -0,0 +1,151 @@
#pragma once
#include "../include/password.hpp"
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <openssl/sha.h>
#include <print>
#include <ranges>
#include <sstream>
namespace sec {
sec::password::password(std::string pass) {
if (pass.size() > _buf.size()) {
throw std::length_error("Password too long");
}
_len = pass.size();
std::copy(pass.data(), pass.data() + _len, _buf.begin());
}
std::string_view sec::password::view() const noexcept {
return std::string_view(_buf.data(), _len);
}
sec::password sec::password::from_console() {
std::string p1, p2;
while (true) {
std::print("Enter password: ");
std::getline(std::cin, p1);
std::print("Re-enter password: ");
std::getline(std::cin, p2);
if (p1 != p2) {
std::print("Passwords do not match. Try again.\n");
continue;
}
if (sec::manager::evaluate_strength(sec::password(p1)) ==
sec::strength_t::very_weak) {
std::print("Password is too weak. Try again.\n");
continue;
}
break;
}
return sec::password(p1);
}
sec::password sec::password::from_string(const std::string &pass) {
if (sec::manager::evaluate_strength(sec::password(pass)) ==
sec::strength_t::very_weak) {
std::print("Password is too weak. Try again.\n\n");
throw std::invalid_argument("Weak password");
}
return sec::password(pass);
}
sec::password_hash::password_hash(std::string hash) : _hash(std::move(hash)) {}
const std::string &sec::password_hash::get() const noexcept { return _hash; }
bool sec::password_hash::verify(const sec::password &pwd) const {
return sec::manager::hash_password(pwd) == _hash;
}
sec::password_hash sec::password::to_hash() const {
return sec::password_hash(sec::manager::hash_password(*this));
}
bool sec::manager::has_lower(const sec::password &pwd) {
auto sv = pwd.view();
return std::any_of(sv.begin(), sv.end(), ::islower);
}
bool sec::manager::has_upper(const sec::password &pwd) {
auto sv = pwd.view();
return std::any_of(sv.begin(), sv.end(), ::isupper);
}
bool sec::manager::has_digit(const sec::password &pwd) {
auto sv = pwd.view();
return std::any_of(sv.begin(), sv.end(), ::isdigit);
}
bool sec::manager::has_spec_symbol(const sec::password &pwd) {
auto sv = pwd.view();
return std::any_of(sv.begin(), sv.end(),
[](unsigned char c) { return std::ispunct(c); });
}
sec::strength_t sec::manager::evaluate_strength(const sec::password &pwd) {
uint8_t score = 0;
if (has_lower(pwd))
++score;
if (has_upper(pwd))
++score;
if (has_digit(pwd))
++score;
if (has_spec_symbol(pwd))
++score;
if (pwd.view().size() >= 8)
++score;
if (score != 0)
score--;
uint8_t max_val = static_cast<uint8_t>(sec::strength_t::very_strong);
uint8_t idx = std::min(score, max_val);
return static_cast<sec::strength_t>(idx);
}
uint64_t sec::manager::time_to_crack(const sec::password &pwd) {
auto sv = pwd.view();
if (sv.empty())
return 0;
int charset = (has_lower(pwd) ? 26 : 0) + (has_upper(pwd) ? 26 : 0) +
(has_digit(pwd) ? 10 : 0) + (has_spec_symbol(pwd) ? 33 : 0);
constexpr double RATE = 1e7;
double combos = std::pow(static_cast<double>(charset), sv.size());
return static_cast<uint64_t>(combos / 2.0 / RATE);
}
std::string sec::manager::format_duration(uint64_t seconds) {
const uint64_t u[] = {31536000, 2592000, 86400, 3600, 60, 1};
const char *lbl[] = {"years", "months", "days", "hours", "mins", "secs"};
std::string s;
for (int i : std::views::iota(0, 6)) {
uint64_t v = seconds / u[i];
if (v) {
s += std::to_string(v) + " " + lbl[i] + ((i == 5) ? "" : " ");
seconds %= u[i];
}
}
return s.empty() ? "0 secs" : s;
}
std::string sec::manager::hash_password(const sec::password &pwd) {
auto sv = pwd.view();
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char *>(sv.data()), sv.size(), hash);
std::ostringstream oss;
for (int32_t i : std::views::iota(0, SHA256_DIGEST_LENGTH)) {
oss << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int32_t>(hash[i]);
}
return oss.str();
}
} // namespace sec