1
0

Compare commits

..

3 Commits

Author SHA1 Message Date
Sytnyk Yehor
9fb9f66f27 OS lb-6 2025-05-15 13:11:19 +03:00
Sytnyk Yehor
4c01c2fe11 added pdfs to all OS labs 2025-05-15 13:10:01 +03:00
Sytnyk Yehor
dbea0e87fd added gitignore 2025-05-15 13:05:20 +03:00
36 changed files with 1429 additions and 3 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*build*

View File

@@ -1,4 +1,5 @@
#import "@local/nure:0.0.0": *
// #import "@local/nure:0.0.0": *
#import "lib.typ": *
#show: lab-pz-template.with(
doctype: "ЛБ",

View File

@@ -1,4 +1,5 @@
#import "@local/nure:0.0.0": *
// #import "@local/nure:0.0.0": *
#import "lib.typ": *
#show: lab-pz-template.with(
doctype: "ЛБ",

View File

@@ -0,0 +1,692 @@
// Academic aliases {{{1
/// subject abbreviations to full names
#let subjects = (
"БД": "Бази даних",
"ОПНJ": "Основи програмування на Java",
"ОС": "Операційні системи",
"ПП": "Проектний практикум",
"СПМ": "Скриптові мови програмування",
"Ф": "Філософія",
)
/// education program abbreviations to name & number
#let edu_programs = (
"ПЗПІ": (
name: "Інженерія програмного забезпечення",
number: 121, // TODO: ПЗПІ is "F2" now
),
)
// Template formatting functions {{{1
/// numberless heading
#let nheading(title) = heading(depth: 1, numbering: none, title)
/// fill horizontal space with a box and not an empty space
#let hfill(width) = box(width: width, repeat("")) // NOTE: This is a HAIR SPACE (U+200A), not a regular space
/// make underlined cell with filled value
#let uline(align: center, content) = underline[
#if align != left { hfill(1fr) }
#content
#if align != right { hfill(1fr) }
]
/// bold text
#let bold(content) = text(weight: "bold")[#content]
/// month name from its number
#let month_gen(month) = (
"січня",
"лютого",
"березня",
"квітня",
"травня",
"червня",
"липня",
"серпня",
"вересня",
"жовтня",
"листопада",
"грудня",
).at(month - 1)
// Helper functions {{{1
/// captioned image with label derived from path:
/// - "image.png" = @image
/// - "img/image.png" = @image
/// - "img/foo/image.png" = @foo_image
/// - "img/foo/foo_image.png" = @foo_image
/// the caption will be modified based on a conditional positional value:
/// - `none`: no change
/// - some value: "`caption` (за даними `value`)"
/// - no value: "`caption` (рисунок виконано самостійно)"
/// additional named arguments will be passed to original `image` function
#let img(path, caption, ..sink) = {
let parts = path.split(".").first().split("/")
let label_string = if parts.len() <= 2 or parts.at(-1).starts-with(parts.at(-2)) {
// ("image",), (_, "image") and (.., "img", "img_image")
parts.last()
} else {
// (.., "img", "image") = "img_image"
parts.at(-2) + "_" + parts.at(-1)
}.replace(" ", "_")
let caption = if sink.pos().len() == 0 {
caption + " (рисунок виконано самостійно)"
} else if sink.pos().first() == none {
caption
} else {
[#caption (за даними #sink.pos().first())]
}
[#figure(image(path, ..sink.named()), caption: caption) #label(label_string)]
}
// Styling {{{1
/// NOTE: may be wrong
#let ua_alpha_numbering = "абвгдежиклмнпрстуфхцшщюя".split("") // 0 = "", 1 = "а"
// general outlook {{{2
// spacing between lines
#let spacing = 0.95em
#let style(it) = {
set page(
paper: "a4",
margin: (top: 20mm, right: 10mm, bottom: 20mm, left: 25mm),
number-align: top + right,
numbering: (..numbers) => {
if numbers.pos().at(0) != 1 {
numbering("1", numbers.pos().at(0))
}
},
)
set text(font: ("Times New Roman", "Liberation Serif"), size: 14pt, hyphenate: false, lang: "uk")
set par(justify: true, first-line-indent: (amount: 1.25cm, all: true))
set underline(evade: false)
// set 1.5 line spacing
set block(spacing: spacing)
set par(spacing: spacing)
set par(leading: spacing)
// enums and lists {{{2
set enum(numbering: i => { ua_alpha_numbering.at(i) + ")" }, indent: 1.25cm, body-indent: 0.5cm)
show enum: it => {
set enum(indent: 0em, numbering: "1)")
it
}
set list(indent: 1.35cm, body-indent: 0.5cm, marker: [--])
// figures {{{2
show figure: it => {
v(spacing * 2, weak: true)
it
v(spacing * 2, weak: true)
}
set figure.caption(separator: [ -- ])
show figure.where(kind: table): set figure.caption(position: top)
show figure.caption.where(kind: table): set align(left)
// figure numbering
show heading.where(level: 1): it => {
counter(math.equation).update(0)
counter(figure.where(kind: image)).update(0)
counter(figure.where(kind: table)).update(0)
counter(figure.where(kind: raw)).update(0)
it
}
set math.equation(numbering: (..num) => numbering("(1.1)", counter(heading).get().at(0), num.pos().first()))
set figure(numbering: (..num) => numbering("1.1", counter(heading).get().at(0), num.pos().first()))
// appearance of references to images and tables {{{2
set ref(
supplement: it => {
if it == none or not it.has("kind") {
it
} else if it.kind == image {
"див. рис."
} else if it.kind == table {
"див. таблицю"
} else {
it
}
},
)
show ref: it => {
let el = it.element
if el == none or not el.has("kind") {
return it
}
if el.kind != image and el.kind != table {
return it
}
[(#it)]
}
// headings {{{2
set heading(numbering: "1.1")
show heading.where(level: 1): it => {
set align(center)
set text(size: 14pt, weight: "semibold")
pagebreak(weak: true)
upper(it)
v(spacing * 2, weak: true)
}
show heading.where(level: 2): it => {
set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[
#h(1.25cm)
#counter(heading).display(it.numbering)
#it.body
]
v(spacing * 2, weak: true)
}
show heading.where(level: 3): it => {
set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[
#h(1.25cm)
#counter(heading).display(it.numbering)
#it.body
]
v(spacing * 2, weak: true)
}
it
}
// Coursework template {{{1
/// DSTU 3008:2015 Template for NURE
/// -> content
/// - doc (content): Content to apply the template to.
/// - title (str): Title of the document.
/// - subject_shorthand (str): Subject short name.
/// - department_gen (str): Department name in genitive form.
/// - authors ((name: str, full_name_gen: str, variant: int, group: str, gender: str),): List of Authors dicts.
/// - mentors ((name: str, gender: str, degree: str),): List of mentors dicts.
/// - edu_program_shorthand (str): Education program shorthand.
/// - task_list (done_date: datetime, initial_date: datetime, source: (content | str), content: (content | str), graphics: (content | str)): Task list object.
/// - calendar_plan ( plan_table: (content | str), approval_date: datetime): Calendar plan object.
/// - abstract (keywords: (str, ), text: (content | str)): Abstract object.
/// - bib_path path: Path to the bibliography yaml file.
/// - appendices (content): Content with appendices.
#let cw-template(
doc,
title: "NONE",
subject_shorthand: "NONE",
department_gen: "Програмної інженерії",
author: (),
mentors: (),
edu_program_shorthand: "ПЗПІ",
task_list: (),
calendar_plan: (),
abstract: (),
bib_path: "bibl.yml",
appendices: (),
) = {
set document(title: title, author: author.name)
show: style
let bib-count = state("citation-counter", ())
show cite: it => {
it
bib-count.update(((..c)) => (..c, it.key))
}
show bibliography: it => {
set text(size: 0pt)
it
}
let head_mentor = mentors.at(0)
let edu_program = edu_programs.at(edu_program_shorthand)
// page 1 {{{2
[
#set align(center)
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ
\
Кафедра Програмної інженерії
\
ПОЯСНЮВАЛЬНА ЗАПИСКА
ДО КУРСОВОЇ РОБОТИ
з дисципліни: "#subjects.at(subject_shorthand, default: "NONE")"
Тема роботи: "#title"
\ \ \
#columns(2, gutter: 4cm)[
#set align(left)
#if author.gender == "m" { [Виконав\ ] } else { [Виконала\ ] } ст. гр. #author.group
\
Керівник:\
#head_mentor.degree
\
Робота захищена на оцінку
\
Комісія:\
#for mentor in mentors {
[#mentor.degree\
]
}
#colbreak()
#set align(left)
\
#author.name
\ \
#head_mentor.name
\
#underline(" " * 35)
\ \
#for mentor in mentors {
[#mentor.name\
]
}
]
#v(1fr)
Харків -- #task_list.done_date.display("[year]")
#pagebreak()
]
// page 2 {{{2
{
uline[Харківський національний університет радіоелектроніки]
linebreak()
linebreak()
grid(
columns: (100pt, 1fr),
bold[
Кафедра
Дисципліна
Спеціальність
],
{
uline(align: left, department_gen)
linebreak()
uline(align: left, subjects.at(subject_shorthand))
linebreak()
uline(align: left, [#edu_program.number #edu_program.name])
},
)
grid(
columns: (1fr, 1fr, 1fr),
gutter: 0.3fr,
[#bold[Курс] #uline(2)], [#bold[Група] #uline(author.group)], [#bold[Семестр] #uline(3)],
)
linebreak()
linebreak()
linebreak()
align(center, bold[ЗАВДАННЯ \ на курсову роботу студента])
linebreak()
uline(align: left)[_#author.full_name_gen _]
linebreak()
linebreak()
bold[\1. Тема роботи:]
uline[#title.]
linebreak()
{
bold[\2. Строк здачі закінченої роботи:]
uline(task_list.done_date.display("[day].[month].[year]"))
hfill(10fr)
}
linebreak()
bold[\3. Вихідні дані для роботи:]
uline(task_list.source)
linebreak()
bold[\4. Зміст розрахунково-пояснювальної записки:]
uline(task_list.content)
linebreak()
bold[\5. Перелік графічного матеріалу:]
uline(task_list.graphics)
linebreak()
{
bold[\6. Дата видачі завдання:]
uline(task_list.initial_date.display("[day].[month].[year]"))
hfill(10fr)
}
pagebreak()
}
// page 3 {{{2
{
align(center, bold[КАЛЕНДАРНИЙ ПЛАН])
set par(first-line-indent: 0pt)
linebreak()
calendar_plan.plan_table
linebreak()
grid(
columns: (5fr, 5fr),
grid(
columns: (1fr, 2fr, 1fr),
gutter: 0.2fr,
[
Студент \
Керівник \
#align(center)["#underline[#calendar_plan.approval_date.day()]"]
],
[
#uline(align: center, []) \
#uline(align: center, []) \
#uline(align: center, month_gen(calendar_plan.approval_date.month()))
],
[
\ \
#underline[#calendar_plan.approval_date.year()] р.
],
),
[
#author.name, \
#head_mentor.degree
#head_mentor.name.
],
)
pagebreak()
}
// page 4 {{{2
[
#align(center, bold[РЕФЕРАТ]) \
#context [
#let pages = counter(page).final().at(0)
#let images = query(figure.where(kind: image)).len()
#let tables = query(figure.where(kind: table)).len()
#let bibs = bib-count.final().dedup().len()
/* TODO: why this stopped working?
#let tables = counter(figure.where(kind: table)).final().at(0)
#let images = counter(figure.where(kind: image)).final().at(0)*/
#let counters = ()
#if pages != 0 { counters.push[#pages с.] }
#if tables != 0 { counters.push[#tables табл.] }
#if images != 0 { counters.push[#images рис.] }
#if bibs != 0 { counters.push[#bibs джерел] }
Пояснювальна записка до курсової роботи: #counters.join(", ").
]
\
#{
let keywords = abstract.keywords.map(upper)
let is_cyrillic = word => word.split("").any(char => ("А" <= char and char <= "я"))
let n = keywords.len()
for i in range(n) {
for j in range(0, n - i - 1) {
if (
(not is_cyrillic(keywords.at(j)) and is_cyrillic(keywords.at(j + 1)))
or (
is_cyrillic(keywords.at(j)) == is_cyrillic(keywords.at(j + 1)) and keywords.at(j) > keywords.at(j + 1)
)
) {
(keywords.at(j), keywords.at(j + 1)) = (keywords.at(j + 1), keywords.at(j))
}
}
}
keywords.join(", ")
}
\
#abstract.text
]
// page 5 {{{2
outline(
title: [
ЗМІСТ
#v(spacing * 2, weak: true)
],
depth: 2,
indent: auto,
)
doc
// bibliography {{{2
{
heading(depth: 1, numbering: none)[Перелік джерел посилання]
bibliography(
bib_path,
style: "ieee",
full: true,
title: none,
)
let bib_data = yaml(bib_path)
let format-entry(citation) = {
if (citation.type == "Web") {
let date_array = citation.url.date.split("-")
let date = datetime(
year: int(date_array.at(0)),
month: int(date_array.at(1)),
day: int(date_array.at(2)),
)
[
#citation.title.
#citation.author.
URL: #citation.url.value (дата звернення: #date.display("[day].[month].[year]")).
]
} else if citation.type == "Book" [
#citation.author
#citation.title.
#citation.publisher,
#citation.date.
#citation.page-total c.
] else [
UNSUPPORTED BIBLIOGRAPHY ENTRY TYPE, PLEASE OPEN AN ISSUE
]
}
show enum.item: it => {
set par(first-line-indent: 0pt)
box(width: 1.25cm)
box(width: 1em + 0.5cm)[#it.number.]
it.body
linebreak()
}
context {
for (i, citation) in query(ref.where(element: none)).map(r => str(r.target)).dedup().enumerate() {
enum.item(
i + 1,
format-entry(bib_data.at(citation)),
)
}
}
}
// appendices {{{2
{
counter(heading).update(0)
set heading(
numbering: (i, ..nums) => {
let char = upper(ua_alpha_numbering.at(i))
if nums.pos().len() == 0 { char } else {
char + "." + nums.pos().map(str).join(".")
}
},
)
show heading.where(level: 1): it => {
set align(center)
set text(size: 14pt, weight: "regular")
pagebreak(weak: true)
bold[ДОДАТОК #counter(heading).display(it.numbering)]
linebreak()
it.body
v(spacing * 2, weak: true)
}
show heading.where(level: 2): it => {
set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[
#h(1.25cm)
#counter(heading).display(it.numbering)
#it.body
]
v(spacing * 2, weak: true)
}
appendices
}
}
// Laboratory work template {{{1
/// DSTU 3008:2015 Template for NURE
/// -> content
/// - doc (content): Content to apply the template to.
/// - doctype ("ЛБ" | "ПЗ"): Document type.
/// - title (str): Title of the document.
/// - subject_shorthand (str): Subject short name.
/// - department_gen (str): Department name in genitive form.
/// - worknumber (int): Number of the work, can be omitted.
/// - authors ((name: str, full_name_gen: str, variant: int, group: str, gender: str),): List of Authors dicts.
/// - mentor (name: str, gender: str, degree: str): Mentors objects.
#let lab-pz-template(
doc,
doctype: "NONE",
title: "NONE",
subject_shorthand: "NONE",
department_gen: "Програмної інженерії",
worknumber: 1,
authors: (),
mentor: (),
) = {
set document(title: title, author: authors.at(0).name)
show: style
context counter(heading).update(worknumber - 1)
// page 1 {{{2
align(center)[
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ \
ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ
\ \
Кафедра #department_gen
\ \ \
Звіт \
з
#if doctype == "ЛБ" [лабораторної роботи] else [практичної роботи]
#if worknumber != none [ #worknumber]
з дисципліни: "#subjects.at(subject_shorthand, default: "UNLNOWN SUBJECT, PLEASE OPEN AN ISSUE")"
з теми: "#title"
\ \ \ \
#columns(2)[
#set align(left)
#set par(first-line-indent: 0pt)
#if authors.len() == 1 {
let author = authors.at(0)
if author.gender == "m" [Виконав:\ ] else [Виконала:\ ]
[
ст. гр. #author.group\
#author.name\
]
if author.variant != none [Варіант: #author.variant]
} else [
Виконали:\
ст. гр. #authors.at(0).group\
#authors.map(a => [ #a.name\ ])
]
#colbreak()
#set align(right)
#if mentor.gender == "m" { [Перевірив:\ ] } else { [Перевірила:\ ] }
#mentor.degree #if mentor.degree.len() >= 15 [\ ]
#mentor.name\
]
#v(1fr)
Харків -- #datetime.today().display("[year]")
]
pagebreak(weak: true)
heading(title)
doc
}
// vim:sts=2:sw=2:fdl=0:fdm=marker:cms=/*%s*/

View File

@@ -1,4 +1,5 @@
#import "@local/nure:0.0.0": *
// #import "@local/nure:0.0.0": *
#import "lib.typ": *
#show: lab-pz-template.with(
doctype: "ЛБ",

View File

@@ -0,0 +1,7 @@
> [!NOTE]
> Викладач: Мельникова Р. В.
>
> Оцінка: -
> [!TIP]
> Виконано для Linux в команді.

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 KiB

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

View 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