OS lb-6
7
semester-4/ОС/lb-6/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
> [!NOTE]
|
||||
> Викладач: Мельникова Р. В.
|
||||
>
|
||||
> Оцінка: -
|
||||
|
||||
> [!TIP]
|
||||
> Виконано для Linux в команді.
|
21
semester-4/ОС/lb-6/doc.yaml
Normal file
@ -0,0 +1,21 @@
|
||||
title: Керування пам'яттю. Частина 2
|
||||
subject: ОС
|
||||
doctype: ЛБ
|
||||
worknumber: 6
|
||||
mentors:
|
||||
- name: Мельнікова Р. В.,
|
||||
gender: f,
|
||||
degree: доц. каф. ПІ,
|
||||
edu_program: &EDU ПЗПІ
|
||||
university: ХНУРЕ
|
||||
authors:
|
||||
- name: Ситник Є. С.
|
||||
course: 2
|
||||
edu: *EDU
|
||||
gender: m
|
||||
group: 23-2
|
||||
- name: Малишкін. А. С.
|
||||
course: 2
|
||||
edu: *EDU
|
||||
gender: m
|
||||
group: 23-2
|
BIN
semester-4/ОС/lb-6/img/cache-lru.png
Normal file
After Width: | Height: | Size: 309 KiB |
BIN
semester-4/ОС/lb-6/img/cache-result.png
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
semester-4/ОС/lb-6/img/cache-test.png
Normal file
After Width: | Height: | Size: 248 KiB |
BIN
semester-4/ОС/lb-6/img/pages-clock.png
Normal file
After Width: | Height: | Size: 366 KiB |
BIN
semester-4/ОС/lb-6/img/pages-lru.png
Normal file
After Width: | Height: | Size: 410 KiB |
BIN
semester-4/ОС/lb-6/img/pages-optimal.png
Normal file
After Width: | Height: | Size: 398 KiB |
BIN
semester-4/ОС/lb-6/img/pages-result.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
semester-4/ОС/lb-6/img/pages-test.png
Normal file
After Width: | Height: | Size: 167 KiB |
BIN
semester-4/ОС/lb-6/img/pass-check.png
Normal file
After Width: | Height: | Size: 231 KiB |
BIN
semester-4/ОС/lb-6/img/pass-hash.png
Normal file
After Width: | Height: | Size: 213 KiB |
BIN
semester-4/ОС/lb-6/img/pass-lock.png
Normal file
After Width: | Height: | Size: 187 KiB |
BIN
semester-4/ОС/lb-6/img/pass-table.png
Normal file
After Width: | Height: | Size: 968 KiB |
17
semester-4/ОС/lb-6/src/.clangd
Normal 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
|
15
semester-4/ОС/lb-6/src/Makefile
Normal 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
|
37
semester-4/ОС/lb-6/src/include/cache.hpp
Normal 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
|
84
semester-4/ОС/lb-6/src/include/locked_buffer.hpp
Normal 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
|
44
semester-4/ОС/lb-6/src/include/paging.hpp
Normal 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
|
68
semester-4/ОС/lb-6/src/include/password.hpp
Normal 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
|
73
semester-4/ОС/lb-6/src/main.cpp
Normal 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");
|
||||
}
|
||||
}
|
38
semester-4/ОС/lb-6/src/src/cache.cpp
Normal 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
|
115
semester-4/ОС/lb-6/src/src/paging.cpp
Normal 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
|
151
semester-4/ОС/lb-6/src/src/password.cpp
Normal 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
|
BIN
semester-4/ОС/lb-6/Лр_6_Ситник_Малишкін_ПЗПІ_23_2.pdf
Normal file
60
semester-4/ОС/lb-6/Лр_6_Ситник_Малишкін_ПЗПІ_23_2.typ
Normal file
@ -0,0 +1,60 @@
|
||||
#import "@local/nure:0.1.0": *
|
||||
|
||||
#show: pz-lb.with(..yaml("doc.yaml"))
|
||||
|
||||
#v(-spacing)
|
||||
|
||||
== Мета роботи
|
||||
Вивчити особливості захисту критичних даних, використання динамічної та кеш пам'яті.
|
||||
|
||||
== Хід роботи
|
||||
#v(-spacing)
|
||||
=== Порівняти алгоритми заміщення сторінок (оптимальний, годинник, LRU).
|
||||
Заміщення сторінок - це процес, який використовується в операційних системах для керування віртуальною пам'яттю, коли фізичної пам'яті недостатньо. Коли потрібна сторінка, якої немає в оперативній пам'яті, операційна система вибирає одну зі сторінок, що вже знаходяться в пам'яті, і замінює її потрібною сторінкою.
|
||||
|
||||
Сучасні операційні системи використовують різні підходи для визначення сторінок, які можна замістити.
|
||||
|
||||
Розглянемо деякі алгоритми заміщення сторінок:
|
||||
+ оптимальний алгоритм (також відомий як алгоритм Беладі) -- теоретичний алгоритм, який досягає найменшої кількості промахів сторінок. Він працює, замінюючи сторінку, яка не буде використовуватися найдовший період часу в майбутньому. Хоча цей алгоритм є оптимальним, він не може бути реалізований на практиці, оскільки вимагає знання майбутньої послідовності звернень до сторінок;
|
||||
+ алгоритм годинник (також відомий як алгоритм "другого шансу") -- зберігає список сторінок у пам'яті, кожна з яких має біт використання. Коли відбувається промах сторінки і потрібно замінити сторінку, алгоритм перевіряє біт використання поточної сторінки, на яку вказує покажчик. Якщо біт використання дорівнює 1, він скидається до 0, і покажчик переміщується до наступної сторінки. Цей процес повторюється до тих пір, поки не буде знайдено сторінку з бітом використання, що дорівнює 0, яка і замінюється. Такий підхід надає "другий шанс" сторінкам, які нещодавно використовувалися, запобігаючи їхньому швидкому витісненню;
|
||||
+ алгоритм LRU (Least Recently Used) -- замінює сторінку, яка найдовше не використовувалася. Він базується на припущенні, що сторінки, які використовувалися нещодавно, ймовірно, будуть використовуватися знову в найближчому майбутньому, а ті, що давно не використовувалися, мають меншу ймовірність повторного звернення. Для реалізації LRU необхідно відстежувати час останнього звернення до кожної сторінки в пам'яті. Коли виникає потреба у заміщенні, вибирається сторінка з найдавнішим часом останнього використання.
|
||||
|
||||
#figure(image("img/pages-optimal.png", width: 90%), caption: [Оптимальний алгоритм заміщення сторінок])
|
||||
#figure(image("img/pages-clock.png", width: 100%), caption: [Алгоритм заміщення сторінок "Годинник"])
|
||||
#figure(image("img/pages-lru.png", width: 80%), caption: [Алгоритм заміщення сторінок "LRU"])
|
||||
|
||||
Протестуємо всі алгоритми із однаковими тестовими даними.
|
||||
|
||||
#figure(image("img/pages-test.png", width: 80%), caption: [Код тестування алгоритмів])
|
||||
|
||||
#figure(image("img/pages-result.png"), caption: [Результати тестування])
|
||||
|
||||
Можемо побачити, що оптимальний алгоритм показує найкращі результати.
|
||||
|
||||
=== Реалізувати алгоритм LRU для роботи з кешем для стандартних параметрів кешу
|
||||
Кешування - це техніка збереження часто використовуваних даних у швидшій пам'яті (кеші) для зменшення часу доступу. Оскільки кеш має обмежений розмір, при його заповненні виникає потреба у визначенні того, які дані слід видалити для звільнення місця для нових.
|
||||
|
||||
#figure(image("img/cache-lru.png", width: 87%), caption: [Алгоритм "LRU" для доступу до кешу])
|
||||
#figure(image("img/cache-test.png", width: 90%), caption: [Код тестування])
|
||||
#figure(image("img/cache-result.png", width: 45%), caption: [Результати тестування])
|
||||
|
||||
=== Реалізувати функції встановлення паролю та перевірки паролю. При складанні функцій забезпечте безпечне зберігання паролів.
|
||||
|
||||
Безпечність пароля можна визначити за часом, що потрібен для його зламу. Чим більше часу необхідно на злам, тим безпечніший пароль.
|
||||
#figure(
|
||||
image("img/pass-table.png", width: 70%),
|
||||
caption: [Таблиця відповідності складності паролю до часу, що необхідний на злам],
|
||||
)
|
||||
Критерії надійності паролю зазначені в таблиці детально обговорюються в дослідженні Hive Systems, яке оновлюється кожен рік починаючи з 2020 (#link("https://www.hivesystems.com/blog/are-your-passwords-in-the-green"))
|
||||
#figure(image("img/pass-check.png", width: 70%), caption: [Функція перевірки надійності пароля])
|
||||
|
||||
Для забезпечення безпеки пароля в пам'яті під час гешування було використано стандартні POSIX функції "mlock" та "munlock".
|
||||
#figure(image("img/pass-lock.png", width: 74%), caption: [Функції блокування та розблокування пам'яті])
|
||||
|
||||
Для гешування паролю ми використали алгоритм "SHA256" із бібліотеки "openssl", яка є стандартним вибором для всього, що так чи інакше пов'язано із криптографією.
|
||||
#figure(image("img/pass-hash.png", width: 74%), caption: [Функція гешування паролю])
|
||||
|
||||
== Висновки
|
||||
Під час даної лабораторної роботи ми вивчили особливості захисту критичних даних, використання динамічної та кеш пам'яті.
|
||||
|
||||
#show: appendices_style
|