Загрузка...

Rate software 2.0

Thread in C/C++ created by Whales_Nik Jul 7, 2022. 383 views

  1. Whales_Nik
    Whales_Nik Topic starter Jul 7, 2022 50 Mar 27, 2022
    Всем привет! Решил я сделать вторую версию своего "шифровальщика", если его можно так назвать.
    В данной версии поддерживаются только два метода шифрования: Цезаря (Просьба не писать про уязвимости этого шифра: частотный анализ, **** и т.д.), и шифр Вернама(Вижинера), хотел добавить RSA, но позже понял, что это не мой уровень.
    - Шифр Цезаря - это сдвиговый шифр, итоговый шифр складывается из того, что каждая буква сдвигается на несколько позиций (в зависимости от ключа), при этом ключ может находится в диапазоне от 1 до n - 1, где n - это мощность алфавита (в русском языке мощность алфавита 33). Этот шифр старый, из-за этого уязвимый, но в свои времена он был надежным.
    - Шифр Вернама - это современный шифр (был придуман в 1917 г.), суть в том, что есть ключ(гамма), он должен быть одноразовым и равным в длине тексту, есть текст. Алгоритм такой: посимвольно сложить текст и ключ по модулю мощности алфавита.

    Учел замечания из предыдущей темы и постарался разбить код на функции, при этом минимизировать повторения.
    Условно разбил функции на 5 частей:
    - Генерирующие ключи
    - Сами шифры
    - Меню (выбор шифра и режима)
    - Основная функция (main)
    - Остальные функции (проверка дебагера, получение имени файла).

    Прилагаю код:
    CPP
    #include <Windows.h> // В нём содержатся функции для работы с WinAPI
    #include <fstream> // Библиотека работы с файлами
    #include <iostream> // Библиотека потокового ввода-вывода
    #include <iomanip> // Функции работы с вводом-выводом
    #include <conio.h> // Из этой билиотеки нам нужна только функция _getch()
    #include <string> // Функции работы со строками
    #include <ctime> // Нужна нам, чтобы получить случайный seed

    using namespace std;

    enum status {
    ENCRYPT,
    DECRYPT
    };

    // ----------- KEY-GENERATING FUNCTIONS -----------

    int generateCaesarRandomKey() {
    srand(time(NULL));
    return rand() % 25 + 1;
    }

    string generateVigVerRandomKey(string text) {
    srand(time(NULL));
    string upperAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    string lowerAlphabet = "abcdefghijklmnopqrstuvwxyz";
    string resultKey = "";
    for (auto& i : text) {
    if (i >= 'a' && i <= 'z') {
    resultKey += lowerAlphabet[rand() % 26];
    }
    else if (i >= 'A' && i <= 'Z') {
    resultKey += upperAlphabet[rand() % 26];
    }
    }
    return resultKey;
    }

    // ----------- CIPHER FUNCTIONS -----------

    string caesarCipher(string text, int key = 0, bool stat = 0) {
    if (stat == ENCRYPT) {
    if (key == 0) {
    key = generateCaesarRandomKey();
    }
    for (auto &i : text) {
    if (i >= 'a' && i <= 'z') {
    i += key;
    if (i > 'z') {
    i = i - 'z' + 'a' - 1;
    }
    }
    else if (i >= 'A' && i <= 'Z') {
    i += key;
    if (i > 'Z') {
    i = i - 'Z' + 'A' - 1;
    }
    }
    }
    }

    else if (stat == DECRYPT) {
    for (auto& i : text) {
    if (i >= 'a' && i <= 'z') {
    i -= key;
    if (i < 'a') {
    i = i + 'z' - 'a' + 1;
    }
    }
    else if (i >= 'A' && i <= 'Z') {
    i -= key;
    if (i < 'A') {
    i = i + 'Z' - 'A' + 1;
    }
    }
    }
    }

    return text;
    }

    string vernamViginereCipher(string text, bool stat = 0, string keyword = "0") {
    int keyInd = 0;
    if (stat == ENCRYPT) {
    if (keyword == "0") {
    keyword = generateVigVerRandomKey(text);
    }
    for (auto& i : text) {
    if (i >= 'a' && i <= 'z') {
    i = 97 + ((i - 97) + (keyword[keyInd % keyword.size()] - 97)) % 26;
    keyInd++;
    }
    else if (i >= 'A' && i <= 'Z') {
    i = 65 + ((i - 65) + (keyword[keyInd % keyword.size()] - 65)) % 26;
    keyInd++;
    }
    }
    }
    else if (stat == DECRYPT) {
    if (keyword != "") {
    for (auto& i : text) {
    if (i >= 'a' && i <= 'z') {
    // Большие выражения с тернарным оператором из-за того,
    // что остаток от деления в C++ может быть отрицательным
    // Извиняюсь за такой ужасный фрагмент кода, вот формула которую можно запихнуть в функцию:
    // (a >= 0 ? a % b : (b - abs(a % b)) % b), где а - это ((i - 97) - (keyword[keyInd % keyword.size()] - 97)), b - 26 (мощность алфавита)
    i = 97 + (((i - 97) - (keyword[keyInd % keyword.size()] - 97)) >= 0 ? ((i - 97) - (keyword[keyInd % keyword.size()] - 97)) : 26 - abs(((i - 97) - (keyword[keyInd % keyword.size()] - 97)) % 26)) % 26;
    keyInd++;
    }
    else if (i >= 'A' && i <= 'Z') {
    i = 65 + ((i - 65) - (keyword[keyInd % keyword.size()] - 65)) % 26;
    keyInd++;
    }
    }
    }
    }
    if (stat == ENCRYPT) {
    string inserting = keyword + "\n";
    text.insert(0, inserting);
    }
    return text;
    }

    // ----------- MENU -----------

    int menu() {
    int chosen = 0;
    char key = '\0';
    while (key != 13) {
    cout << "\t\tCIPHER: " << endl;
    cout << setw(30) << "\tCAESAR CIPHER " << right << setw(21) << (chosen == 0 ? "<--" : "") << endl;
    cout << setw(40) << "\tVERNAM (VIGINERE) CIPHER " << right << setw(10) << (chosen == 1 ? "<--" : "") << endl;
    key = _getch();
    if (key != 13) {
    key = _getch();
    if(key == 72 || key == 80) {
    if (chosen == 0) chosen = 1;
    else chosen = 0;
    }
    }
    system("cls");
    }
    return chosen;
    }



    bool chooseStat() {
    bool chosen = 0;
    char key = '\0';
    while (key != 13) {
    cout << "\t\tCHOOSE ACTION: " << endl;
    cout << setw(20) << "\tENCRYPT " << right << setw(10) << (chosen == 0 ? "<--" : "") << endl;
    cout << setw(20) << "\tDECRYPT " << right << setw(10) << (chosen == 1 ? "<--" : "") << endl;
    key = _getch();
    if (key != 13) {
    key = _getch();
    if (key == 72 || key == 80) {
    chosen = !chosen;
    }
    }
    system("cls");
    }
    return chosen;
    }

    // ----------- OTHER FUNCTIONS -----------

    void debCheck() {
    if (IsDebuggerPresent()) exit(0);
    }

    string getFileName(bool stat) {
    string res = "";
    time_t now = time(0);
    tm* loc = localtime(&now);
    res = (stat == ENCRYPT ? "ENC-" : "DEC-") + to_string(loc->tm_mday) + "-" + to_string(loc->tm_mon) + "-" + to_string(loc->tm_year) + "-" + to_string(loc->tm_hour) + "-" + to_string(loc->tm_min) + (stat == ENCRYPT ? ".mp3" : ".txt");
    return res;
    }

    // ----------- MAIN -----------

    int main() {
    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)debCheck, NULL, NULL, NULL);
    ifstream in;
    ofstream out;
    while (true) {
    cin.ignore(32767, '\n');
    system("cls");
    char path[MAX_PATH];
    string keyword = "-1";
    int key = -1;
    bool stat = chooseStat();
    int method = menu();
    system("cls");
    cout << "\tENTER FILE PATH: ";
    cin.getline(path, MAX_PATH);
    system("cls");
    switch (method) {
    case 0:
    cout << setw(30) << "CAESAR CIPPHER" << endl;
    cout << setw(10) << "ENTER THE KEY OR 0 TO " << (stat == ENCRYPT ? "GENERATE IT" : "READ IT FROM THE FIRST LINE") << ": " << endl;
    cin >> key;
    break;
    case 1:
    cout << setw(30) << "VERNAM (VIGINERE) CIPPHER" << endl;
    cout << setw(10) << "ENTER THE KEYWORD OR \"0\" TO " << (stat == ENCRYPT ? "GENERATE IT" : "READ IT FROM THE FIRST LINE") << ": " << endl;
    cin >> keyword;
    break;
    }
    if (stat == DECRYPT) {
    char tmp[1024];
    in.open(path);
    in.getline(tmp, 1024);
    if (key == 0) {
    cout << "SET KEY WITH: " << (key = atoi(tmp)) << endl;
    }
    else if (keyword == "0") {
    cout << "SET KEYWORD WITH: " << (keyword = tmp) << endl;
    }
    in.close();
    }
    else if (stat == ENCRYPT) {
    if (key == 0) {
    cout << "SET KEY WITH: " << (key = generateCaesarRandomKey()) << endl;
    }
    }
    in.open(path);
    string newFile = getFileName(stat);
    out.open(newFile);
    if (out.is_open()) {
    cout << "CREATED NEW FILE: " << newFile << endl;
    }
    else {
    cout << "ERROR CREATING FILE!" << endl;
    continue;
    }
    if (stat == ENCRYPT) {
    if (method == 0) {
    out << key << endl;
    }
    }
    char line[2048];
    bool keyS = 1;
    long long linecnt = 0;
    while (in.getline(line, 2048)) {
    switch (method) {
    case 0:
    if(stat == DECRYPT && linecnt != 0 || stat == ENCRYPT) out << caesarCipher(line, key, stat) << endl;
    break;
    case 1:
    if (stat == DECRYPT) {
    if (keyS == 1) {
    keyword = line;
    }
    else {
    out << vernamViginereCipher(line, stat, keyword) << endl;
    }
    keyS = !keyS;
    }
    else {
    out << vernamViginereCipher(line, stat, keyword) << endl;
    }
    break;
    }
    linecnt++;
    }
    in.close();
    out.close();
    cout << "\tDONE!" << endl;
    cout << "PRESS \"X\" TO EXIT: ";
    char com = _getch();
    if (com == 'x') break;
    }
    cout << "\tBYE!" << endl;
    return 0;
    }
    Если кто-то будет компилировать, необходимо добавить
    _CRT_SECURE_NO_WARNINGS

    Интересно ваше мнение.
     
  2. 4lex7o8
    4lex7o8 Jul 7, 2022 282 May 22, 2019
     
    1. Whales_Nik Topic starter
  3. vtlstolyarov
    vtlstolyarov Jul 8, 2022 468 Jan 8, 2022
    Абстракции у тебя пока плохо получаются. И надо отходить от процедурного программирования в ООП.

    Вот некое подобие того что что я имел в виду под словом "стратегия" - прямо перед методом main в моём коде есть переменная
    EncryptionAlgorithms
    которая представляет собой массив алгоритмов шифрования. Сейчас в ней только одна реализация - шифр цезаря (абстракцию набросал я, а реализацию более или менее взял из твоего кода) - как первый шаг напиши класс
    VernamViginereCipherEncryptionAlgorithm
    и добавь его в этот массив. Прочувствуй насколько изолированно находится реализация алгоритма от кода в котором он используется. Реализуй остальную часть твое программы (меню выбора алгоритма и шифрование файлов) так что бы твой код опирался только на массив
    EncryptionAlgorithms
    (без знания того какие именно алгоритмы в этом массиве находятся).

    C
    #include <iostream>
    #include <string>

    using namespace std;

    class IEncryptionAlgorithm
    {
    public:
    virtual string GetAlgorithmName() = 0;
    virtual bool ReadSecret(istream &in, ostream &out) = 0;
    virtual string *Encrypt(string *text) = 0;
    virtual string *Decrypt(string *text) = 0;
    };

    class CaesarCipherEncryptionAlgorithm : public IEncryptionAlgorithm
    {
    private:
    const int UNDEFINED_KEY = 0;
    int key = UNDEFINED_KEY;

    void ValidateKey()
    {
    if (key == UNDEFINED_KEY)
    {
    throw std::runtime_error("The secred key is not configured. Invoke the `ReadSecret` method first.");
    }
    }

    public:
    virtual string GetAlgorithmName()
    {
    return "Caesar Сipher";
    }

    virtual bool ReadSecret(istream &in, ostream &out)
    {
    out << "ENTER THE KEY OR 0 TO GENERATE IT: ";
    string input;
    in >> input;
    if (input == "0")
    {
    srand(time(NULL));
    key = rand() % 25 + 1;
    }
    else
    {
    try
    {
    key = stoi(input);
    ValidateKey();
    }
    catch (...)
    {
    out << "KEY MUST BE A NON-ZERO INTEGER" << endl;
    return false;
    }
    }

    out << "SET KEY WITH: " << key << endl;
    return true;
    }

    virtual string *Encrypt(string *text)
    {
    ValidateKey();
    string* encrypted_text = new std::string(*text);
    for (auto &i : *encrypted_text) {
    if (i >= 'a' && i <= 'z') {
    i += key;
    if (i > 'z') {
    i = i - 'z' + 'a' - 1;
    }
    }
    else if (i >= 'A' && i <= 'Z') {
    i += key;
    if (i > 'Z') {
    i = i - 'Z' + 'A' - 1;
    }
    }
    }

    return encrypted_text;
    }

    virtual string *Decrypt(string *text)
    {
    ValidateKey();
    string *decrypted_text = new std::string(*text);
    for (auto &i : *decrypted_text) {
    if (i >= 'a' && i <= 'z') {
    i -= key;
    if (i < 'a') {
    i = i + 'z' - 'a' + 1;
    }
    }
    else if (i >= 'A' && i <= 'Z') {
    i -= key;
    if (i < 'A') {
    i = i + 'Z' - 'A' + 1;
    }
    }
    }

    return decrypted_text;
    }
    };

    IEncryptionAlgorithm* EncryptionAlgorithms[1] =
    {
    new CaesarCipherEncryptionAlgorithm(),
    };

    int main()
    {
    for (IEncryptionAlgorithm* encryptionAlgorithm : EncryptionAlgorithms)
    {
    cout << "Configuring `" << encryptionAlgorithm->GetAlgorithmName() << "` encryption algorithm:" << endl;
    bool secretConfigured;
    do
    {
    secretConfigured = encryptionAlgorithm->ReadSecret(cin, cout);
    }
    while (!secretConfigured);
    }

    cout << endl << "Type the text to encrypt: ";
    string unencryptedText;
    cin >> unencryptedText;

    for (IEncryptionAlgorithm* encryptionAlgorithm : EncryptionAlgorithms)
    {
    cout << endl << encryptionAlgorithm->GetAlgorithmName() << ":" << endl;

    string* encryptedText = encryptionAlgorithm->Encrypt(&unencryptedText);
    cout << "\x1B[31mEncrypted text:\033[0m " << *encryptedText << endl;

    string* decryptedText = encryptionAlgorithm->Decrypt(encryptedText);
    cout << "\x1B[32mDecrypted text:\033[0m " << *decryptedText << endl;

    delete encryptedText;
    delete decryptedText;
    }

    return 0;
    }
     
  4. renameduser_907389
    renameduser_907389 Jul 8, 2022 (tm) 168 Feb 7, 2019
    пиши на расте
     
Top
Loading...