├── .gitignore ├── tests ├── main.cpp ├── Caesar.cpp ├── Affine.cpp └── Polybius.cpp ├── crack.1.gz ├── install.sh ├── sources ├── main.cpp ├── Log.cpp ├── Cipher.cpp ├── Console_manager.cpp ├── Affine.cpp ├── Caesar.cpp ├── SimpleSubstitution.cpp ├── Polybius.cpp ├── english_bigrams.txt └── Vigener.cpp ├── .travis.yml ├── include ├── Console_manager.hpp ├── Log.hpp ├── Affine.hpp ├── data_alphabet.hpp ├── SimpleSubstitution.hpp ├── Polybius.hpp ├── Caesar.hpp ├── Cipher.hpp └── Vigener.hpp ├── examples ├── ex_Caesar.cpp ├── ex_Affine.cpp ├── ex_SimpleSubstitution.cpp └── ex_Polybius.cpp ├── CMakeLists.txt ├── ToDo.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | build/ 3 | cmake-build-debug/ -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" -------------------------------------------------------------------------------- /crack.1.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CppHackers/Cipher_crack/HEAD/crack.1.gz -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mkdir build 3 | cd build 4 | cmake .. 5 | make 6 | ./Tests 7 | if [ -f "/usr/local/bin/crack" ]; then 8 | rm /usr/local/bin/crack 9 | fi 10 | sudo ln ./Cipher_crack /usr/local/bin/crack 11 | cd .. 12 | sudo cp crack.1.gz /usr/share/man/man1/crack.1.gz 13 | -------------------------------------------------------------------------------- /sources/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Console_manager.hpp" 2 | 3 | int main(int argc, char* argv[]) 4 | { 5 | Console_manager manager; 6 | try 7 | { 8 | manager.parse_command_args(argc, argv); 9 | } 10 | catch (const std::exception& ex) 11 | { 12 | std::cout << ex.what() << std::endl; 13 | } 14 | 15 | return 0; 16 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | matrix: 3 | include: 4 | - os: linux 5 | sudo: required 6 | env: COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5 7 | addons: 8 | apt: 9 | packages: 10 | - g++-5 11 | - cmake 12 | - libboost-all-dev 13 | sources: &sources 14 | - llvm-toolchain-precise 15 | - ubuntu-toolchain-r-test 16 | - os: osx 17 | compiler: clang-3.8 18 | env: COMPILER=clang++ -std=c++11 19 | 20 | script: 21 | - mkdir build 22 | - cd build 23 | - cmake .. && make 24 | - ./Tests 25 | -------------------------------------------------------------------------------- /include/Console_manager.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONSOLE_MANAGER_HPP 2 | #define CONSOLE_MANAGER_HPP 3 | 4 | #include 5 | #include "Cipher.hpp" 6 | 7 | namespace po = boost::program_options; 8 | 9 | enum class Action : int; 10 | 11 | class Console_manager 12 | { 13 | public: 14 | Console_manager(); 15 | ~Console_manager(); 16 | void parse_command_args(int argc, char** argv); 17 | 18 | private: 19 | po::variables_map var_map_; 20 | Cipher* cipher_; 21 | 22 | bool initialize_cipher(); 23 | void do_action(Action action); 24 | }; 25 | 26 | #endif // CONSOLE_MANAGER_HPP -------------------------------------------------------------------------------- /include/Log.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LOG_HPP 2 | #define LOG_HPP 3 | 4 | #include 5 | #include 6 | 7 | #define LOGFILE_NAME "log_cipher.txt" 8 | 9 | class Log { 10 | 11 | public: 12 | 13 | static Log * Logger(unsigned level = Log::Debug); 14 | enum MSG { Debug, Info, Warn, Error }; 15 | void log(unsigned level, const std::string & information); 16 | void set_log_level(unsigned level); 17 | ~Log(); 18 | 19 | protected: 20 | 21 | Log(unsigned level); 22 | 23 | private: 24 | 25 | static Log * logger_; 26 | unsigned level_; 27 | std::string log_file_name = LOGFILE_NAME; 28 | std::ofstream log_file_; 29 | }; 30 | 31 | #endif // !LOG_HPP 32 | -------------------------------------------------------------------------------- /tests/Caesar.cpp: -------------------------------------------------------------------------------- 1 | #include "Caesar.hpp" 2 | #include "catch.hpp" 3 | 4 | SCENARIO("Caesar: decrypted text and cracked text must be equal") 5 | { 6 | GIVEN("encrypted text") 7 | { 8 | Caesar a; 9 | a.set_text_source("Rising fuel costs have impacted everything from the price of groceries to the cost of getting to work everyday."); 10 | a.encrypt("7"); 11 | auto enc_text = a.get_text_modified(); 12 | WHEN("decrypt encrypted text and crack encrypted text") 13 | { 14 | a.set_text_source(enc_text); 15 | a.decrypt("7"); 16 | auto dec_text = a.get_text_modified(); 17 | a.crack(); 18 | auto cracked_text = a.get_text_modified(); 19 | THEN("texts must be equal") 20 | { 21 | REQUIRE(dec_text == cracked_text); 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /tests/Affine.cpp: -------------------------------------------------------------------------------- 1 | #include "Affine.hpp" 2 | #include "catch.hpp" 3 | 4 | SCENARIO("Affine: decrypted text and cracked text must be equal") 5 | { 6 | GIVEN("encrypted text") 7 | { 8 | Affine a; 9 | a.set_text_source("Rising fuel costs have impacted everything from the price of groceries to the cost of getting to work everyday."); 10 | a.encrypt("3,4"); 11 | auto enc_text = a.get_text_modified(); 12 | WHEN("decrypt encrypted text and crack encrypted text") 13 | { 14 | a.set_text_source(enc_text); 15 | a.decrypt("3,4"); 16 | auto dec_text = a.get_text_modified(); 17 | a.crack(); 18 | auto cracked_text = a.get_text_modified(); 19 | THEN("texts must be equal") 20 | { 21 | REQUIRE(dec_text == cracked_text); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /include/Affine.hpp: -------------------------------------------------------------------------------- 1 | #ifndef AFFINE_HPP 2 | #define AFFINE_HPP 3 | 4 | #include "Cipher.hpp" 5 | 6 | class Affine : public Cipher 7 | { 8 | public: 9 | Affine(unsigned log_level = Log::Debug ); 10 | 11 | void encrypt(const std::string& key) override; 12 | void decrypt(const std::string& key) override; 13 | void crack() override; 14 | 15 | private: 16 | struct Key 17 | { 18 | int a; 19 | int b; 20 | Key(int a = 0, int b = 0); 21 | }; 22 | 23 | float * frequency_table_; 24 | char * alphabet_; 25 | std::size_t alphabet_len_; 26 | Key key_; 27 | std::string decrypt(const Key& key) const; 28 | Key parse_key(const std::string& key) noexcept(false); 29 | void change_text_source(); 30 | bool from_this_alphabet(char letter) const noexcept; 31 | double count_coefficient(const std::string& text) const; 32 | }; 33 | 34 | #endif // AFFINE_HPP -------------------------------------------------------------------------------- /examples/ex_Caesar.cpp: -------------------------------------------------------------------------------- 1 | //example1 2 | 3 | #include"Caesar.hpp" 4 | #include 5 | 6 | int main() { 7 | 8 | Caesar z1; 9 | z1.set_text_source("LoGin, AdmiN! password_ !Is! password..."); 10 | z1.encrypt("5"); 11 | z1.text_modified_out(std::cout); 12 | z1.set_text_source(z1.get_text_modified()); 13 | std::cout << '\n'; 14 | z1.crack(); 15 | z1.text_modified_out(std::cout); 16 | std::cout << "\n\n"; 17 | 18 | Caesar z2; 19 | std::cout << "Print your text:\n"; 20 | z2.text_source_in(std::cin); 21 | std::cout << "\nYour text_source\n: " << z2.get_text_source() << "\n"; 22 | z2.encrypt(std::to_string(128)); 23 | std::cout << "\nYour encrypt_text\n: " << z2.get_text_modified() << "\n"; 24 | z2.crack(); 25 | std::cout << "\nYour crack_text\n:" << z2.get_text_modified(); 26 | 27 | getchar(); 28 | return 0; 29 | } 30 | 31 | //helloiamthesuperman 32 | //wearegoodatprogramming 33 | //iamhackerhelloworld 34 | //loginadminpasswordpassword -------------------------------------------------------------------------------- /include/data_alphabet.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DATA_ALPHABET 2 | #define DATA_ALPHABET 3 | 4 | /////////////////////////////////////////////////////////ENGLISH 5 | #define ENGLISH_ALPHABET_LEN 26 6 | 7 | #define ENGLISH_MATCH_INDEX 0.0667 8 | 9 | static char ENGLISH_ALPHABET[ENGLISH_ALPHABET_LEN] = 10 | { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 11 | 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 12 | 'u', 'v', 'w', 'x', 'y', 'z' }; 13 | 14 | static float ENGLISH_LETTER_FREQUENCIES[ENGLISH_ALPHABET_LEN] = 15 | { 8.55, //A 16 | 1.60, //B 17 | 3.16, //C 18 | 3.87, //D 19 | 12.10, //E 20 | 2.18, //F 21 | 2.09, //G 22 | 4.96, //H 23 | 7.33, //I 24 | 0.22, //J 25 | 0.81, //K 26 | 4.21, //L 27 | 2.53, //M 28 | 7.17, //N 29 | 7.47, //O 30 | 2.07, //P 31 | 0.10, //Q 32 | 6.33, //R 33 | 6.73, //S 34 | 8.94, //T 35 | 2.68, //U 36 | 1.06, //V 37 | 1.83, //W 38 | 0.19, //X 39 | 1.72, //Y 40 | 0.11 //Z 41 | }; 42 | /////////////////////////////////////////////////////////ENGLISH 43 | 44 | #endif // !DATA_ALPHABET -------------------------------------------------------------------------------- /sources/Log.cpp: -------------------------------------------------------------------------------- 1 | #include "Log.hpp" 2 | 3 | Log * Log::logger_ = nullptr; 4 | 5 | Log::Log(unsigned level) 6 | :level_(level) { 7 | 8 | if (level > MSG::Error) { 9 | level_ = MSG::Error; 10 | } 11 | log_file_.open(log_file_name); 12 | } 13 | 14 | Log * Log::Logger(unsigned level) { 15 | if (logger_ == nullptr) { 16 | logger_ = new Log(level); 17 | } 18 | return logger_; 19 | } 20 | 21 | void Log::log(unsigned level, const std::string & information) { 22 | 23 | if (level < level_) { 24 | return; 25 | } 26 | 27 | switch (level) { 28 | case Debug: 29 | log_file_ << "[Debug]: "; 30 | break; 31 | case Info: 32 | log_file_ << "[Info]: "; 33 | break; 34 | case Warn: 35 | log_file_ << "[Warn]: "; 36 | break; 37 | case Error: 38 | log_file_ << "[Error]: "; 39 | break; 40 | default: 41 | return; 42 | } 43 | log_file_ << information << "\n"; 44 | 45 | } 46 | 47 | void Log::set_log_level(unsigned level) { 48 | 49 | level_ = level; 50 | } 51 | 52 | Log::~Log() { 53 | logger_->log_file_.close(); 54 | delete logger_; 55 | 56 | } 57 | 58 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.7) 2 | project(Cipher_crack) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | set(Boost_USE_STATIC_LIBS ON) 6 | set(Boost_USE_MULTITHREADED ON) 7 | set(Boost_USE_STATIC_RUNTIME OFF) 8 | 9 | find_package(Boost COMPONENTS program_options REQUIRED) 10 | 11 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/) 12 | include_directories(${Boost_INCLUDE_DIRS}) 13 | 14 | set(SOURCE_FILES include/Cipher.hpp include/data_alphabet.hpp include/Caesar.hpp include/Affine.hpp include/Vigener.hpp 15 | include/SimpleSubstitution.hpp include/Polybius.hpp include/Log.hpp 16 | sources/Cipher.cpp sources/Caesar.cpp sources/Affine.cpp sources/Vigener.cpp sources/SimpleSubstitution.cpp 17 | sources/Polybius.cpp sources/Log.cpp) 18 | 19 | add_executable(Cipher_crack ${SOURCE_FILES} include/Console_manager.hpp sources/Console_manager.cpp sources/main.cpp) 20 | target_link_libraries(Cipher_crack ${Boost_LIBRARIES}) 21 | 22 | add_executable(Tests ${SOURCE_FILES} tests/catch.hpp tests/main.cpp tests/Affine.cpp tests/Caesar.cpp tests/Polybius.cpp) 23 | -------------------------------------------------------------------------------- /include/SimpleSubstitution.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLESUBSTITUTION_HPP 2 | #define SIMPLESUBSTITUTION_HPP 3 | 4 | #include 5 | #include "Cipher.hpp" 6 | 7 | class SimpleSubstitution : public Cipher 8 | { 9 | public: 10 | SimpleSubstitution(unsigned log_level = Log::Debug); 11 | 12 | void encrypt(const std::string& key) override; 13 | void decrypt(const std::string& key) override; 14 | void crack() override; 15 | 16 | private: 17 | typedef std::unordered_map str_dbl_map; 18 | 19 | float * frequency_table_; 20 | char * alphabet_; 21 | std::size_t alphabet_len_; 22 | std::string key_; 23 | str_dbl_map bigrams_freq_table_; 24 | str_dbl_map current_bigrams_freq_table_; 25 | 26 | bool check_key(const std::string& key) const noexcept; 27 | void change_text_source() noexcept; 28 | bool from_this_alphabet(char letter) const noexcept; 29 | double count_bigrams_coefficient(const std::string& text) noexcept; 30 | std::string decr(const std::string& key) const noexcept; 31 | void load_bigrams_freq() noexcept; 32 | }; 33 | 34 | #endif // SIMPLESUBSTITUTION_HPP -------------------------------------------------------------------------------- /ToDo.md: -------------------------------------------------------------------------------- 1 | ## Cipher_crack (исследование шифров методами криптоанализа) 2 | 3 | ## Этапы 4 | 5 | ## 1 неделя (14.11 - 21.11) 6 | 7 | 1. Разработка структуры проекта: 8 | Создание интерфейса базового класса Сipher 9 | Создание плана по разделению обязанностей 10 | 2. Реализация алгоритмов шифрования и их взлома: 11 | Реализация шифра Цезаря 12 | Взлом шифра Цезаря 13 | Реализация афинного шифра 14 | Взлом афинного шифра 15 | 3. Решение проблем взлома небольших текстов 16 | 17 | ## 2 неделя: 18 | 19 | 1. Реализация алгоритмов шифрования и их взлома: 20 | Реализация шифра простой замены 21 | Взлом шифра простой замены 22 | Реализация шифра Полибия 23 | Взлом шифра Полибия 24 | Реализация шифра Виженера 25 | Взлом шифра Виженера 26 | 2. Решение проблем взлома небольших текстов 27 | 3. Тестирование алгоритмов взлома, улучшение работы программы с критическими случаями 28 | 29 | 30 | Виженер: 31 | а) Установить максимальную длину проверяемого ключа 32 | б) Побробовать другой способ поиска длины ключа 33 | в) Попробовать другой способ поиска исходного текста 34 | г) Топ вариантов 35 | д) Запоминание пробелов 36 | е) Тесты + Цезарь 37 | 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cipher_crack 2 | 3 | [![Build Status](https://travis-ci.org/CppHackers/Cipher_crack.svg?branch=master)](https://travis-ci.org/CppHackers/Cipher_crack) 4 | 5 | ## What's the Cipher_crack 6 | 7 | It's a program that can encrypt, decrypt and crack texts using cryptanalysis. 8 | 9 | ### Ciphers used: 10 | 11 | 1) Caesar cipher 12 | 13 | 2) Affine cipher 14 | 15 | 3) Simple substitution cipher 16 | 17 | 4) Polybius cipher 18 | 19 | 5) Vigenere cipher 20 | 21 | ### Сryptanalysis methods used: 22 | 23 | 1) Brute force 24 | 25 | 2) Frequency analysis of letters 26 | 27 | 3) Frequency analysis of n-grams 28 | 29 | 4) 'Hill-climbing' algorithm 30 | 31 | 5) Accounting for the index of coincidence 32 | 33 | ## Build requirements 34 | 35 | Before installing the program, check that `cmake` and `libboost-all-dev` packets are installed. 36 | 37 | ## Install 38 | 39 | ```ShellSession 40 | $ git clone https://github.com/CppHackers/Cipher_crack 41 | $ cd Cipher_crack 42 | $ ./install.sh 43 | ``` 44 | 45 | ## How to use it 46 | 47 | ```ShellSession 48 | $ crack [general options] [cipher options] [encrypt/decrypt/crack options] 49 | ``` 50 | 51 | ## More 52 | 53 | ```ShellSession 54 | $ man crack 55 | ``` 56 | or 57 | ```ShellSession 58 | $ crack --help 59 | ``` 60 | or 61 | ```ShellSession 62 | $ crack -h 63 | ``` 64 | -------------------------------------------------------------------------------- /include/Polybius.hpp: -------------------------------------------------------------------------------- 1 | #ifndef POLYBIUS_HPP 2 | #define POLYBIUS_HPP 3 | 4 | #include 5 | #include 6 | #include "Cipher.hpp" 7 | 8 | class Polybius : public Cipher 9 | { 10 | public: 11 | Polybius(unsigned log_level = Log::Debug); 12 | 13 | void encrypt(const std::string& key) override; 14 | void decrypt(const std::string& key) override; 15 | void crack() override; 16 | 17 | private: 18 | typedef std::unordered_map str_dbl_map; 19 | 20 | struct Key 21 | { 22 | std::vector> matrix; 23 | std::size_t rows; 24 | std::size_t cols; 25 | Key(std::size_t rows = 0, std::size_t cols = 0); 26 | }; 27 | 28 | std::vector frequency_table_; 29 | std::vector alphabet_; 30 | std::size_t alphabet_len_; 31 | Key key_; 32 | str_dbl_map bigrams_freq_table_; 33 | str_dbl_map current_bigrams_freq_table_; 34 | 35 | bool check_key(const std::string& key) const noexcept; 36 | Key parse_key(const std::string& key) const noexcept; 37 | void change_text_source() noexcept; 38 | bool from_this_alphabet(char letter) const noexcept; 39 | double count_bigrams_coefficient(const std::string& text) noexcept; 40 | std::string decr(const std::string& key) const noexcept; 41 | void load_bigrams_freq() noexcept; 42 | }; 43 | 44 | #endif // POLYBIUS_HPP 45 | -------------------------------------------------------------------------------- /include/Caesar.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CAESAR_HPP 2 | #define CAESAR_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include"data_alphabet.hpp" 8 | #include"Cipher.hpp" 9 | 10 | #define TOP 3 11 | 12 | class Caesar : public Cipher { 13 | 14 | public: 15 | 16 | Caesar(char letter_first = 'a', bool need_spaces = false, 17 | unsigned log_level = Log::Debug, unsigned top = TOP); 18 | void encrypt(const std::string & key) override; 19 | void decrypt(const std::string & key) override; 20 | void crack() override; 21 | ~Caesar(); 22 | void change_spaces_mode(); 23 | std::string spaces_reborn(std::string const & text_modified); 24 | std::vector> get_top(); 25 | std::ostream & top_out(std::ostream & out); 26 | std::ofstream & top_out(std::ofstream & out); 27 | 28 | private: 29 | 30 | float * frequency_table_; 31 | char * alphabet_; 32 | std::size_t alphabet_len_; 33 | int key_; // !!! unsigned 34 | char letter_first_; 35 | std::vector> top_vector_; 36 | std::unordered_set spaces_pos_; 37 | bool need_spaces_; 38 | std::size_t const top_; // if 0 then don't waste the time, it's not more then alphabet_len_ 39 | std::size_t * letters_count_; 40 | 41 | 42 | bool prepare_to_modify(const std::string & key); 43 | bool from_this_alphabet(char letter) const; 44 | void encr(); 45 | void decr(); 46 | void text_to_lower(); 47 | void add_decryptod(decryptod decr); 48 | 49 | }; 50 | 51 | #endif // !CAESAR_HPP -------------------------------------------------------------------------------- /include/Cipher.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CIPHER_HPP 2 | #define CIPHER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Log.hpp" 9 | 10 | class Cipher { 11 | 12 | public: 13 | 14 | Cipher(unsigned log_level = Log::Debug); 15 | 16 | void text_source_in(std::istream & in); 17 | 18 | void text_modified_out(std::ostream & out) const; 19 | 20 | void text_source_in(std::ifstream & in); 21 | 22 | void text_modified_out(std::ofstream & out) const; 23 | 24 | void set_text_source(std::string const & text_source); 25 | 26 | std::string get_text_source() const; 27 | 28 | std::string get_text_modified() const; 29 | 30 | virtual void encrypt(const std::string& key) = 0; 31 | 32 | virtual void decrypt(const std::string& key) = 0; 33 | 34 | virtual void crack() = 0; 35 | 36 | bool is_modified() const; 37 | 38 | virtual ~Cipher(); 39 | 40 | protected: 41 | 42 | std::string text_source_; 43 | std::string text_modified_; 44 | }; 45 | 46 | 47 | template 48 | struct decryptod { 49 | 50 | decryptod() 51 | : text_("") 52 | , key_(KeyType()) 53 | , factor_(0.0) 54 | {}; 55 | decryptod(std::string text, KeyType key, double factor) 56 | : text_(text) 57 | , key_(key) 58 | , factor_(factor) 59 | {}; 60 | 61 | std::string text_; 62 | KeyType key_; 63 | double factor_; 64 | }; 65 | 66 | struct decryptod_Vigener_mod { 67 | 68 | decryptod_Vigener_mod(std::size_t key_len = 0, double match_index = 0.0, std::size_t top_key = 0) 69 | : key_len_(key_len) 70 | , match_index_(match_index){ 71 | 72 | top_key_vector_.assign(top_key, decryptod()); 73 | } 74 | 75 | std::size_t key_len_; 76 | std::vector> top_key_vector_; 77 | double match_index_; 78 | }; 79 | 80 | #endif // !CIPHER_HPP -------------------------------------------------------------------------------- /examples/ex_Affine.cpp: -------------------------------------------------------------------------------- 1 | #include "Affine.hpp" 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | Affine a1; 8 | a1.set_text_source("Hello, my name is John. I am seventeen and I love playing the guitar"); 9 | try 10 | { 11 | a1.encrypt("3,4"); 12 | } 13 | catch (const std::exception& ex) 14 | { 15 | std::cout << ex.what() << std::endl; 16 | } 17 | a1.text_modified_out(std::cout); 18 | std::cout << std::endl; 19 | 20 | a1.set_text_source(a1.get_text_modified()); 21 | try 22 | { 23 | a1.decrypt("3,4"); 24 | } 25 | catch (const std::exception& ex) 26 | { 27 | std::cout << ex.what() << std::endl; 28 | } 29 | a1.text_modified_out(std::cout); 30 | std::cout << std::endl; 31 | 32 | a1.set_text_source("Hello, my name is John. I am seventeen and I love playing the guitar"); 33 | try 34 | { 35 | a1.encrypt("27,3"); 36 | } 37 | catch (const std::exception& ex) 38 | { 39 | std::cout << ex.what() << std::endl; 40 | } 41 | a1.set_text_source(a1.get_text_modified()); 42 | a1.crack(); 43 | a1.text_modified_out(std::cout); 44 | std::cout << std::endl; 45 | 46 | Affine a2; 47 | std::cout << "Print your text:\n"; 48 | a2.text_source_in(std::cin); 49 | std::cout << "\nYour text_source\n: " << a2.get_text_source() << std::endl; 50 | std::cout << "Print your key in format \"a,b\": "; 51 | std::string key; 52 | std::cin >> key; 53 | try 54 | { 55 | a2.encrypt(key); 56 | } 57 | catch (const std::exception& ex) 58 | { 59 | std::cout << ex.what() << std::endl; 60 | } 61 | std::cout << "\nYour encrypt_text\n: " << a2.get_text_modified() << std::endl; 62 | a2.crack(); 63 | std::cout << "\nYour crack_text\n:" << a2.get_text_modified() << std::endl; 64 | 65 | getchar(); 66 | return 0; 67 | } -------------------------------------------------------------------------------- /sources/Cipher.cpp: -------------------------------------------------------------------------------- 1 | #include"Cipher.hpp" 2 | 3 | Cipher::Cipher(unsigned log_level) { 4 | 5 | text_source_ = ""; 6 | text_modified_ = ""; 7 | Log::Logger(log_level)->log(Log::Debug, "Created Cipher"); 8 | } 9 | 10 | void Cipher::text_source_in(std::istream & in) { 11 | 12 | Log::Logger()->log(Log::Debug, "Reading text_source from terminal"); 13 | text_source_ = ""; 14 | do { 15 | std::string new_text = ""; 16 | std::getline(in, new_text); 17 | if (new_text.length() > 0) { 18 | text_source_ += new_text; 19 | } else { 20 | break; 21 | } 22 | } while (true); 23 | text_modified_ = ""; 24 | Log::Logger()->log(Log::Debug, "Completed reading text_source from terminal"); 25 | } 26 | 27 | void Cipher::text_modified_out(std::ostream & out) const { 28 | 29 | Log::Logger()->log(Log::Debug, "Output text_modified_ to terminal"); 30 | out << text_modified_; 31 | } 32 | 33 | void Cipher::text_source_in(std::ifstream & in) { 34 | 35 | Log::Logger()->log(Log::Debug, "Reading text_source from file"); 36 | text_source_ = ""; 37 | do { 38 | std::string new_text = ""; 39 | std::getline(in, new_text); 40 | if (new_text.length() > 0) { 41 | text_source_ += new_text; 42 | } else { 43 | break; 44 | } 45 | } while (true); 46 | text_modified_ = ""; 47 | Log::Logger()->log(Log::Debug, "Completed reading text_source from file"); 48 | 49 | } 50 | 51 | void Cipher::text_modified_out(std::ofstream & out) const { 52 | 53 | Log::Logger()->log(Log::Debug, "Output text_source to file"); 54 | out << text_modified_; 55 | } 56 | 57 | void Cipher::set_text_source(std::string const & text_source) { 58 | 59 | Log::Logger()->log(Log::Debug, "Setting text_source in programm"); 60 | text_source_ = text_source; 61 | text_modified_ = ""; 62 | } 63 | 64 | std::string Cipher::get_text_source() const { 65 | 66 | Log::Logger()->log(Log::Debug, "Getting text_source in programm"); 67 | return text_source_; 68 | } 69 | 70 | std::string Cipher::get_text_modified() const { 71 | 72 | Log::Logger()->log(Log::Debug, "Getting text_modified in programm"); 73 | return text_modified_; 74 | } 75 | 76 | bool Cipher::is_modified() const { 77 | 78 | Log::Logger()->log(Log::Debug, "Is_modified request"); 79 | return text_modified_.length() > 0; 80 | } 81 | 82 | 83 | Cipher::~Cipher() { 84 | 85 | } -------------------------------------------------------------------------------- /tests/Polybius.cpp: -------------------------------------------------------------------------------- 1 | #include "Polybius.hpp" 2 | #include "catch.hpp" 3 | 4 | SCENARIO("Polybius: decrypted text and cracked text must be equal") 5 | { 6 | GIVEN("encrypted text") 7 | { 8 | Polybius a; 9 | a.set_text_source("The current severe economic downturn in America affects people on every level. Rising fuel costs have impacted everything from the price of groceries to the cost of getting to work everyday. Due to this economy issue, there are the changes in the way people spend their leisure time. There are media reports that tell about the trend away from vacations and toward \"staycations\", where people stay at home instead of travelling. At the same time, there's a significant trend toward finding recreational activities. They are called crafts for kids, quilting, and gardening.\n" 10 | "Parents and grandparents are always on the lookout for kids' craft projects that will engage children and keep those little hands busy. Thankfully there are many inexpensive books that are filled with ideas. For example, you can find books that outline crafts using play dough, how to make flower figures, and even Christmas crafts. In fact, you can even find books that provide ideas for making Christmas gifts that fit in a jar. From crafts for preschool-age children to pastimes tor older kids these idea books provide a wealth of options for engaging children's imaginations." 11 | "As for adults, two trends are emerging. Knitting and sewing were popular during the past decade. The latest pastime appreciated by American adults is quilting. Hobbyists are bringing it back tо lite and enjoying the detail and craft involved in making a quilt. There is a wealth of helpful new books on quilting projects, including how-to books, quilting patterns, and quilting designs."); 12 | a.encrypt("qwertyuiopasdfghklzxcvbnm"); 13 | auto enc_text = a.get_text_modified(); 14 | WHEN("decrypt encrypted text and crack encrypted text") 15 | { 16 | a.set_text_source(enc_text); 17 | a.decrypt("qwertyuiopasdfghklzxcvbnm"); 18 | auto dec_text = a.get_text_modified(); 19 | a.crack(); 20 | auto cracked_text = a.get_text_modified(); 21 | THEN("texts must be equal") 22 | { 23 | REQUIRE(dec_text == cracked_text); 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /include/Vigener.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VIGENER_HPP 2 | #define VEGENER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include "data_alphabet.hpp" 8 | #include "Cipher.hpp" 9 | #include "Caesar.hpp" 10 | 11 | #define MAX_KEY_LEN 15 12 | #define TOP_KEY_LEN 2 13 | #define TOP_KEY 2 14 | 15 | class Vigener : public Cipher { 16 | 17 | public: 18 | 19 | Vigener(char letter_first = 'a', std::size_t max_key_len = MAX_KEY_LEN, 20 | bool need_spaces = false, unsigned log_level = Log::Debug, 21 | unsigned top_key_len = TOP_KEY_LEN, unsigned top_key = TOP_KEY); 22 | void encrypt(const std::string & key) override; 23 | void decrypt(const std::string & key) override; 24 | void crack() override; 25 | std::string get_key() const; 26 | void change_spaces_mode(); 27 | std::ostream & top_out(std::ostream & out); 28 | std::ofstream & top_out(std::ofstream & out); 29 | ~Vigener(); 30 | 31 | private: 32 | 33 | float * frequency_table_; 34 | char * alphabet_; 35 | std::string key_; 36 | double match_index_; 37 | std::size_t alphabet_len_; 38 | std::size_t key_len_; 39 | std::size_t const max_key_len_; 40 | char letter_first_; 41 | std::unordered_set spaces_pos_; 42 | bool need_spaces_; 43 | std::vector top_vector_; 44 | std::size_t const top_key_len_; // if 0 then don't waste the time, it's not more then max_key_len_ 45 | std::size_t const top_key_; // it's not more then pow(top_key_len_, aplphabet_len_) 46 | std::size_t * letters_count_; 47 | 48 | bool prepare_to_modify(const std::string & key); 49 | bool from_this_alphabet(char letter) const; 50 | void encr(); 51 | void decr(); 52 | void text_to_lower(); 53 | std::size_t find_key_len(); 54 | std::string find_text(); 55 | std::string find_top_text(); 56 | std::string spaces_reborn(std::string const & text_modified); 57 | void add_decryptod_Vigener_mod(decryptod_Vigener_mod decr); 58 | void find_optimal_top(std::vector & indexes, std::vector>> & source_variant, 59 | std::vector & letters_source, std::size_t text_len, std::string *& text_parts, 60 | std::size_t top_key, std::size_t top_key_len, std::size_t cur_key_len, 61 | decryptod_Vigener_mod & cur_decr, std::size_t deep); 62 | char find_key_letter(char letter_source, char letter_modified); 63 | void add_decryptod(decryptod_Vigener_mod & decr_V_m, decryptod decr_C); 64 | double calc_factor(std::string const & text); 65 | }; 66 | 67 | #endif // !VIGENER_HPP 68 | 69 | -------------------------------------------------------------------------------- /examples/ex_SimpleSubstitution.cpp: -------------------------------------------------------------------------------- 1 | #include "SimpleSubstitution.hpp" 2 | 3 | int main(int argc, char* argv[]) 4 | { 5 | SimpleSubstitution ss; 6 | std::string text = "I am always both amused and annoyed when I hear foreign people criticize British food. \"It's unimaginative,\" they say. \"It's boring, it's tasteless, and it's chips with everything and totally overcooked vegetables.\"\n" 7 | "\n" 8 | "I have a theory about British cooking, and I was interested to read that several famous cookery writers agree with me. My theory is this. Our basic ingredients, when fresh, are so full of flavor that we haven't had to invent sauces and complex recipes to disguise their natural taste. What can compare with fresh peas or new potatoes just boiled (not over boiled) and served with butter? Why drown spring lamb a wine or cream or yoghurt and spices, when with just one or two herbs it is absolutely delicious?\n" 9 | "\n" 10 | "If you ask foreigners to name some typically English dishes, they will probably say \"fish and chips\" and then stop. It is disappointing, but true, that there is no tradition in Britain of eating in restaurants, because our food doesn’t lend itself to such preparation. British cooking is found in the home, where it is possible to time the dishes to perfection. So it is difficult to find a good English restaurant with reasonable prices.\n" 11 | "\n" 12 | "It is for these reasons that we haven’t exported our dishes, but we have imported a surprising number from all over the world. In most cities in Britain you’ll also find Indian, Chinese, French and Italian restaurants. In London you’ll also find Indonesian, Lebanese, Iranian, German, Spanish, Mexican, Greek… Cynics will say that this is because we have no \"cuisine\" ourselves, but, well, you know what I think!"; 13 | ss.set_text_source(text); 14 | try 15 | { 16 | ss.encrypt("poiuytrewqasdfghjklmnbvcxz"); 17 | } 18 | catch (const std::exception& ex) 19 | { 20 | std::cout << ex.what() << std::endl; 21 | } 22 | ss.text_modified_out(std::cout); 23 | std::cout << std::endl; 24 | 25 | ss.set_text_source(ss.get_text_modified()); 26 | try 27 | { 28 | ss.decrypt("poiuytrewqasdfghjklmnbvcxz"); 29 | } 30 | catch (const std::exception& ex) 31 | { 32 | std::cout << ex.what() << std::endl; 33 | } 34 | ss.text_modified_out(std::cout); 35 | std::cout << std::endl; 36 | 37 | ss.set_text_source(text); 38 | try 39 | { 40 | ss.encrypt("poiuytrewqasdfghjklmnbvcxz"); 41 | } 42 | catch (const std::exception& ex) 43 | { 44 | std::cout << ex.what() << std::endl; 45 | } 46 | ss.set_text_source(ss.get_text_modified()); 47 | ss.crack(); 48 | ss.text_modified_out(std::cout); 49 | std::cout << std::endl; 50 | return 0; 51 | } -------------------------------------------------------------------------------- /examples/ex_Polybius.cpp: -------------------------------------------------------------------------------- 1 | #include "Polybius.hpp" 2 | 3 | int main() 4 | { 5 | Polybius p; 6 | std::string text = "If you read this story you'll be able to find a common language with any American. All of them are very proud of their Constitution.\n" 7 | "The USA Constitution was written by fifty-five men who met at Philadelphia Convention in 1787. In four months they wrote the Constitution which has lasted over 200 years!\n" 8 | "All were white men. The average age was forty-two. Many of these men had been leaders during the American Revolution. About three-fourths of them had served in Congress. Most were leaders in their states. Some were rich, but most were not. None were poor.\n" 9 | "There were no native Americans among the delegates. There were no women. There were no black men or slaves. Poor farmers were not present either.\n" 10 | "George Washington, James Madison, and Benjamin Franklin were the three important delegates to the Convention.\n" 11 | "George Washington came from Virginia. He was probably the most respected man in the country. As the commander-in-chief of the American army during the Revolution, he was a great hero to most people.\n" 12 | "Then he had retired to his plantation and would have liked to remain there. However, his friends told him he should attend the convention. They said his support was necessary to get a new constitution accepted by the people. Since Washington thought a stronger national government was necessary, he came to Philadelphia.\n" 13 | "James Madison is often called the \"Father of the Constitution\". His ideas about government greatly influenced the other delegates. He had already developed a written plan for the new government which he brought to Philadelphia. It was known as the Virginia plan and it called for a strong national government. Madison took notes during the meetings. Much of what we know about the Philadelphia Convention is based on his notes.\n" 14 | "Benjamin Franklin attended the convention as a delegate from Pennsylvania. He was 81 years old and in poor health. Like Washington, he was highly respected by the Americans. He had been a printer, inventor and writer. He had also helped the country develop good relations with other nations. At the convention, he encouraged the delegates to cooperate with each other and work hard to settle their differences. His support of the Constitution was important to the other delegates.\n" 15 | "Once the Framers reached these agreements, it was time to get down to work and create a constitution.\n" 16 | "Delegates from states with large populations believed that a state with more people should have more votes in Congress.\n" 17 | "During the long debates, the Framers could not reach a decision on this issue. Neither side was willing to give in. The delegates were almost ready to quit and go home. A special committee of one delegate from each state was formed to try and find a solution. The members of the committee worked hard to find a compromise a majority of the delegates would accept."; 18 | 19 | p.set_text_source(text); 20 | try 21 | { 22 | p.encrypt("poiuytrewqasdfghklmnbvcxz"); 23 | } 24 | catch (const std::exception& ex) 25 | { 26 | std::cout << ex.what() << std::endl; 27 | } 28 | p.text_modified_out(std::cout); 29 | std::cout << std::endl; 30 | 31 | p.set_text_source(p.get_text_modified()); 32 | try 33 | { 34 | p.decrypt("poiuytrewqasdfghklmnbvcxz"); 35 | } 36 | catch (const std::exception& ex) 37 | { 38 | std::cout << ex.what() << std::endl; 39 | } 40 | p.text_modified_out(std::cout); 41 | std::cout << std::endl; 42 | 43 | p.set_text_source(text); 44 | try 45 | { 46 | p.encrypt("poiuytrewqasdfghklmnbvcxz"); 47 | } 48 | catch (const std::exception& ex) 49 | { 50 | std::cout << ex.what() << std::endl; 51 | } 52 | 53 | p.set_text_source(p.get_text_modified()); 54 | p.crack(); 55 | p.text_modified_out(std::cout); 56 | std::cout << std::endl; 57 | 58 | return 0; 59 | } -------------------------------------------------------------------------------- /sources/Console_manager.cpp: -------------------------------------------------------------------------------- 1 | #include "Console_manager.hpp" 2 | #include 3 | #include "Caesar.hpp" 4 | #include "Affine.hpp" 5 | #include "SimpleSubstitution.hpp" 6 | #include "Polybius.hpp" 7 | #include "Vigener.hpp" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | enum class Action 14 | { 15 | Encrypt, Decrypt, Crack 16 | }; 17 | 18 | Console_manager::Console_manager() : cipher_(nullptr), var_map_() 19 | {} 20 | 21 | Console_manager::~Console_manager() 22 | { 23 | delete cipher_; 24 | } 25 | 26 | void Console_manager::parse_command_args(int argc, char** argv) 27 | { 28 | po::options_description desc("General options"); 29 | desc.add_options() 30 | ("help,h", "Show help") 31 | ("encrypt,e", "Encrypt") 32 | ("decrypt,d", "Decrypt") 33 | ("crack,c", "Crack") 34 | ; 35 | po::options_description ciphers_desc("Cipher options"); 36 | ciphers_desc.add_options() 37 | ("Caesar,C", "Caesar cipher") 38 | ("Affine,A", "Affine cipher") 39 | ("Vigenere,V", "Vigenere cipher") 40 | ("SimpleSub,S", "Simple substitution cipher") 41 | ("Polybius,P", "Polybius cipher") 42 | ; 43 | po::options_description encrypt_desc("Encrypt options"); 44 | encrypt_desc.add_options() 45 | ("input,i", po::value(), "Input file") 46 | ("key,k", po::value(), "Key") 47 | ("output,o", po::value(), "Output file") 48 | ; 49 | po::options_description decrypt_desc("Decrypt options"); 50 | decrypt_desc.add_options() 51 | ("input,i", po::value(), "Input file") 52 | ("key,k", po::value(), "Key") 53 | ("output,o", po::value(), "Output file") 54 | ; 55 | po::options_description crack_desc("Crack options"); 56 | crack_desc.add_options() 57 | ("input,i", po::value(), "Input file") 58 | ("output,o", po::value(), "Output file") 59 | ; 60 | 61 | desc.add(ciphers_desc); 62 | po::parsed_options parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); 63 | po::store(parsed, var_map_); 64 | po::notify(var_map_); 65 | 66 | if (var_map_.count("help")) 67 | { 68 | desc.add(encrypt_desc).add(decrypt_desc).add(crack_desc); 69 | std::cout << desc << std::endl; 70 | return; 71 | } 72 | 73 | if (!initialize_cipher()) 74 | { 75 | std::cout << "\nUsage: crack [general options] [cipher options] [encrypt/decrypt/crack options]\n" 76 | "Run \"crack -h\" for more detailed information.\n\n"; 77 | return; 78 | } 79 | 80 | if (var_map_.count("encrypt")) 81 | { 82 | desc.add(encrypt_desc); 83 | po::store(po::parse_command_line(argc, argv, desc), var_map_); 84 | do_action(Action::Encrypt); 85 | } 86 | else if(var_map_.count("decrypt")) 87 | { 88 | desc.add(decrypt_desc); 89 | po::store(po::parse_command_line(argc, argv, desc), var_map_); 90 | do_action(Action::Decrypt); 91 | } 92 | else if(var_map_.count("crack")) 93 | { 94 | desc.add(crack_desc); 95 | po::store(po::parse_command_line(argc, argv, desc), var_map_); 96 | do_action(Action::Crack); 97 | } 98 | else 99 | { 100 | std::cout << "\nUsage: crack [general options] [cipher options] [encrypt/decrypt/crack options]\n" 101 | "Run \"crack -h\" for more detailed information.\n\n"; 102 | } 103 | } 104 | 105 | bool Console_manager::initialize_cipher() 106 | { 107 | if (var_map_.count("Caesar")) 108 | { 109 | cipher_ = new Caesar; 110 | return true; 111 | } 112 | else if (var_map_.count("Affine")) 113 | { 114 | cipher_ = new Affine; 115 | return true; 116 | } 117 | else if (var_map_.count("Vigenere")) 118 | { 119 | cipher_ = new Vigener; 120 | return true; 121 | } 122 | else if (var_map_.count("SimpleSub")) 123 | { 124 | cipher_ = new SimpleSubstitution; 125 | return true; 126 | } 127 | else if (var_map_.count("Polybius")) 128 | { 129 | cipher_ = new Polybius; 130 | return true; 131 | } 132 | 133 | return false; 134 | } 135 | 136 | void Console_manager::do_action(Action action) 137 | { 138 | std::string key; // a key for encrypting (decrypting) 139 | std::string output_path; // output path to a file with encrypted (decrypted) text 140 | 141 | if (var_map_.count("input")) 142 | { 143 | std::ifstream ifs(var_map_["input"].as()); 144 | if (!ifs) 145 | { 146 | std::cout << "\nError trying open input file\n\n"; 147 | ifs.close(); 148 | return; 149 | } 150 | cipher_->text_source_in(ifs); 151 | ifs.close(); 152 | } 153 | else cipher_->text_source_in(std::cin); 154 | 155 | if(var_map_.count("key")) 156 | key = var_map_["key"].as(); 157 | 158 | switch (action) 159 | { 160 | case Action::Encrypt: cipher_->encrypt(key); break; 161 | case Action::Decrypt: cipher_->decrypt(key); break; 162 | case Action::Crack: cipher_->crack(); break; 163 | } 164 | 165 | if(var_map_.count("output")) 166 | { 167 | std::ofstream ofs(var_map_["output"].as()); 168 | if (!ofs) 169 | { 170 | std::cout << "\nError trying open output file\n\n"; 171 | ofs.close(); 172 | return; 173 | } 174 | cipher_->text_modified_out(ofs); 175 | ofs.close(); 176 | } 177 | else 178 | { 179 | cipher_->text_modified_out(std::cout); 180 | std::cout << std::endl; 181 | } 182 | } -------------------------------------------------------------------------------- /sources/Affine.cpp: -------------------------------------------------------------------------------- 1 | #include "Affine.hpp" 2 | #include "data_alphabet.hpp" 3 | #include 4 | 5 | int count_reverse_number(int num, unsigned int mode); 6 | std::size_t count_remainder(int a, std::size_t m); 7 | int count_GCD(int firstNumber, int secondNumber); 8 | 9 | Affine::Affine(unsigned log_level) : Cipher(log_level), 10 | frequency_table_(ENGLISH_LETTER_FREQUENCIES), 11 | alphabet_(ENGLISH_ALPHABET), 12 | alphabet_len_(ENGLISH_ALPHABET_LEN), 13 | key_() 14 | { 15 | Log::Logger()->log(Log::Debug, "Affine::created"); 16 | } 17 | 18 | void Affine::encrypt(const std::string& key) // key = "a,b" 19 | { 20 | Log::Logger()->log(Log::Debug, "Affine::trying to encrypt"); 21 | key_ = parse_key(key); 22 | change_text_source(); 23 | 24 | for (char c : text_source_) 25 | text_modified_+= static_cast((key_.a * (c - alphabet_[0]) + key_.b) % alphabet_len_ + alphabet_[0]); 26 | Log::Logger()->log(Log::Debug, "Affine::encrypted"); 27 | } 28 | 29 | void Affine::decrypt(const std::string& key) 30 | { 31 | Log::Logger()->log(Log::Debug, "Affine::trying to decrypt"); 32 | key_ = parse_key(key); 33 | change_text_source(); 34 | text_modified_ = decrypt(key_); 35 | Log::Logger()->log(Log::Debug, "Affine::decrypted"); 36 | } 37 | 38 | void Affine::crack() 39 | { 40 | Log::Logger()->log(Log::Debug, "Affine::trying to crack"); 41 | change_text_source(); 42 | double max = 0.0; 43 | std::string current; 44 | 45 | for (std::size_t i = 1; i < alphabet_len_; i += 2) 46 | { 47 | if (count_GCD(i, alphabet_len_) != 1) 48 | continue; 49 | 50 | for (std::size_t j = 0; j < alphabet_len_; j++) 51 | { 52 | current = decrypt(Key(i, j)); 53 | auto val = count_coefficient(current); 54 | if (val > max) 55 | { 56 | max = val; 57 | text_modified_ = current; 58 | } 59 | } 60 | } 61 | Log::Logger()->log(Log::Debug, "Affine::cracked"); 62 | } 63 | 64 | Affine::Key::Key(int a, int b) : a(a), b(b) {} 65 | 66 | std::string Affine::decrypt(const Key& key) const 67 | { 68 | std::string res; 69 | auto rev_a = count_reverse_number(key.a, alphabet_len_); 70 | 71 | for (char c : text_source_) 72 | res += static_cast(count_remainder(rev_a * (c - alphabet_[0] - key.b), alphabet_len_) + alphabet_[0]); 73 | 74 | return res; 75 | } 76 | 77 | Affine::Key Affine::parse_key(const std::string& key) 78 | { 79 | Log::Logger()->log(Log::Debug, "Affine::trying parse key"); 80 | auto found = key.find(','); 81 | if (found == std::string::npos) 82 | { 83 | Log::Logger()->log(Log::Error, "Affine::bad key"); 84 | Log::Logger()->log(Log::Info, "Affine::key is "); 85 | Log::Logger()->log(Log::Info, key); 86 | throw std::invalid_argument("Invalid key"); 87 | } 88 | 89 | std::istringstream iss(key.substr(0, found)); 90 | int a = 0; 91 | if (!(iss >> a)) 92 | { 93 | Log::Logger()->log(Log::Error, "Affine::bad key"); 94 | Log::Logger()->log(Log::Info, "Affine::key is "); 95 | Log::Logger()->log(Log::Info, key); 96 | throw std::invalid_argument("Invalid key"); 97 | } 98 | 99 | if (count_GCD(a, static_cast(alphabet_len_)) != 1) 100 | { 101 | Log::Logger()->log(Log::Error, "Affine::bad key"); 102 | Log::Logger()->log(Log::Info, "Affine::key is "); 103 | Log::Logger()->log(Log::Info, key); 104 | throw std::invalid_argument("Invalid key: a and alphabet length must be comprime integers"); 105 | } 106 | 107 | iss = std::istringstream(key.substr(found + 1, key.length() - found - 1)); 108 | int b = 0; 109 | if (!(iss >> b)) 110 | { 111 | Log::Logger()->log(Log::Error, "Affine::bad key"); 112 | Log::Logger()->log(Log::Info, "Affine::key is "); 113 | Log::Logger()->log(Log::Info, key); 114 | throw std::invalid_argument("Invalid key"); 115 | } 116 | 117 | Log::Logger()->log(Log::Debug, "Affine::success parsing"); 118 | return {a, b}; 119 | } 120 | 121 | void Affine::change_text_source() 122 | { 123 | Log::Logger()->log(Log::Debug, "Affine::trying to change text to work well"); 124 | std::string new_text_source; 125 | 126 | for (char c : text_source_) 127 | if (from_this_alphabet(static_cast(tolower(c)))) 128 | { 129 | new_text_source += static_cast(tolower(c)); 130 | } 131 | else 132 | { 133 | Log::Logger()->log(Log::Warn, "Affine::letter is not from this alphabet"); 134 | Log::Logger()->log(Log::Info, "Affine::letter is"); 135 | Log::Logger()->log(Log::Info, std::to_string(tolower(c))); 136 | } 137 | 138 | 139 | text_source_ = new_text_source; 140 | Log::Logger()->log(Log::Debug, "Affine::text is ready to be modified"); 141 | } 142 | 143 | bool Affine::from_this_alphabet(char letter) const noexcept 144 | { 145 | for (std::size_t i = 0; i < alphabet_len_; ++i) 146 | if (letter == alphabet_[i]) 147 | return true; 148 | 149 | return false; 150 | } 151 | 152 | double Affine::count_coefficient(const std::string& text) const 153 | { 154 | Log::Logger()->log(Log::Debug, "Affine::trying to calculate corfficient"); 155 | auto frequencies = new double[alphabet_len_]; 156 | for (std::size_t i = 0; i < alphabet_len_; i++) 157 | frequencies[i] = 0; 158 | 159 | for (char c : text) 160 | ++frequencies[c - alphabet_[0]]; 161 | 162 | for (auto i = 0; i < alphabet_len_; i++) 163 | frequencies[i] /= text.length(); 164 | 165 | double res = 0.0; 166 | for (std::size_t i = 0; i < alphabet_len_; i++) 167 | res += frequency_table_[i] * frequencies[i] / 100.0; 168 | 169 | delete[] frequencies; 170 | Log::Logger()->log(Log::Debug, "Affine::success calculation"); 171 | return res; 172 | } 173 | 174 | void extended_euclid(int a, int b, int& x, int& y, int& d) 175 | { 176 | Log::Logger()->log(Log::Debug, "Affine::trying to find expression of extended_euclid"); 177 | if (b == 0) 178 | { 179 | d = a; 180 | x = 1; 181 | y = 0; 182 | return; 183 | } 184 | 185 | int x2 = 1; 186 | int x1 = 0; 187 | int y2 = 0; 188 | int y1 = 1; 189 | 190 | while (b > 0) 191 | { 192 | int q = a / b; 193 | int r = a - q * b; 194 | x = x2 - q * x1; 195 | y = y2 - q * y1; 196 | a = b; 197 | b = r; 198 | x2 = x1; 199 | x1 = x; 200 | y2 = y1; 201 | y1 = y; 202 | } 203 | 204 | x = x2; 205 | y = y2; 206 | d = a; 207 | Log::Logger()->log(Log::Debug, "Affine::success in extended_euclid"); 208 | } 209 | 210 | int count_reverse_number(int num, unsigned int mode) 211 | { 212 | Log::Logger()->log(Log::Debug, "Affine::trying to find reverse number"); 213 | int d = 0; 214 | int x = 0; 215 | int y = 0; 216 | 217 | extended_euclid(num, mode, x, y, d); 218 | 219 | Log::Logger()->log(Log::Debug, "Affine::reverse number is found"); 220 | if (d == 1) 221 | return (x >= 0) ? x : x + mode; 222 | 223 | return 0; 224 | } 225 | 226 | std::size_t count_remainder(int a, std::size_t m) 227 | { 228 | int res = a % static_cast(m); 229 | return (res >= 0) ? res : res + m; 230 | } 231 | 232 | int count_GCD(int firstNumber, int secondNumber) 233 | { 234 | while (firstNumber != 0 && secondNumber != 0) 235 | if (firstNumber > secondNumber) 236 | firstNumber = firstNumber % secondNumber; 237 | else 238 | secondNumber = secondNumber % firstNumber; 239 | 240 | return firstNumber + secondNumber; 241 | } -------------------------------------------------------------------------------- /sources/Caesar.cpp: -------------------------------------------------------------------------------- 1 | #include"Caesar.hpp" 2 | 3 | Caesar::Caesar(char letter_first, bool need_spaces, unsigned log_level, unsigned top) 4 | : 5 | Cipher(log_level), 6 | key_(0), 7 | letter_first_(letter_first), 8 | frequency_table_(nullptr), 9 | alphabet_(nullptr), 10 | need_spaces_(need_spaces), 11 | top_(top) { 12 | 13 | Log::Logger()->log(Log::Debug, "Caesar::Creating Caesar"); 14 | Log::Logger()->log(Log::Info, " Caesar::First letter of alphabet: "); 15 | Log::Logger()->log(Log::Info, std::to_string(letter_first)); 16 | switch (letter_first_) { 17 | case'a': 18 | alphabet_len_ = ENGLISH_ALPHABET_LEN; 19 | frequency_table_ = ENGLISH_LETTER_FREQUENCIES; 20 | alphabet_ = ENGLISH_ALPHABET; 21 | break; 22 | default: 23 | Log::Logger()->log(Log::Error, "Fatall. Caesar::has no this alphabet"); 24 | throw std::invalid_argument("Invalid alphabet"); 25 | break; 26 | } 27 | 28 | letters_count_ = new std::size_t[alphabet_len_]; 29 | Log::Logger()->log(Log::Debug, "Caesar::Created"); 30 | 31 | } 32 | 33 | void Caesar::encrypt(const std::string& key) { 34 | 35 | Log::Logger()->log(Log::Debug, "Caesar::want to encrypt"); 36 | if (!prepare_to_modify(key)) { 37 | Log::Logger()->log(Log::Error, "Caesar::bad key"); 38 | Log::Logger()->log(Log::Info, " Caesar::key is"); 39 | Log::Logger()->log(Log::Info, key); 40 | throw std::invalid_argument("Invalid key"); 41 | } 42 | encr(); 43 | if (need_spaces_) { 44 | text_modified_ = spaces_reborn(text_modified_); 45 | } 46 | } 47 | 48 | void Caesar::decrypt(const std::string& key) { 49 | 50 | Log::Logger()->log(Log::Debug, "Caesar::want to decrypt"); 51 | if (!prepare_to_modify(key)) { 52 | throw std::invalid_argument("Invalid key"); 53 | } 54 | decr(); 55 | if (need_spaces_) { 56 | text_modified_ = spaces_reborn(text_modified_); 57 | } 58 | } 59 | 60 | void Caesar::crack() { 61 | 62 | Log::Logger()->log(Log::Debug, "Caesar::Trying to crack"); 63 | if (top_) { 64 | top_vector_.clear(); 65 | top_vector_.assign((top_ < alphabet_len_) ? top_ : alphabet_len_, decryptod()); 66 | } 67 | spaces_pos_.clear(); 68 | text_to_lower(); 69 | 70 | if (text_source_.length() == 0) { 71 | Log::Logger()->log(Log::Warn, "Caesar::text is empty to crack"); 72 | Log::Logger()->log(Log::Debug, "Caesar::refused to crack"); 73 | throw(std::logic_error("Text is too short")); 74 | return; 75 | } 76 | float max_probability = 0; 77 | int cur_key = 1; 78 | int max_probability_key = 1; 79 | 80 | 81 | while (cur_key < alphabet_len_) { 82 | 83 | key_ = cur_key; 84 | text_modified_ = ""; 85 | decr(); 86 | 87 | for (std::size_t i = 0; i < alphabet_len_; ++i) { 88 | letters_count_[i] = 0; 89 | } 90 | std::size_t max_letters = text_modified_.length(); 91 | for (std::size_t i = 0; i < max_letters; ++i) { 92 | letters_count_[text_modified_[i] - letter_first_] += 1; 93 | } 94 | 95 | double cur_probability = 0; 96 | for (std::size_t i = 0; i < alphabet_len_; ++i) { 97 | cur_probability += ((letters_count_[i] * 1.0) / max_letters ) * (frequency_table_[i] / 100); 98 | } 99 | if (top_) { 100 | add_decryptod({ text_modified_, cur_key, cur_probability }); 101 | } 102 | if (cur_probability > max_probability) { 103 | max_probability = cur_probability; 104 | max_probability_key = cur_key; 105 | } 106 | ++cur_key; 107 | } 108 | 109 | key_ = max_probability_key; 110 | text_modified_ = ""; 111 | decr(); 112 | if (need_spaces_) { 113 | text_modified_ = spaces_reborn(text_modified_); 114 | } 115 | Log::Logger()->log(Log::Debug, "Caesar::cracking is completed"); 116 | } 117 | 118 | void Caesar::text_to_lower() { 119 | 120 | Log::Logger()->log(Log::Debug, "Caesar::doing text comfortable to work with"); 121 | std::string new_text_source = ""; 122 | std::size_t text_source_size = text_source_.length(); 123 | for (std::size_t i = 0; i < text_source_size; ++i) { 124 | if (from_this_alphabet(tolower(text_source_[i]))) { 125 | new_text_source += tolower(text_source_[i]); 126 | } else { 127 | if (need_spaces_) { 128 | spaces_pos_.insert(i); 129 | } 130 | Log::Logger()->log(Log::Warn, " Caesar::letter is not from selected alphabet"); 131 | Log::Logger()->log(Log::Info, " Caesar::letter is "); 132 | Log::Logger()->log(Log::Info, std::to_string(text_source_[i])); 133 | } 134 | } 135 | 136 | text_source_ = new_text_source; 137 | Log::Logger()->log(Log::Debug, "Caesar::done text comfortable"); 138 | 139 | } 140 | 141 | bool Caesar::prepare_to_modify(const std::string & key) { 142 | 143 | Log::Logger()->log(Log::Debug, "Caesar::preparing to modify"); 144 | key_ = 0; 145 | spaces_pos_.clear(); 146 | 147 | std::istringstream sstream(key); 148 | int new_key = 0; 149 | if (!(sstream >> new_key)) { 150 | return false; 151 | } 152 | 153 | text_to_lower(); 154 | 155 | while(new_key < 0) { 156 | new_key += alphabet_len_; 157 | } 158 | 159 | key_ = new_key % alphabet_len_; 160 | text_modified_ = ""; 161 | Log::Logger()->log(Log::Debug, "Caesar::is ready to be modified"); 162 | 163 | return true; 164 | } 165 | 166 | bool Caesar::from_this_alphabet(char letter) const { 167 | 168 | for (std::size_t i = 0; i < alphabet_len_; ++i) { 169 | if (letter == alphabet_[i]) { 170 | return true; 171 | } 172 | } 173 | 174 | return false; 175 | } 176 | 177 | void Caesar::encr() { 178 | 179 | Log::Logger()->log(Log::Debug, "Caesar::tring to encrypt"); 180 | std::size_t text_source_size = text_source_.length(); 181 | for (std::size_t i = 0; i < text_source_size; ++i) { 182 | char letter_modified = (text_source_[i] - letter_first_ + key_) % (alphabet_len_)+letter_first_; 183 | text_modified_ += letter_modified; 184 | } 185 | Log::Logger()->log(Log::Debug, "Caesar::encrypting done"); 186 | } 187 | 188 | void Caesar::decr() { 189 | 190 | Log::Logger()->log(Log::Debug, "Caesar::tring to decrypt"); 191 | std::size_t text_source_size = text_source_.length(); 192 | for (std::size_t i = 0; i < text_source_size; ++i) { 193 | int pos = (text_source_[i] - letter_first_ - key_); 194 | while (pos < 0) { 195 | pos += alphabet_len_; 196 | } 197 | char letter_modified = pos % (alphabet_len_)+letter_first_; 198 | text_modified_ += letter_modified; 199 | } 200 | Log::Logger()->log(Log::Debug, "Caesar::decrypting done"); 201 | } 202 | 203 | Caesar::~Caesar() { 204 | delete[] letters_count_; 205 | } 206 | 207 | std::string Caesar::spaces_reborn(std::string const & text_modified) { 208 | 209 | Log::Logger()->log(Log::Debug, "Caesar::trying to reborn spaces"); 210 | if (spaces_pos_.size() > 0) { 211 | std::size_t new_text_len = text_modified.length() + spaces_pos_.size(); 212 | std::size_t spaces_count = 0; 213 | std::string new_text_modified = ""; 214 | auto end = spaces_pos_.end(); 215 | for (std::size_t i = 0; i < new_text_len; ++i) { 216 | if (spaces_pos_.find(i) != end) { 217 | new_text_modified += " "; 218 | ++spaces_count; 219 | } else { 220 | new_text_modified += text_modified[i - spaces_count]; 221 | } 222 | } 223 | Log::Logger()->log(Log::Debug, "Caesar::complete spaces reborn"); 224 | return new_text_modified; 225 | } 226 | 227 | Log::Logger()->log(Log::Debug, "Caesar::complete spaces reborn, but don't find it"); 228 | return text_modified; 229 | } 230 | 231 | void Caesar::change_spaces_mode() { 232 | 233 | need_spaces_ = !need_spaces_; 234 | } 235 | 236 | void Caesar::add_decryptod(decryptod decr) { 237 | 238 | std::size_t top_len = top_vector_.size(); // or (top_ < alphabet_len) ? top_ : alphabet_len_ 239 | bool find_place = false; 240 | for (std::size_t i = 0; i < top_len; ++i) { 241 | if (top_vector_[i].factor_ < decr.factor_) { 242 | find_place = true; 243 | } 244 | if (find_place) { 245 | decryptod old_decr = top_vector_[i]; 246 | top_vector_[i] = decr; 247 | decr = old_decr; 248 | } 249 | } 250 | } 251 | 252 | std::vector> Caesar::get_top() { 253 | 254 | return top_vector_; 255 | } 256 | 257 | //+out 258 | 259 | std::ostream & Caesar::top_out(std::ostream & out) { 260 | 261 | if (!top_) { 262 | return out; 263 | } 264 | 265 | std::size_t top_len = top_vector_.size(); // top_ or alphabet_len_ 266 | for (std::size_t i = top_len; i > 0; --i) { 267 | 268 | if (need_spaces_) { 269 | top_vector_[i - 1].text_ = spaces_reborn(top_vector_[i - 1].text_); 270 | } 271 | 272 | out << i << ".\n"; 273 | out << "Text:\n" << top_vector_[i - 1].text_ << "\n"; 274 | out << "Key: " << top_vector_[i - 1].key_ << "\n"; 275 | out << "Factor: " << top_vector_[i - 1].factor_ << "\n\n"; 276 | } 277 | 278 | return out; 279 | } 280 | 281 | std::ofstream & Caesar::top_out(std::ofstream & out) { 282 | 283 | if (!top_) { 284 | return out; 285 | } 286 | 287 | std::size_t top_len = top_vector_.size(); // top_ or alphabet_len_ 288 | for (std::size_t i = 0; i < top_len; ++i) { 289 | 290 | if (need_spaces_) { 291 | top_vector_[i].text_ = spaces_reborn(top_vector_[i].text_); 292 | } 293 | 294 | out << i + 1 << ".\n"; 295 | out << "Text:\n" << top_vector_[i].text_ << "\n"; 296 | out << "Key: " << top_vector_[i].key_ << "\n"; 297 | out << "Factor: " << top_vector_[i].factor_ << "\n\n"; 298 | } 299 | 300 | return out; 301 | } 302 | 303 | -------------------------------------------------------------------------------- /sources/SimpleSubstitution.cpp: -------------------------------------------------------------------------------- 1 | #include "SimpleSubstitution.hpp" 2 | #include "data_alphabet.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include //std::greater 8 | 9 | template 10 | std::size_t find_first_index(const T* arr, std::size_t len, T value); 11 | 12 | SimpleSubstitution::SimpleSubstitution(unsigned log_level) : Cipher(log_level), 13 | frequency_table_(ENGLISH_LETTER_FREQUENCIES), 14 | alphabet_(ENGLISH_ALPHABET), 15 | alphabet_len_(ENGLISH_ALPHABET_LEN), 16 | bigrams_freq_table_(), 17 | current_bigrams_freq_table_() 18 | { 19 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::created"); 20 | } 21 | 22 | void SimpleSubstitution::encrypt(const std::string& key) 23 | { 24 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::trying to encrypt"); 25 | if (check_key(key)) key_ = key; 26 | else 27 | { 28 | Log::Logger()->log(Log::Error, "SimpleSubstitution::bad key"); 29 | Log::Logger()->log(Log::Info, "SimpleSubstitution::key is"); 30 | Log::Logger()->log(Log::Info, key); 31 | throw std::invalid_argument("Incorrect key"); 32 | } 33 | change_text_source(); 34 | 35 | for (char c : text_source_) 36 | text_modified_ += key[find_first_index(alphabet_, alphabet_len_, c)]; 37 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::encrypted"); 38 | } 39 | 40 | void SimpleSubstitution::decrypt(const std::string& key) 41 | { 42 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::trying to decrypt"); 43 | if (check_key(key)) key_ = key; 44 | else 45 | { 46 | Log::Logger()->log(Log::Error, "SimpleSubstitution::bad key"); 47 | Log::Logger()->log(Log::Info, "SimpleSubstitution::key is"); 48 | Log::Logger()->log(Log::Info, key); 49 | throw std::invalid_argument("Incorrect key"); 50 | } 51 | change_text_source(); 52 | text_modified_ = decr(key_); 53 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::decrypted"); 54 | } 55 | 56 | void SimpleSubstitution::crack() 57 | { 58 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::trying to crack"); 59 | // Primary key calculation 60 | std::vector current_freqs_table(alphabet_len_, 0.0); // letters' frequencies of cipher text 61 | 62 | for (char c : text_source_) 63 | current_freqs_table[find_first_index(alphabet_, alphabet_len_, c)] += 1.0; 64 | 65 | for (auto i = 0; i < alphabet_len_; ++i) 66 | { 67 | current_freqs_table[i] = current_freqs_table[i] / text_source_.length() * 100.0; 68 | for (auto j = 0; j < i; ++j) 69 | if (current_freqs_table[i] == current_freqs_table[j]) 70 | current_freqs_table[i] -= 0.00000000001; // to exclude equal frequencies 71 | } 72 | 73 | std::vector current_freqs_sorted = current_freqs_table; // letters' frequencies of cipher text, sorted by descending frequency 74 | std::sort(current_freqs_sorted.begin(), current_freqs_sorted.end(), std::greater()); 75 | 76 | std::vector freq_table_sorted(alphabet_len_); // standart frequency table, sorted by descending frequency 77 | for (auto i = 0; i < alphabet_len_; ++i) 78 | freq_table_sorted[i] = (double)frequency_table_[i]; 79 | std::sort(freq_table_sorted.begin(), freq_table_sorted.end(), std::greater()); 80 | 81 | std::string key(alphabet_len_, ' '); 82 | 83 | // forming the most suitable primary key (based on letters' frequencies of cipher text) 84 | for (auto i = 0; i < alphabet_len_; ++i) 85 | { 86 | auto symb = alphabet_[std::find(current_freqs_table.begin(), current_freqs_table.end(), current_freqs_sorted[i]) - current_freqs_table.begin()]; 87 | key[find_first_index(frequency_table_, alphabet_len_, static_cast(freq_table_sorted[i]))] = symb; 88 | } 89 | 90 | // decrypting text_source_ with primary key 91 | auto text = decr(key); 92 | 93 | // counting bigrams coefficient for text 94 | load_bigrams_freq(); 95 | 96 | auto bigrams_rating = count_bigrams_coefficient(text); 97 | auto prev_bigrams_rating = bigrams_rating; 98 | auto step = 1; 99 | 100 | // trying to find key with the lowest bigrams_rating rearranging 2 letters (using step) in the key 101 | while (true) 102 | { 103 | auto find_good_key = false; 104 | 105 | for (auto i = 0; i < alphabet_len_; ++i) 106 | { 107 | if (i + step >= alphabet_len_) 108 | break; 109 | 110 | auto q = key.find_first_of(alphabet_[std::find(current_freqs_table.begin(), current_freqs_table.end(), 111 | current_freqs_sorted[i]) - current_freqs_table.begin()]); 112 | auto p = key.find_first_of(alphabet_[std::find(current_freqs_table.begin(), current_freqs_table.end(), 113 | current_freqs_sorted[i + step]) - current_freqs_table.begin()]); 114 | std::swap(key[q], key[p]); 115 | 116 | text = decr(key); 117 | bigrams_rating = count_bigrams_coefficient(text); 118 | 119 | if (bigrams_rating < prev_bigrams_rating) 120 | { 121 | find_good_key = true; 122 | prev_bigrams_rating = bigrams_rating; 123 | step = 1; 124 | break; 125 | } 126 | 127 | std::swap(key[q], key[p]); 128 | } 129 | 130 | if (!find_good_key) 131 | { 132 | ++step; 133 | if (step >= alphabet_len_ - 1) 134 | break; 135 | } 136 | } 137 | 138 | text_modified_ = decr(key); 139 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::cracked"); 140 | } 141 | 142 | bool SimpleSubstitution::check_key(const std::string& key) const noexcept 143 | { 144 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::cheking key"); 145 | for (auto i = 1; i < key.length(); ++i) 146 | for (auto j = 0; j < i; ++j) 147 | if (key[i] == key[j]) 148 | return false; 149 | return true; 150 | } 151 | 152 | void SimpleSubstitution::change_text_source() noexcept 153 | { 154 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::chganging text to work better with"); 155 | std::string new_text_source; 156 | 157 | for (char c : text_source_) 158 | if (from_this_alphabet(static_cast(tolower(c)))) 159 | new_text_source += static_cast(tolower(c)); 160 | else 161 | { 162 | Log::Logger()->log(Log::Warn, "SimpleSubstitution::letter is not from this alphanet"); 163 | Log::Logger()->log(Log::Info, "SimpleSubstitution::letter is "); 164 | Log::Logger()->log(Log::Info, std::to_string(tolower(c))); 165 | } 166 | 167 | text_source_ = new_text_source; 168 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::success in changing text to work better with"); 169 | } 170 | 171 | bool SimpleSubstitution::from_this_alphabet(char letter) const noexcept 172 | { 173 | for (std::size_t i = 0; i < alphabet_len_; ++i) 174 | if (letter == alphabet_[i]) 175 | return true; 176 | return false; 177 | } 178 | 179 | std::string SimpleSubstitution::decr(const std::string& key) const noexcept 180 | { 181 | std::string res; 182 | for (char c : text_source_) 183 | res += alphabet_[find_first_index(key.c_str(), key.length(), c)]; 184 | return res; 185 | } 186 | 187 | void SimpleSubstitution::load_bigrams_freq() noexcept 188 | { 189 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::loading bigrams"); 190 | std::ifstream ifs("../sources/english_bigrams.txt"); 191 | std::string str; 192 | 193 | while(std::getline(ifs, str)) 194 | { 195 | double key = 0.0; 196 | std::istringstream sstream(str.substr(3, str.length() - 3)); 197 | sstream >> key; 198 | bigrams_freq_table_.insert(std::pair(str.substr(0, 2), key)); 199 | current_bigrams_freq_table_.insert(std::pair(str.substr(0, 2), 0.0)); 200 | } 201 | 202 | ifs.close(); 203 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::completed loading bigrams"); 204 | 205 | } 206 | 207 | double SimpleSubstitution::count_bigrams_coefficient(const std::string& text) noexcept 208 | { 209 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::calculating bigrams coefficient"); 210 | for (std::size_t i = 1; i < text.length(); ++i) 211 | { 212 | std::string temp = std::string(1, text[i - 1]) + std::string(1, text[i]); 213 | if (current_bigrams_freq_table_.find(temp) == current_bigrams_freq_table_.end()) 214 | current_bigrams_freq_table_.insert(std::pair(temp, 1.0)); 215 | else 216 | current_bigrams_freq_table_[temp] += 1.0; 217 | } 218 | 219 | double bigrams_rating = 0.0; 220 | 221 | for (auto& current_bigram_freq : current_bigrams_freq_table_) 222 | { 223 | current_bigram_freq.second = (current_bigram_freq.second / (text.length() - 1)) * 100.0; 224 | if (bigrams_freq_table_.find(current_bigram_freq.first) == bigrams_freq_table_.end()) 225 | bigrams_rating += pow(current_bigram_freq.second, 2.0); 226 | else 227 | bigrams_rating += pow(current_bigram_freq.second - bigrams_freq_table_.at(current_bigram_freq.first), 2.0); 228 | } 229 | 230 | Log::Logger()->log(Log::Debug, "SimpleSubstitution::completed calclulating bigrams coefficient"); 231 | return bigrams_rating; 232 | } 233 | 234 | template 235 | std::size_t find_first_index(const T* arr, std::size_t len, T value) 236 | { 237 | for (std::size_t i = 0; i < len; ++i) 238 | if (arr[i] == value) 239 | return i; 240 | return len; 241 | } -------------------------------------------------------------------------------- /sources/Polybius.cpp: -------------------------------------------------------------------------------- 1 | #include "Polybius.hpp" 2 | #include "data_alphabet.hpp" 3 | #include 4 | #include 5 | #include 6 | #include //std::greater 7 | 8 | Polybius::Polybius(unsigned log_level) : Cipher(log_level), 9 | alphabet_len_(ENGLISH_ALPHABET_LEN - 1), 10 | key_(5, 5), 11 | bigrams_freq_table_(), 12 | current_bigrams_freq_table_() 13 | { 14 | alphabet_ = std::vector(alphabet_len_); 15 | int j = 0; 16 | for (auto i = 0; i < alphabet_len_; ++i) // for english alphabet 17 | { 18 | if (ENGLISH_ALPHABET[i] == 'j') j = 1; 19 | alphabet_[i] = ENGLISH_ALPHABET[i + j]; 20 | } 21 | 22 | frequency_table_ = std::vector(alphabet_len_); 23 | j = 0; 24 | for (auto i = 0; i < alphabet_len_; ++i) // for english alphabet 25 | { 26 | if (i == 9) j = 1; 27 | frequency_table_[i] = ENGLISH_LETTER_FREQUENCIES[i + j]; 28 | } 29 | Log::Logger()->log(Log::Debug, "Polibius::created"); 30 | } 31 | 32 | void Polybius::encrypt(const std::string& key) 33 | { 34 | Log::Logger()->log(Log::Debug, "Polibius::trying to encrypt"); 35 | if (!check_key(key)) 36 | { 37 | Log::Logger()->log(Log::Error, "Polibius::bad key"); 38 | Log::Logger()->log(Log::Info, "Polibius::key is"); 39 | Log::Logger()->log(Log::Info, key); 40 | throw std::invalid_argument("Incorrect key"); 41 | } 42 | key_ = parse_key(key); 43 | change_text_source(); 44 | 45 | for (char c : text_source_) 46 | { 47 | int row = 0; 48 | int col = 0; 49 | for (auto j = 0; j < key_.rows; ++j) 50 | { 51 | for (auto k = 0; k < key_.cols; ++k) 52 | { 53 | if (key_.matrix[j][k] == c) 54 | { 55 | row = j; 56 | col = k; 57 | break; 58 | } 59 | } 60 | } 61 | text_modified_ += alphabet_[row]; 62 | text_modified_ += alphabet_[col]; 63 | } 64 | Log::Logger()->log(Log::Debug, "Polibius::encrypted"); 65 | } 66 | 67 | void Polybius::decrypt(const std::string& key) 68 | { 69 | Log::Logger()->log(Log::Debug, "Polibius::trying to decrypt"); 70 | if (!check_key(key)) 71 | { 72 | Log::Logger()->log(Log::Error, "Polibius::bad key"); 73 | Log::Logger()->log(Log::Info, "Polibius::key is"); 74 | Log::Logger()->log(Log::Info, key); 75 | throw std::invalid_argument("Incorrect key"); 76 | } 77 | key_ = parse_key(key); 78 | change_text_source(); 79 | auto length = text_source_.length() / 2; 80 | for (auto i = 0; i < length; ++i) 81 | text_modified_ += key_.matrix[text_source_[2 * i] - alphabet_[0]][text_source_[2 * i + 1] - alphabet_[0]]; 82 | Log::Logger()->log(Log::Debug, "Polibius::decrypted"); 83 | } 84 | 85 | void Polybius::crack() // for english alphabet 86 | { 87 | Log::Logger()->log(Log::Debug, "Polibius::trying to crack"); 88 | // Primary key calculation 89 | std::vector current_freqs_table(alphabet_len_, 0.0); // letters' frequencies of cipher text (0 - aa, 1 - ab, 2 - ac...) 90 | 91 | auto l = text_source_.length() / 2; 92 | for (auto i = 0; i < l; ++i) 93 | { 94 | auto index = (text_source_[2 * i] - alphabet_[0]) * 5 + text_source_[2 * i + 1] - alphabet_[0]; 95 | current_freqs_table[index] += 1.0; 96 | } 97 | 98 | for (auto i = 0; i < alphabet_len_; ++i) 99 | { 100 | current_freqs_table[i] = current_freqs_table[i] / l * 100.0; 101 | for (auto j = 0; j < i; ++j) 102 | if (current_freqs_table[i] == current_freqs_table[j]) 103 | current_freqs_table[i] -= 0.00000000001; // to exclude equal frequencies 104 | } 105 | 106 | auto current_freqs_sorted = current_freqs_table; // letters' frequencies of cipher text, sorted by descending frequency 107 | std::sort(current_freqs_sorted.begin(), current_freqs_sorted.end(), std::greater()); 108 | 109 | auto freq_table_sorted = frequency_table_; // standart frequency table, sorted by descending frequency 110 | std::sort(freq_table_sorted.begin(), freq_table_sorted.end(), std::greater()); 111 | 112 | std::string key(alphabet_len_, ' '); 113 | 114 | // forming the most suitable primary key (based on letters' frequencies of cipher text) 115 | for (auto i = 0; i < alphabet_len_; ++i) 116 | { 117 | auto symb = alphabet_[std::find(frequency_table_.begin(), frequency_table_.end(), freq_table_sorted[i]) - frequency_table_.begin()]; 118 | key[std::find(current_freqs_table.begin(), current_freqs_table.end(), current_freqs_sorted[i]) - current_freqs_table.begin()] = symb; 119 | } 120 | 121 | // decrypting text_source_ with primary key 122 | auto text = decr(key); 123 | 124 | // counting bigrams coefficient for text 125 | load_bigrams_freq(); 126 | 127 | auto bigrams_rating = count_bigrams_coefficient(text); 128 | auto prev_bigrams_rating = bigrams_rating; 129 | auto step = 1; 130 | 131 | // trying to find key with the lowest bigrams_rating rearranging 2 letters (using step) in the key 132 | while (true) 133 | { 134 | auto find_good_key = false; 135 | 136 | for (auto i = 0; i < alphabet_len_; ++i) 137 | { 138 | if (i + step >= alphabet_len_) 139 | break; 140 | 141 | auto q = key.find_first_of(alphabet_[std::find(current_freqs_table.begin(), current_freqs_table.end(), current_freqs_sorted[i]) - current_freqs_table.begin()]); 142 | auto p = key.find_first_of(alphabet_[std::find(current_freqs_table.begin(), current_freqs_table.end(), current_freqs_sorted[i + step]) - current_freqs_table.begin()]); 143 | std::swap(key[q], key[p]); 144 | 145 | text = decr(key); 146 | bigrams_rating = count_bigrams_coefficient(text); 147 | 148 | if (bigrams_rating < prev_bigrams_rating) 149 | { 150 | find_good_key = true; 151 | prev_bigrams_rating = bigrams_rating; 152 | step = 1; 153 | break; 154 | } 155 | 156 | std::swap(key[q], key[p]); 157 | } 158 | 159 | if (!find_good_key) 160 | { 161 | ++step; 162 | if (step >= alphabet_len_ - 1) 163 | break; 164 | } 165 | } 166 | 167 | text_modified_ = decr(key); 168 | Log::Logger()->log(Log::Debug, "Polibius::cracked"); 169 | } 170 | 171 | Polybius::Key::Key(std::size_t r, std::size_t c) 172 | { 173 | rows = r; 174 | cols = c; 175 | matrix = std::vector>(rows); 176 | for (auto i = 0; i < rows; ++i) 177 | matrix[i] = std::vector(cols); 178 | } 179 | 180 | bool Polybius::check_key(const std::string& key) const noexcept 181 | { 182 | Log::Logger()->log(Log::Debug, "Polibius::checking key"); 183 | if (key.length() != alphabet_len_ || !from_this_alphabet(key[0])) 184 | return false; 185 | 186 | for (auto i = 1; i < key.length(); ++i) 187 | { 188 | if (!from_this_alphabet(key[i])) return false; 189 | for (auto j = 0; j < i; ++j) 190 | if (key[i] == key[j]) return false; 191 | } 192 | 193 | return true; 194 | } 195 | 196 | Polybius::Key Polybius::parse_key(const std::string& key) const noexcept 197 | { 198 | Log::Logger()->log(Log::Debug, "Polibius::trying to parse key"); 199 | Key res(5, 5); 200 | 201 | for (auto i = 0; i < res.rows; i++) 202 | for (auto j = 0; j < res.cols; j++) 203 | res.matrix[i][j] = key[i * res.rows + j]; 204 | 205 | Log::Logger()->log(Log::Debug, "Polibius::completed parsing"); 206 | return res; 207 | } 208 | 209 | void Polybius::change_text_source() noexcept 210 | { 211 | Log::Logger()->log(Log::Debug, "Polibius::trying to change text to work better with"); 212 | std::string new_text_source; 213 | 214 | for (char c : text_source_) 215 | if (from_this_alphabet((char)tolower(c))) 216 | new_text_source += (char)tolower(c); 217 | else if (tolower(c) == 'j') new_text_source += 'i'; 218 | else 219 | { 220 | Log::Logger()->log(Log::Warn, "Polibius::letter is not from this alphabet"); 221 | Log::Logger()->log(Log::Info, "Polibius::letter is"); 222 | Log::Logger()->log(Log::Info, std::to_string(tolower(c))); 223 | } 224 | 225 | text_source_ = new_text_source; 226 | Log::Logger()->log(Log::Debug, "Polibius::completed changing text to work better with"); 227 | } 228 | 229 | bool Polybius::from_this_alphabet(char letter) const noexcept 230 | { 231 | for (std::size_t i = 0; i < alphabet_len_; ++i) 232 | if (letter == alphabet_[i]) 233 | return true; 234 | return false; 235 | } 236 | 237 | std::string Polybius::decr(const std::string& key) const noexcept 238 | { 239 | std::string res; 240 | Key k = parse_key(key); 241 | auto length = text_source_.length() / 2; 242 | for (auto i = 0; i < length; ++i) 243 | res += k.matrix[text_source_[2 * i] - alphabet_[0]][text_source_[2 * i + 1] - alphabet_[0]]; 244 | return res; 245 | } 246 | 247 | void Polybius::load_bigrams_freq() noexcept 248 | { 249 | Log::Logger()->log(Log::Debug, "Polibius::loading bigrams"); 250 | std::ifstream ifs("../sources/english_bigrams.txt"); 251 | std::string str; 252 | 253 | while(std::getline(ifs, str)) 254 | { 255 | double key = 0.0; 256 | std::istringstream sstream(str.substr(3, str.length() - 3)); 257 | sstream >> key; 258 | std::string bigram = str.substr(0, 2); 259 | if (bigram[0] != 'j' && bigram[1] != 'j') 260 | { 261 | bigrams_freq_table_.insert(std::pair(bigram, key)); 262 | current_bigrams_freq_table_.insert(std::pair(bigram, 0.0)); 263 | } 264 | } 265 | 266 | ifs.close(); 267 | Log::Logger()->log(Log::Debug, "Polibius::completed loading bigrams"); 268 | } 269 | 270 | double Polybius::count_bigrams_coefficient(const std::string& text) noexcept 271 | { 272 | Log::Logger()->log(Log::Debug, "Polibius::calculation of bigrams coefficient"); 273 | for (std::size_t i = 1; i < text.length(); ++i) 274 | { 275 | std::string temp = std::string(1, text[i - 1]) + std::string(1, text[i]); 276 | if (current_bigrams_freq_table_.find(temp) == current_bigrams_freq_table_.end()) 277 | current_bigrams_freq_table_.insert(std::pair(temp, 1.0)); 278 | else 279 | current_bigrams_freq_table_[temp] += 1.0; 280 | } 281 | 282 | double bigrams_rating = 0.0; 283 | 284 | for (auto& current_bigram_freq : current_bigrams_freq_table_) 285 | { 286 | current_bigram_freq.second = (current_bigram_freq.second / (text.length() - 1)) * 100.0; 287 | if (bigrams_freq_table_.find(current_bigram_freq.first) == bigrams_freq_table_.end()) 288 | bigrams_rating += pow(current_bigram_freq.second, 2.0); 289 | else 290 | bigrams_rating += pow(current_bigram_freq.second - bigrams_freq_table_.at(current_bigram_freq.first), 2.0); 291 | } 292 | 293 | Log::Logger()->log(Log::Debug, "Polibius::completed calculation of bigrams coefficient"); 294 | return bigrams_rating; 295 | } -------------------------------------------------------------------------------- /sources/english_bigrams.txt: -------------------------------------------------------------------------------- 1 | th 2.7056980400 2 | he 2.3285449734 3 | in 2.0275533912 4 | er 1.7838136077 5 | an 1.6136243080 6 | re 1.4089222457 7 | es 1.3198141739 8 | on 1.3162249877 9 | st 1.2492322192 10 | nt 1.1725158252 11 | en 1.1329747192 12 | at 1.1164000013 13 | ed 1.0787830752 14 | nd 1.0682918499 15 | to 1.0664621631 16 | or 1.0574430728 17 | ea 1.0020473710 18 | ti 0.9918454526 19 | ar 0.9794636727 20 | te 0.9781351042 21 | ng 0.8919108278 22 | al 0.8836830184 23 | it 0.8773684503 24 | as 0.8735606074 25 | is 0.8637575440 26 | ha 0.8318866089 27 | et 0.7602122952 28 | se 0.7292169123 29 | ou 0.7195042486 30 | of 0.7062904859 31 | le 0.7026448491 32 | sa 0.6956346263 33 | ve 0.6780783001 34 | ro 0.6759922610 35 | ra 0.6624590582 36 | ri 0.6390801475 37 | hi 0.6358586656 38 | ne 0.6320736943 39 | me 0.6299011868 40 | de 0.6250933272 41 | co 0.6183235460 42 | ta 0.6046905542 43 | ec 0.5960924043 44 | si 0.5957002559 45 | ll 0.5697536136 46 | so 0.5527965759 47 | na 0.5445612274 48 | li 0.5386327488 49 | la 0.5360229277 50 | el 0.5340324917 51 | ma 0.5048041703 52 | di 0.5012339707 53 | ic 0.4964795785 54 | rt 0.4961939024 55 | ns 0.4927333664 56 | rs 0.4911339225 57 | io 0.4905072297 58 | om 0.4871769859 59 | ch 0.4655909917 60 | ot 0.4645572110 61 | ca 0.4609196220 62 | ce 0.4579794916 63 | ho 0.4562544501 64 | be 0.4502292583 65 | tt 0.4478931341 66 | fo 0.4376321055 67 | ts 0.4376031979 68 | ss 0.4374453395 69 | no 0.4369461637 70 | ee 0.4277843395 71 | em 0.4196289840 72 | ac 0.4140646019 73 | il 0.4134382791 74 | da 0.4066497426 75 | ni 0.4035982371 76 | ur 0.4010454218 77 | wa 0.3894147991 78 | sh 0.3878961808 79 | ei 0.3706392445 80 | am 0.3694613422 81 | tr 0.3658824703 82 | dt 0.3644589925 83 | us 0.3630640291 84 | lo 0.3606810515 85 | pe 0.3601493374 86 | un 0.3523877954 87 | nc 0.3518541387 88 | wi 0.3518170214 89 | ut 0.3500629336 90 | ad 0.3440516637 91 | ew 0.3417199103 92 | ow 0.3378815178 93 | ge 0.3335938093 94 | ep 0.3243284497 95 | ai 0.3231846815 96 | ly 0.3177989019 97 | ol 0.3174395230 98 | ft 0.3167361905 99 | os 0.3144279100 100 | eo 0.3127610074 101 | ef 0.3064716699 102 | pr 0.3050599401 103 | we 0.3049196575 104 | do 0.3034212282 105 | mo 0.2995001138 106 | id 0.2982517465 107 | ie 0.2892038874 108 | mi 0.2814196126 109 | pa 0.2791015729 110 | fi 0.2773699868 111 | po 0.2756055154 112 | ct 0.2749398782 113 | wh 0.2741109712 114 | ir 0.2701435585 115 | ay 0.2664910995 116 | ga 0.2599319041 117 | sc 0.2497760528 118 | ke 0.2463079315 119 | ev 0.2445351116 120 | sp 0.2444568299 121 | im 0.2438508349 122 | op 0.2418858838 123 | ds 0.2412020927 124 | ld 0.2369397766 125 | ul 0.2352721340 126 | oo 0.2351654766 127 | su 0.2319775274 128 | ia 0.2313070339 129 | gh 0.2284946055 130 | pl 0.2269180333 131 | eb 0.2252199336 132 | ig 0.2204045349 133 | vi 0.2169232087 134 | iv 0.2111230796 135 | wo 0.2106007777 136 | yo 0.2101810399 137 | rd 0.2087273364 138 | tw 0.2060589833 139 | ba 0.2050693502 140 | ag 0.2037235297 141 | ry 0.2032441961 142 | ab 0.2029445518 143 | ls 0.2006289404 144 | sw 0.2005776468 145 | ap 0.1978181771 146 | fe 0.1972487675 147 | tu 0.1960509769 148 | ci 0.1953245645 149 | fa 0.1932858875 150 | ht 0.1931383896 151 | fr 0.1928568299 152 | av 0.1916891725 153 | eg 0.1916331612 154 | go 0.1893724741 155 | bo 0.1889952189 156 | bu 0.1876279143 157 | ty 0.1852146415 158 | mp 0.1811965828 159 | oc 0.1768437976 160 | od 0.1759941927 161 | eh 0.1748130759 162 | ys 0.1743616554 163 | ey 0.1741008167 164 | rm 0.1706237457 165 | ov 0.1699767944 166 | gt 0.1699299873 167 | ya 0.1674221521 168 | ck 0.1666252978 169 | gi 0.1642675738 170 | rn 0.1633771052 171 | gr 0.1616502368 172 | rc 0.1612825326 173 | bl 0.1605189335 174 | lt 0.1576565992 175 | yt 0.1552717946 176 | oa 0.1515732453 177 | ye 0.1503032552 178 | ob 0.1436708658 179 | db 0.1412242915 180 | ff 0.1407340193 181 | sf 0.1404675147 182 | rr 0.1363560960 183 | du 0.1355489737 184 | ki 0.1344631132 185 | uc 0.1327986851 186 | if 0.1327531036 187 | af 0.1318778520 188 | dr 0.1318619413 189 | cl 0.1314300623 190 | ex 0.1306474536 191 | sm 0.1290608215 192 | pi 0.1285625708 193 | sb 0.1284347762 194 | cr 0.1275250668 195 | tl 0.1249532187 196 | oi 0.1234148507 197 | ru 0.1232747300 198 | up 0.1227287471 199 | by 0.1209972072 200 | tc 0.1201818520 201 | nn 0.1198137315 202 | ak 0.1188057132 203 | sl 0.1148211179 204 | nf 0.1144816506 205 | ue 0.1139614070 206 | dw 0.1134752280 207 | au 0.1129515155 208 | pp 0.1127023323 209 | ug 0.1117525916 210 | rl 0.1110801092 211 | rg 0.1074421965 212 | br 0.1068673291 213 | cu 0.1064733768 214 | ua 0.1061485021 215 | dh 0.1060506326 216 | rk 0.1038683429 217 | yi 0.1031702599 218 | lu 0.1018226125 219 | um 0.1015168861 220 | bi 0.1007477599 221 | ny 0.1004431436 222 | nw 0.0974986654 223 | qu 0.0964223097 224 | og 0.0962766618 225 | sn 0.0961578864 226 | mb 0.0953201221 227 | va 0.0950798656 228 | df 0.0932876660 229 | dd 0.0925336874 230 | ms 0.0907201425 231 | gs 0.0906697278 232 | aw 0.0906300666 233 | nh 0.0905479691 234 | pu 0.0892237252 235 | hr 0.0888734349 236 | sd 0.0888560672 237 | tb 0.0882364972 238 | pt 0.0881674891 239 | nm 0.0878079484 240 | dc 0.0874738463 241 | gu 0.0871489022 242 | tm 0.0869507351 243 | mu 0.0868576065 244 | nu 0.0863203421 245 | mm 0.0862719161 246 | nl 0.0854041573 247 | eu 0.0849681156 248 | wn 0.0844011805 249 | nb 0.0833160369 250 | rp 0.0829806166 251 | dm 0.0819796518 252 | sr 0.0812605010 253 | ud 0.0809304229 254 | ui 0.0805129283 255 | rf 0.0794664745 256 | ok 0.0785723751 257 | yw 0.0781444045 258 | tf 0.0778989908 259 | ip 0.0774403781 260 | rw 0.0774261325 261 | rb 0.0773846674 262 | oh 0.0752674082 263 | ks 0.0746354657 264 | dp 0.0727324230 265 | fu 0.0725903597 266 | yc 0.0723395114 267 | tp 0.0710068496 268 | mt 0.0706719613 269 | dl 0.0705563079 270 | nk 0.0703771967 271 | cc 0.0699908066 272 | ub 0.0691669642 273 | rh 0.0686544447 274 | np 0.0686410315 275 | ju 0.0676394192 276 | fl 0.0668536885 277 | dn 0.0656900550 278 | ka 0.0655169796 279 | ph 0.0653390478 280 | hu 0.0641014804 281 | jo 0.0629339617 282 | lf 0.0624986600 283 | yb 0.0623660090 284 | rv 0.0622656188 285 | oe 0.0605048707 286 | ib 0.0600917470 287 | ik 0.0597837080 288 | yp 0.0597082939 289 | gl 0.0595909061 290 | lp 0.0588316779 291 | ym 0.0581914563 292 | lb 0.0569754886 293 | hs 0.0569369374 294 | dg 0.0564770297 295 | gn 0.0561137194 296 | ek 0.0557716851 297 | nr 0.0553540518 298 | ps 0.0549714544 299 | td 0.0542656473 300 | lc 0.0538389023 301 | sk 0.0536960990 302 | yf 0.0533111890 303 | yh 0.0529880949 304 | vo 0.0521097444 305 | ah 0.0514617062 306 | dy 0.0512945049 307 | lm 0.0512592145 308 | sy 0.0512073197 309 | nv 0.0507509039 310 | yd 0.0490812725 311 | fs 0.0473486457 312 | sg 0.0472643281 313 | yr 0.0467594633 314 | yl 0.0465744549 315 | ws 0.0459914009 316 | my 0.0450756555 317 | oy 0.0447001579 318 | kn 0.0440282073 319 | iz 0.0431486311 320 | xp 0.0425680285 321 | lw 0.0424781838 322 | tn 0.0412133739 323 | ko 0.0406556198 324 | aa 0.0398032398 325 | ja 0.0396094435 326 | ze 0.0395425630 327 | fc 0.0363261919 328 | gw 0.0362614389 329 | tg 0.0353838978 330 | xt 0.0349196192 331 | fh 0.0348649261 332 | lr 0.0348068335 333 | je 0.0343964848 334 | yn 0.0343573324 335 | gg 0.0339556561 336 | gf 0.0338863704 337 | eq 0.0337972426 338 | hy 0.0334506988 339 | kt 0.0333936699 340 | hc 0.0333259568 341 | bs 0.0326001458 342 | hw 0.0324510059 343 | hn 0.0320054825 344 | cs 0.0319511363 345 | hm 0.0312895694 346 | nj 0.0310521573 347 | hh 0.0307576008 348 | wt 0.0300937675 349 | gc 0.0300532507 350 | lh 0.0294636983 351 | ej 0.0290692835 352 | fm 0.0289379044 353 | dv 0.0286431166 354 | lv 0.0286366876 355 | wr 0.0283699980 356 | gp 0.0281028690 357 | fp 0.0277476760 358 | gb 0.0273899622 359 | gm 0.0272543048 360 | hl 0.0270451759 361 | lk 0.0269230241 362 | cy 0.0264866356 363 | mc 0.0254785942 364 | yg 0.0242611232 365 | xi 0.0236980964 366 | hb 0.0234499076 367 | fw 0.0232625635 368 | gy 0.0226589967 369 | hp 0.0226322861 370 | mw 0.0216834705 371 | pm 0.0215355563 372 | za 0.0214868528 373 | lg 0.0214256382 374 | iw 0.0213235829 375 | xa 0.0209093722 376 | fb 0.0205395173 377 | sv 0.0203990959 378 | gd 0.0203461142 379 | ix 0.0203361237 380 | aj 0.0201257229 381 | kl 0.0195717846 382 | hf 0.0192936939 383 | hd 0.0191658299 384 | ae 0.0188700015 385 | sq 0.0185088420 386 | dj 0.0184861784 387 | fy 0.0182686779 388 | az 0.0177691090 389 | ln 0.0173980978 390 | ao 0.0173345011 391 | fd 0.0172989101 392 | kw 0.0166422690 393 | mf 0.0165371380 394 | mh 0.0164394767 395 | sj 0.0162909612 396 | uf 0.0162319898 397 | tv 0.0161454521 398 | xc 0.0161418676 399 | yu 0.0160844456 400 | bb 0.0159375027 401 | ww 0.0156010649 402 | oj 0.0152882157 403 | ax 0.0152822954 404 | mr 0.0152775083 405 | wl 0.0152118997 406 | xe 0.0151232113 407 | kh 0.0150341298 408 | ox 0.0150337366 409 | uo 0.0150297589 410 | zi 0.0148939859 411 | fg 0.0147488237 412 | ih 0.0141226859 413 | tk 0.0141145917 414 | ii 0.0140403802 415 | iu 0.0133364001 416 | tj 0.0129384008 417 | mn 0.0129135172 418 | wy 0.0128036684 419 | ky 0.0127955512 420 | kf 0.0124265982 421 | fn 0.0123576826 422 | uy 0.0123021338 423 | pw 0.0122663115 424 | dk 0.0121583823 425 | rj 0.0119829249 426 | uk 0.0119069790 427 | kr 0.0117253701 428 | ku 0.0117160734 429 | wm 0.0116945431 430 | km 0.0112304032 431 | md 0.0111265441 432 | ml 0.0110664627 433 | ez 0.0107643902 434 | kb 0.0105884934 435 | wc 0.0103695823 436 | wd 0.0100053932 437 | hg 0.0099351131 438 | bt 0.0099043324 439 | zo 0.0098058154 440 | kc 0.0097133343 441 | pf 0.0096705743 442 | yv 0.0095160691 443 | pc 0.0092575430 444 | py 0.0091613155 445 | wb 0.0091306272 446 | yk 0.0090643248 447 | cp 0.0088554966 448 | yj 0.0087573496 449 | kp 0.0086873702 450 | pb 0.0085412830 451 | cd 0.0082891859 452 | ji 0.0082693437 453 | uw 0.0081572980 454 | uh 0.0078476171 455 | wf 0.0077752788 456 | yy 0.0077003504 457 | wp 0.0074407142 458 | bc 0.0074091240 459 | aq 0.0072862785 460 | cb 0.0068927887 461 | iq 0.0067443657 462 | cm 0.0066127091 463 | mg 0.0065940001 464 | dq 0.0065519339 465 | bj 0.0065356069 466 | tz 0.0064754560 467 | kd 0.0064286257 468 | pd 0.0063171582 469 | fj 0.0062409116 470 | cf 0.0061892249 471 | nz 0.0061621905 472 | cw 0.0059492459 473 | fv 0.0056585976 474 | vy 0.0053902661 475 | fk 0.0052936686 476 | oz 0.0052855976 477 | zz 0.0051172168 478 | ij 0.0050675652 479 | lj 0.0050498506 480 | nq 0.0050281121 481 | uv 0.0049039021 482 | xo 0.0048835974 483 | pg 0.0048826724 484 | hk 0.0048653741 485 | kg 0.0048394961 486 | vs 0.0047198650 487 | hv 0.0045682969 488 | bm 0.0044357384 489 | hj 0.0043917757 490 | cn 0.0043487613 491 | gv 0.0043194143 492 | cg 0.0041994595 493 | wu 0.0041831325 494 | gj 0.0040920852 495 | xh 0.0038527769 496 | gk 0.0037887408 497 | tq 0.0036796090 498 | cq 0.0036434167 499 | rq 0.0036292405 500 | bh 0.0035727204 501 | xs 0.0035694365 502 | uz 0.0035553065 503 | wk 0.0034449490 504 | xu 0.0034118556 505 | ux 0.0033489759 506 | bd 0.0032781639 507 | bw 0.0032420179 508 | wg 0.0032351032 509 | mv 0.0031524044 510 | mj 0.0031049729 511 | pn 0.0030444289 512 | xm 0.0029483864 513 | oq 0.0028370345 514 | bv 0.0027769993 515 | xw 0.0027594466 516 | kk 0.0027476292 517 | bp 0.0026632191 518 | zu 0.0026256855 519 | rz 0.0026232342 520 | xf 0.0026139606 521 | mk 0.0025679398 522 | zh 0.0024892649 523 | bn 0.0024542521 524 | zy 0.0024483781 525 | hq 0.0023413045 526 | wj 0.0022995388 527 | iy 0.0022747014 528 | dz 0.0022672317 529 | vr 0.0022297213 530 | zs 0.0021968129 531 | xy 0.0021814572 532 | cv 0.0021790290 533 | xb 0.0021747969 534 | xr 0.0020824083 535 | uj 0.0020389776 536 | yq 0.0020340055 537 | vd 0.0019798443 538 | pk 0.0019198553 539 | vu 0.0019155308 540 | jr 0.0018609764 541 | zl 0.0018509859 542 | sz 0.0018463839 543 | yz 0.0018103304 544 | lq 0.0017841285 545 | kj 0.0017764507 546 | bf 0.0017425942 547 | nx 0.0017308461 548 | qa 0.0017003891 549 | qi 0.0016971515 550 | kv 0.0016924569 551 | zw 0.0015925755 552 | wv 0.0014784484 553 | uu 0.0014579356 554 | vt 0.0014549061 555 | vp 0.0014471589 556 | xd 0.0013898988 557 | gq 0.0013817815 558 | xl 0.0013779657 559 | vc 0.0013649920 560 | cz 0.0013393221 561 | lz 0.0013254465 562 | zt 0.0013171442 563 | wz 0.0012218880 564 | sx 0.0011788504 565 | zb 0.0011713807 566 | vl 0.0011339165 567 | pv 0.0011124787 568 | fq 0.0010985799 569 | pj 0.0010879188 570 | zm 0.0010645846 571 | vw 0.0010547329 572 | cj 0.0009603324 573 | zc 0.0009490237 574 | bg 0.0009369751 575 | js 0.0009094551 576 | xg 0.0009085994 577 | rx 0.0008939144 578 | hz 0.0008571902 579 | xx 0.0008106143 580 | vm 0.0008099668 581 | xn 0.0008032602 582 | qw 0.0008017570 583 | jp 0.0007983113 584 | vn 0.0007650560 585 | zd 0.0007609858 586 | zr 0.0007558750 587 | fz 0.0007212090 588 | xv 0.0007196133 589 | zp 0.0007027775 590 | vh 0.0006984761 591 | vb 0.0006750957 592 | zf 0.0006627464 593 | gz 0.0006594162 594 | tx 0.0006511371 595 | vf 0.0006496108 596 | dx 0.0006339544 597 | qb 0.0006315031 598 | bk 0.0006242415 599 | zg 0.0006098108 600 | vg 0.0005916800 601 | jc 0.0005728323 602 | zk 0.0005610842 603 | zn 0.0005605986 604 | uq 0.0005408258 605 | jm 0.0005165897 606 | vv 0.0005163816 607 | jd 0.0005065299 608 | mq 0.0004939262 609 | jh 0.0004847220 610 | qs 0.0004821088 611 | jt 0.0004719564 612 | jb 0.0004481829 613 | fx 0.0004466334 614 | pq 0.0004303064 615 | mz 0.0004225361 616 | yx 0.0003918709 617 | qt 0.0003911540 618 | wq 0.0003756827 619 | jj 0.0003719825 620 | jw 0.0003719363 621 | lx 0.0003576906 622 | gx 0.0003417568 623 | jn 0.0003342177 624 | zv 0.0003316044 625 | mx 0.0003295462 626 | jk 0.0003230015 627 | kq 0.0003215677 628 | xk 0.0003156937 629 | jf 0.0002923133 630 | qm 0.0002847973 631 | qh 0.0002838260 632 | jl 0.0002809584 633 | jg 0.0002780445 634 | vk 0.0002652327 635 | vj 0.0002643770 636 | kz 0.0002588268 637 | qc 0.0002466856 638 | xj 0.0002458068 639 | pz 0.0002242533 640 | ql 0.0002220795 641 | qo 0.0002172461 642 | jv 0.0002064000 643 | qf 0.0002030005 644 | qd 0.0002006879 645 | bz 0.0001880610 646 | hx 0.0001740467 647 | zj 0.0001657444 648 | px 0.0001575809 649 | qp 0.0001401901 650 | qe 0.0001392188 651 | qr 0.0001381782 652 | zq 0.0001335067 653 | jy 0.0001323504 654 | bq 0.0001274939 655 | xq 0.0001252507 656 | cx 0.0001225681 657 | kx 0.0001175497 658 | wx 0.0001081837 659 | qy 0.0001053854 660 | qv 0.0000974069 661 | qn 0.0000880640 662 | vx 0.0000738184 663 | bx 0.0000698638 664 | jz 0.0000661174 665 | vz 0.0000608909 666 | qg 0.0000593646 667 | qq 0.0000577920 668 | zx 0.0000569595 669 | xz 0.0000481484 670 | qk 0.0000467840 671 | vq 0.0000344116 672 | qj 0.0000310352 673 | qx 0.0000176914 674 | jx 0.0000172752 675 | jq 0.0000166970 676 | qz 0.0000064753 677 | -------------------------------------------------------------------------------- /sources/Vigener.cpp: -------------------------------------------------------------------------------- 1 | #include"Vigener.hpp" 2 | #include"Caesar.hpp" 3 | 4 | Vigener::Vigener(char letter_first, std::size_t max_key_len, 5 | bool need_spaces, unsigned log_level, 6 | unsigned top_key_len, unsigned top_key) 7 | : 8 | Cipher(log_level), 9 | key_(""), 10 | letter_first_(letter_first), 11 | key_len_(0), 12 | match_index_(0.0), 13 | frequency_table_(nullptr), 14 | alphabet_(nullptr), 15 | max_key_len_(max_key_len), 16 | need_spaces_(need_spaces), 17 | top_key_len_(top_key_len), 18 | top_key_(top_key) { 19 | 20 | Log::Logger()->log(Log::Debug, "Vigener::creating Vigener"); 21 | Log::Logger()->log(Log::Info, " Vigener::first letter of alphabet: "); 22 | Log::Logger()->log(Log::Info, std::to_string(letter_first)); 23 | switch (letter_first_) { 24 | case'a': 25 | alphabet_len_ = ENGLISH_ALPHABET_LEN; 26 | frequency_table_ = ENGLISH_LETTER_FREQUENCIES; 27 | alphabet_ = ENGLISH_ALPHABET; 28 | match_index_ = ENGLISH_MATCH_INDEX; 29 | break; 30 | default: 31 | Log::Logger()->log(Log::Error, "Fatall. Vigener::has no this alphabet"); 32 | throw std::invalid_argument("Invalid alphabet"); 33 | break; 34 | } 35 | letters_count_ = new std::size_t[alphabet_len_]; 36 | Log::Logger()->log(Log::Debug, "Vigener::created"); 37 | 38 | } 39 | 40 | void Vigener::change_spaces_mode() { 41 | 42 | need_spaces_ = !need_spaces_; 43 | } 44 | 45 | void Vigener::encrypt(const std::string& key) { 46 | 47 | Log::Logger()->log(Log::Debug, "Vigener::want to encrypt"); 48 | if (!prepare_to_modify(key)) { 49 | throw std::invalid_argument("Invalid key"); 50 | } 51 | encr(); 52 | if (need_spaces_) { 53 | text_modified_ = spaces_reborn(text_modified_); 54 | } 55 | } 56 | 57 | void Vigener::decrypt(const std::string& key) { 58 | 59 | Log::Logger()->log(Log::Debug, "Vigener::want to decrypt"); 60 | if (!prepare_to_modify(key)) { 61 | Log::Logger()->log(Log::Error, "Vigener::bad key"); 62 | Log::Logger()->log(Log::Info, " Vigener::key is"); 63 | Log::Logger()->log(Log::Info, key); 64 | throw std::invalid_argument("Invalid key"); 65 | } 66 | decr(); 67 | if (need_spaces_) { 68 | text_modified_ = spaces_reborn(text_modified_); 69 | } 70 | } 71 | 72 | void Vigener::crack() { 73 | 74 | std::size_t min_text_len = 2; 75 | 76 | Log::Logger()->log(Log::Debug, "Vigener::trying to crack"); 77 | key_ = ""; 78 | key_len_ = 0; 79 | text_modified_ = ""; 80 | if (top_key_len_) { 81 | top_vector_.clear(); 82 | top_vector_.assign((top_key_len_ < max_key_len_) ? top_key_len_ : max_key_len_, decryptod_Vigener_mod(0, 0.0, top_key_)); 83 | } 84 | spaces_pos_.clear(); 85 | text_to_lower(); 86 | 87 | if (text_source_.length() < min_text_len) { 88 | Log::Logger()->log(Log::Error, "Vigener::text is too short to crack"); 89 | Log::Logger()->log(Log::Debug, "Vigener::refused to crack"); 90 | throw(std::logic_error("Text is too small to crack")); 91 | return; 92 | } 93 | 94 | 95 | key_len_ = find_key_len(); 96 | if (top_key_len_ && top_key_) { 97 | text_modified_ = find_top_text(); 98 | key_ = top_vector_[0].top_key_vector_[0].key_; 99 | } else { 100 | text_modified_ = find_text(); 101 | } 102 | if (need_spaces_) { 103 | text_modified_ = spaces_reborn(text_modified_); 104 | } 105 | Log::Logger()->log(Log::Debug, "Vigener::cracking is completed"); 106 | } 107 | 108 | std::string Vigener::get_key() const { 109 | 110 | return key_; 111 | } 112 | 113 | void Vigener::text_to_lower() { 114 | 115 | Log::Logger()->log(Log::Debug, "Vigener::doing text comfortable to work with"); 116 | std::string new_text_source = ""; 117 | std::size_t text_source_size = text_source_.length(); 118 | for (std::size_t i = 0; i < text_source_size; ++i) { 119 | if (from_this_alphabet(tolower(text_source_[i]))) { 120 | new_text_source += tolower(text_source_[i]); 121 | } else { 122 | if (need_spaces_) { 123 | spaces_pos_.insert(i); 124 | } 125 | Log::Logger()->log(Log::Warn, " Vigener::letter is not from selected alphabet"); 126 | Log::Logger()->log(Log::Info, " Vigener::letter is "); 127 | Log::Logger()->log(Log::Info, std::to_string(text_source_[i])); 128 | } 129 | } 130 | 131 | text_source_ = new_text_source; 132 | Log::Logger()->log(Log::Debug, "Vigener::done text comfortable"); 133 | 134 | } 135 | 136 | bool Vigener::prepare_to_modify(const std::string & key) { 137 | 138 | std::size_t min_text_len = 2; 139 | 140 | Log::Logger()->log(Log::Debug, "Vigener::preparing to modify"); 141 | key_ = ""; 142 | key_len_ = 0; 143 | spaces_pos_.clear(); 144 | 145 | std::size_t key_len = key.length(); 146 | if (key_len == 0) { 147 | return false; 148 | } 149 | 150 | std::string new_key = ""; 151 | for (std::size_t i = 0; i < key_len; ++i) { 152 | if (from_this_alphabet(tolower(key[i]))) { 153 | new_key += tolower(key[i]); 154 | } else { 155 | return false; 156 | } 157 | } 158 | 159 | text_to_lower(); 160 | 161 | if (text_source_.length() < min_text_len) { 162 | Log::Logger()->log(Log::Error, "Vigener::text is too short to crack"); 163 | throw(std::logic_error("Text is too small")); 164 | } 165 | 166 | key_len_ = key_len; 167 | key_ = new_key; 168 | text_modified_ = ""; 169 | Log::Logger()->log(Log::Debug, "Vigener::is ready to be modified"); 170 | 171 | return true; 172 | } 173 | 174 | bool Vigener::from_this_alphabet(char letter) const { 175 | 176 | for (std::size_t i = 0; i < alphabet_len_; ++i) { 177 | if (letter == alphabet_[i]) { 178 | return true; 179 | } 180 | } 181 | 182 | return false; 183 | } 184 | 185 | void Vigener::encr() { 186 | 187 | Log::Logger()->log(Log::Debug, "Vigener::tring to encrypt"); 188 | std::size_t text_source_size = text_source_.length(); 189 | for (std::size_t i = 0; i < text_source_size; ++i) { 190 | char letter_modified = (text_source_[i] - letter_first_ + (key_[i % key_len_] - letter_first_)) % (alphabet_len_)+letter_first_; 191 | text_modified_ += letter_modified; 192 | } 193 | Log::Logger()->log(Log::Debug, "Vigener::encrypting done"); 194 | } 195 | 196 | void Vigener::decr() { 197 | 198 | Log::Logger()->log(Log::Debug, "Vigener::tring to decrypt"); 199 | std::size_t text_source_size = text_source_.length(); 200 | for (std::size_t i = 0; i < text_source_size; ++i) { 201 | int pos = (text_source_[i] - letter_first_ - (key_[i % key_len_] - letter_first_)); 202 | while (pos < 0) { 203 | pos += alphabet_len_; 204 | } 205 | char letter_modified = pos % (alphabet_len_) + letter_first_; 206 | text_modified_ += letter_modified; 207 | } 208 | Log::Logger()->log(Log::Debug, "Vigener::decrypting done"); 209 | } 210 | 211 | std::size_t Vigener::find_key_len() { 212 | 213 | Log::Logger()->log(Log::Debug, "Vigener::trying to find key_len"); 214 | std::size_t text_len = text_source_.length(); 215 | std::size_t prob_key_len = 1; 216 | std::size_t cur_key_len = 1; 217 | double max_prob_match_index = 0; 218 | 219 | std::size_t * letters_count = new std::size_t[alphabet_len_]; 220 | while (cur_key_len <= max_key_len_) { 221 | double cur_match_index = 0; 222 | for (std::size_t i = 0; i < alphabet_len_; ++i) { 223 | letters_count[i] = 0; 224 | } 225 | 226 | std::size_t part_len = 0; 227 | for (std::size_t i = cur_key_len - 1; i < text_len; i += cur_key_len) { 228 | ++part_len; 229 | letters_count[text_source_[i] - letter_first_] += 1; 230 | } 231 | 232 | for (std::size_t i = 0; i < alphabet_len_; ++i) { 233 | if (letters_count[i] > 1) { 234 | cur_match_index += letters_count[i] * (letters_count[i] - 1) *1.0 / (part_len * (part_len - 1)); 235 | } 236 | } 237 | 238 | if (top_key_len_) { 239 | add_decryptod_Vigener_mod(decryptod_Vigener_mod(cur_key_len, cur_match_index, top_key_)); 240 | } 241 | double dif_cur = (match_index_ - cur_match_index); 242 | double dif_min = (match_index_ - max_prob_match_index); 243 | if (dif_cur * dif_cur < dif_min * dif_min) { 244 | max_prob_match_index = cur_match_index; 245 | prob_key_len = cur_key_len; 246 | } 247 | 248 | ++cur_key_len; 249 | } 250 | delete[] letters_count; 251 | Log::Logger()->log(Log::Debug, "Vigener::completed finding key_len"); 252 | return prob_key_len; 253 | } 254 | 255 | std::string Vigener::find_text() { 256 | 257 | Log::Logger()->log(Log::Debug, "Vigener::trying to find real text"); 258 | std::string * text_parts = new std::string[key_len_]; 259 | std::size_t text_len = text_source_.length(); 260 | for (std::size_t i = 0; i < key_len_; ++i) { 261 | text_parts[i] = ""; 262 | } 263 | for (std::size_t i = 0; i < text_len; ++i) { 264 | text_parts[i % key_len_] += text_source_[i]; 265 | } 266 | 267 | Caesar caesar_cracker(letter_first_, false, Log::Error, 0); 268 | 269 | for (std::size_t i = 0; i < key_len_; ++i) { 270 | caesar_cracker.set_text_source(text_parts[i]); 271 | caesar_cracker.crack(); 272 | char letter_source = text_parts[i][0]; 273 | text_parts[i] = caesar_cracker.get_text_modified(); 274 | key_ += find_key_letter(letter_source, text_parts[i][0]); 275 | } 276 | 277 | std::string text_modified = ""; 278 | std::size_t max_text_part_len = text_len / key_len_ + (((text_len % key_len_) != 0) ? 1 : 0); 279 | std::size_t count_letters = 0; 280 | for (std::size_t i = 0; i < max_text_part_len; ++i) { 281 | for (std::size_t j = 0; j < key_len_; ++j) { 282 | /* 283 | if (text_parts[j].length() < i) { 284 | break; 285 | } 286 | */ 287 | if (count_letters == text_len) { 288 | break; 289 | } 290 | ++count_letters; 291 | text_modified += text_parts[j][i]; 292 | } 293 | } 294 | 295 | delete[] text_parts; 296 | Log::Logger()->log(Log::Debug, "Vigener::completed finding real text"); 297 | return text_modified; 298 | } 299 | 300 | std::string Vigener::find_top_text() { 301 | 302 | //top_key for every top_key_len 303 | 304 | Log::Logger()->log(Log::Debug, "Vigener::trying to find top of real text"); 305 | Caesar caesar_cracker(letter_first_, false, Log::Error, top_key_); 306 | std::size_t text_len = text_source_.length(); 307 | std::size_t top_key_len = top_vector_.size(); // or (top_key_len_ < max_key_len_) ? top_key_len_ : max_key_len_ 308 | for (std::size_t i = 0; i < top_key_len; ++i) { 309 | std::size_t cur_key_len = top_vector_[i].key_len_; 310 | std::string * text_parts = new std::string[cur_key_len]; 311 | for (std::size_t j = 0; j < cur_key_len; ++j) { 312 | text_parts[j] = ""; 313 | } 314 | for (std::size_t j = 0; j < text_len; ++j) { 315 | text_parts[j % cur_key_len] += text_source_[j]; 316 | } 317 | 318 | std::vector>> decr_caesar_top_vector; // matrix top_key_len_ : top_key 319 | std::vector letters_source; 320 | for (std::size_t j = 0; j < cur_key_len; ++j) { 321 | caesar_cracker.set_text_source(text_parts[j]); 322 | caesar_cracker.crack(); 323 | decr_caesar_top_vector.push_back(caesar_cracker.get_top()); 324 | letters_source.push_back(text_parts[j][0]); 325 | } 326 | 327 | std::size_t top_key = top_vector_[i].top_key_vector_.size(); // or top_key_ < pow(alphabet_len_, cur_key_len) ? top_key_ : pow() 328 | std::vector indexes;//size==cur_key_len 329 | find_optimal_top(indexes, decr_caesar_top_vector, letters_source, text_len, text_parts, top_key, top_key_len, cur_key_len, top_vector_[i], 0); 330 | delete[] text_parts; 331 | } 332 | Log::Logger()->log(Log::Debug, "Vigener::completed finding top of real text"); 333 | 334 | return top_vector_[0].top_key_vector_[0].text_; 335 | } 336 | 337 | Vigener::~Vigener() { 338 | delete[] letters_count_; 339 | } 340 | 341 | std::string Vigener::spaces_reborn(std::string const & text_modified) { 342 | 343 | Log::Logger()->log(Log::Debug, "Vigener::trying to reborn spaces"); 344 | if (spaces_pos_.size() > 0) { 345 | std::size_t new_text_len = text_modified.length() + spaces_pos_.size(); 346 | std::size_t spaces_count = 0; 347 | std::string new_text_modified = ""; 348 | auto end = spaces_pos_.end(); 349 | for (std::size_t i = 0; i < new_text_len; ++i) { 350 | if (spaces_pos_.find(i) != end) { 351 | new_text_modified += " "; 352 | ++spaces_count; 353 | } else { 354 | new_text_modified += text_modified[i - spaces_count]; 355 | } 356 | } 357 | Log::Logger()->log(Log::Debug, "Vigener::complete spaces reborn"); 358 | return new_text_modified; 359 | } 360 | 361 | Log::Logger()->log(Log::Debug, "Vigener::complete spaces reborn, but don't find it"); 362 | return text_modified; 363 | } 364 | 365 | void Vigener::add_decryptod_Vigener_mod(decryptod_Vigener_mod decr) { 366 | 367 | std::size_t top_len = top_vector_.size(); 368 | bool find_place = false; 369 | for (std::size_t i = 0; i < top_len; ++i) { 370 | if (top_vector_[i].match_index_ < decr.match_index_) { 371 | find_place = true; 372 | } 373 | if (find_place) { 374 | decryptod_Vigener_mod old_decr = top_vector_[i]; 375 | top_vector_[i] = decr; 376 | decr = old_decr; 377 | } 378 | } 379 | } 380 | 381 | void Vigener::find_optimal_top(std::vector & indexes, std::vector>> & source_variant, 382 | std::vector & letters_source, std::size_t text_len, std::string *& text_parts, 383 | std::size_t top_key, std::size_t top_key_len, std::size_t cur_key_len, 384 | decryptod_Vigener_mod & cur_decr, std::size_t deep) { 385 | 386 | if (deep == cur_key_len) { 387 | 388 | std::string text_modified = ""; 389 | std::size_t max_text_part_len = text_len / cur_key_len + (((text_len % cur_key_len) != 0) ? 1 : 0); 390 | std::string key = ""; 391 | for (std::size_t i = 0; i < cur_key_len; ++i) { 392 | text_parts[i] = source_variant[i][indexes[i]].text_; 393 | key += find_key_letter(letters_source[i], text_parts[i][0]); // ? 394 | } 395 | std::size_t count_letters = 0; 396 | for (std::size_t i = 0; i < max_text_part_len; ++i) { 397 | for (std::size_t j = 0; j < cur_key_len; ++j) { 398 | /* 399 | if (text_parts[j].length() < i) { 400 | break; 401 | } 402 | */ 403 | if (count_letters == text_len) { 404 | break; 405 | } 406 | ++count_letters; 407 | text_modified += text_parts[j][i]; 408 | } 409 | } 410 | double factor = calc_factor(text_modified); // ? 411 | add_decryptod(cur_decr , decryptod( text_modified, key, factor )); // ? 412 | indexes.pop_back(); 413 | } else { 414 | for (std::size_t i = 0; i < top_key; ++i) { 415 | indexes.push_back(i); 416 | find_optimal_top(indexes, source_variant, letters_source, text_len, text_parts, top_key, top_key_len, cur_key_len, cur_decr, deep + 1); 417 | } 418 | } 419 | } 420 | 421 | char Vigener::find_key_letter(char letter_source, char letter_modified) { 422 | 423 | Log::Logger()->log(Log::Debug, "Vigener::trying to find key_letter"); 424 | 425 | int pos = letter_source - letter_modified; 426 | 427 | if (pos < 0) { 428 | pos += alphabet_len_; 429 | } 430 | Log::Logger()->log(Log::Debug, "Vigener::completed finding key_letter"); 431 | 432 | return letter_first_ + pos; 433 | 434 | } 435 | 436 | void Vigener::add_decryptod(decryptod_Vigener_mod & decr_V_m, decryptod decr_C) { 437 | 438 | std::size_t top_key = decr_V_m.top_key_vector_.size(); 439 | bool find_place = false; 440 | for (std::size_t i = 0; i < top_key; ++i) { 441 | if (decr_V_m.top_key_vector_[i].text_.compare(decr_C.text_) == 0) { 442 | break; 443 | } 444 | if (decr_V_m.top_key_vector_[i].factor_ < decr_C.factor_) { 445 | find_place = true; 446 | } 447 | if (find_place) { 448 | decryptod old_decr = decr_V_m.top_key_vector_[i]; 449 | decr_V_m.top_key_vector_[i] = decr_C; 450 | decr_C = old_decr; 451 | } 452 | } 453 | 454 | } 455 | 456 | double Vigener::calc_factor(std::string const & text) { 457 | 458 | 459 | for (std::size_t i = 0; i < alphabet_len_; ++i) { 460 | letters_count_[i] = 0; 461 | } 462 | std::size_t max_letters = text.length(); 463 | for (std::size_t i = 0; i < max_letters; ++i) { 464 | letters_count_[text[i] - letter_first_] += 1; 465 | } 466 | double cur_probability = 0; 467 | for (std::size_t i = 0; i < alphabet_len_; ++i) { 468 | cur_probability += ((letters_count_[i] * 1.0) / max_letters) * (frequency_table_[i] / 100); 469 | } 470 | return cur_probability; 471 | } 472 | 473 | // +output 474 | 475 | std::ostream & Vigener::top_out(std::ostream & out) { 476 | 477 | if (!key_len_) { 478 | return out; 479 | } 480 | std::size_t top_key_len = top_vector_.size(); 481 | for (std::size_t i = top_key_len; i > 0; --i) { 482 | std::size_t top_key = top_vector_[i - 1].top_key_vector_.size(); 483 | std::cout << "Key_len: " << top_vector_[i - 1].key_len_ << "\n"; 484 | std::cout << "Match_index: " << top_vector_[i - 1].match_index_ << "\n\n"; 485 | 486 | for (std::size_t j = top_key; j > 0; --j) { 487 | if (need_spaces_) { 488 | top_vector_[i - 1].top_key_vector_[j - 1].text_ = spaces_reborn(top_vector_[i - 1].top_key_vector_[j - 1].text_); 489 | } 490 | out << i << "." << j << ".\n"; 491 | out << "Text:\n" << top_vector_[i - 1].top_key_vector_[j - 1].text_ << "\n"; 492 | out << "Key: " << top_vector_[i - 1].top_key_vector_[j - 1].key_ << "\n"; 493 | out << "Factor: " << top_vector_[i - 1].top_key_vector_[j - 1].factor_ << "\n\n"; 494 | } 495 | } 496 | 497 | return out; 498 | } 499 | 500 | std::ofstream & Vigener::top_out(std::ofstream & out) { 501 | 502 | if (!key_len_) { 503 | return out; 504 | } 505 | std::size_t top_key_len = top_vector_.size(); 506 | for (std::size_t i = 0; i < top_key_len; ++i) { 507 | std::size_t top_key = top_vector_[i].top_key_vector_.size(); 508 | out << "Key_len: " << top_vector_[i].key_len_ << "\n"; 509 | out << "Match_index: " << top_vector_[i].match_index_ << "\n"; 510 | 511 | for (std::size_t j = 0; j < top_key; ++j) { 512 | if (need_spaces_) { 513 | top_vector_[i].top_key_vector_[j].text_ = spaces_reborn(top_vector_[i].top_key_vector_[j].text_); 514 | } 515 | out << i + 1 << "." << j + 1 << ".\n"; 516 | out << "Text:\n" << top_vector_[i].top_key_vector_[j].text_ << "\n"; 517 | out << "Key: " << top_vector_[i].top_key_vector_[j].key_ << "\n"; 518 | out << "Factor: " << top_vector_[i].top_key_vector_[j].factor_ << "\n\n"; 519 | } 520 | } 521 | 522 | return out; 523 | } --------------------------------------------------------------------------------