Экспериментируя с алгоритмами: есть ли обратный алгоритм? - PullRequest
0 голосов
/ 10 июня 2019

РЕДАКТИРОВАТЬ - - Я переименовал этот заголовок и изменил формулировку вопроса, поскольку некоторые отметили, что это скорее алгоритм хеширования, чем алгоритм шифрования-дешифрования.Тем не менее, я заквашу название функций такими, какие они есть.Я также добавлю свой полный код в конце вместе со ссылкой, где вы можете найти файл словаря, который я использую, поскольку некоторые не были уверены, где или как я генерировал числа, которые будут использоваться в алгоритме (ах).-


Я работаю над нестандартным алгоритмом, и пока результаты кажутся хорошими для первой части.Однако расчет, который я использую для обратного, я не уверен, есть ли один или нет.

Псевдокод выглядит следующим образом:

for each character in string:
    new character in return string = (a|b) & c + 'a';
    where:
        a is a large value based on the occurrence of that character 
          based on an alpha text dictionary file
        b is a small value based on the occurrence of that character 
          found in the analyzed string to be encrypted.
        c is the current string converted to lowercase.

Моя функция шифрования:

std::string encrypt(const std::string& sentence, std::map<char, std::pair<unsigned, unsigned>>& dist) {
    std::string encrypted = "";

    // take each character from our original sentence
    // find it in the map and perform the calculation.
    // if the character is non alphabetical just add it. 
    for (auto& s : sentence)        
        if (std::isalpha(s)) {
            char c = std::tolower(s);
            char a = dist[std::remove_const_t<char>(c)].first;  // large value
            char b = dist[std::remove_const_t<char>(c)].second; // small value
            char res = (a | b) % c + 'a';
            encrypted.push_back(res);
        }
        else
            encrypted.push_back(s);

    return encrypted;
}

Функция дешифрования:

std::string decrypt(const std::string& encrypted, std::map<char, std::pair<unsigned, unsigned>>& dist) {
    std::string decrpyted = "";

    for (auto& s : encrypted) {    
        // ? Is there an inverse to the above?
        // Also how would I handle the non alpha characters that
        // were unchanged?  
    }    
    return decrpyted;
}

Я изменилрезультат функции к этому:

char res = (a % b) % c + 'a';

Текст кажется зашифрованным.Есть ли способ отменить это?


EDIT - -Полный исходный код и ссылка на файл словаря-

Github: Файл словаря

Полный источник

#include <cctype>
#include <climits>
#include <iostream>
#include <iterator>
#include <fstream>
#include <map>
#include <sstream>

void generateCryptoBaseMapFromFile(std::string filename, std::map<char, unsigned>& weights);
void printWeights(std::string filename, std::map<char, unsigned> weights);
void analyzeTextAndGenerateDistributionMap(std::string contents, std::map<char,unsigned>& weights, std::map<char, std::pair<unsigned, unsigned>>& dist);       
void printDistributionMap(std::string filename, std::map<char, std::pair<unsigned, unsigned>>& dist);
std::string encrypt(const std::string& sentence, std::map<char, std::pair<unsigned, unsigned>>& dist);
std::string decrypt(const std::string& encrypted, std::map<char, std::pair<unsigned, unsigned>>& dist);

int main() {        
    std::string filenameIn( "words_alpha.txt" );
    std::map<char, unsigned> weights;
    generateCryptoBaseMapFromFile(filenameIn, weights);    

    std::string filenameOut("character_distribution.txt");
    printWeights(filenameOut, weights);
    std::cout << '\n';

    std::string sentence("I enjoyed myself when I went to the shore. I had a blast swimming in the cool ocean on a hot summer day with a mild breeze.");
    std::map<char, std::pair<unsigned, unsigned>> distMap;
    analyzeTextAndGenerateDistributionMap(sentence, weights, distMap);
    printDistributionMap(filenameOut, distMap);
    std::cout << '\n';

    std::string encrypted = encrypt(sentence, distMap);
    std::cout << encrypted << '\n';

    // std::string decrypted = decrypt(encrypted, dist);
    // std::cout << decrypted << '\n'; // should match original sentence.

    return EXIT_SUCCESS;
}

void generateCryptoBaseMapFromFile(std::string filename, std::map<char, unsigned>& weights) {
    unsigned int count[1U << CHAR_BIT]{};
    std::ifstream in;

    in.open(filename);
    if (!in.is_open()) {
        std::cout << "Could not open " << filename << " for reading.";
        return;
    }

    for (std::istream_iterator<char> it(in), it_eof; it != it_eof; ++it)
        ++count[std::tolower(static_cast<unsigned char>(*it))];

    for (unsigned i = 0; i < (1U << CHAR_BIT); ++i)
        if (std::isalpha(i) && count[i])
            weights[static_cast<char>(i)] = count[i];

    in.close();
}

void printWeights(std::string filename, std::map<char, unsigned> weights) {
    std::ostringstream ostream;
    for (auto& u : weights)
        ostream << u.first << ' ' << u.second << '\n';

    // print to file & cout
    std::ofstream out;

    out.open(filename, std::ios::trunc);
    out << ostream.str();
    std::cout << ostream.str();
}

void analyzeTextAndGenerateDistributionMap(std::string contents, std::map<char,unsigned>& weights, std::map<char, std::pair<unsigned, unsigned>>& dist) {
    std::cout << "\nAnalyzing the following sentence:\n" << contents << '\n';

    unsigned int count[1U << CHAR_BIT]{};
    std::istringstream istream( contents );

    for (std::istream_iterator<char> it(istream), it_eof; it != it_eof; ++it) 
        ++count[std::tolower(static_cast<unsigned char>(*it))];

    for (unsigned i = 0; i < (1U << CHAR_BIT); ++i) {
        if (std::isalpha(i) && count[i]) {
            unsigned weight = weights.at(static_cast<unsigned char>(i));
            dist[static_cast<unsigned char>(i)] = std::make_pair(weight, count[i]);
        }
    }
}

void printDistributionMap(std::string filename, std::map<char, std::pair<unsigned, unsigned>>& dist) {
    std::ofstream out;
    out.open(filename, std::ios::app);
    std::ostringstream os;
    os << "\n\n";
    out << os.str();
    std::cout << os.str();
    os.str(std::string());
    os.clear();

    for (auto& m : dist) {
        os << m.first << " (" << m.second.first << "," << m.second.second << ")\n";
    }
    out << os.str();
    std::cout << os.str();
}

std::string encrypt(const std::string& sentence, std::map<char, std::pair<unsigned, unsigned>>& dist) {
    std::string encrypted = "";

    // take each character from original string find it in the map 
    // and perform the calculations. If the character is non 
    // alpahbetical we just add it to the string. 
    for (auto& s : sentence)        
        if (std::isalpha(s)) {
            char c = std::tolower(s);
            char a = dist[c].first;
            char b = dist[c].second;
            // the following formula must have an inverse!
            unsigned char res = (a % (b * c)) /*+ 'a'*/;
            std::cout << +res << ' ';
            encrypted.push_back(res);
        }
        else
            encrypted.push_back(s);

    std::cout << "\n\n";
    return encrypted;
}

std::string decrypt(const std::string& encrypted, std::map<char, std::pair<unsigned, unsigned>>& dist) {
    std::string decrpyted = "";

    for (auto& s : encrypted) {
        // ???    
    }

    return decrpyted;
}

1 Ответ

2 голосов
/ 10 июня 2019

Невозможно определить, являются ли выполненные операции обратимыми, не видя, как генерируется dist. Однако есть довольно простой способ выяснить это. То, что делает ваш алгоритм, по существу отображает любой алфавитный символ на определенное фиксированное значение, которое может быть легко вычислено заранее:

for(char c = 'a'; c <= 'z'; c++)
    std::cout << c << ': ' << (int) ((dist[c].first | dist[c].second) % c + 'a') << '\n';

Предположение, основанное на том, что я могу сказать из кода, состоит в том, что он не является обратимым просто потому, что отображение в большинстве случаев не будет биективным. Из-за размера c, если в вычислении dist не произойдет что-то волшебное, по крайней мере некоторые алфавитные символы будут сопоставлены с кодами, взятыми не алфавитными символами, что приведет к коллизии.

Если вы хотите ограничить шифрование буквенными символами, вам следует убедиться, что только те коды вывода являются действительными. И последнее, но не менее важное: большинство логических операторов, а также оператор по модулю обрезают ваши данные, что, скорее всего, не поможет сделать все это обратимым.

И важное примечание (вы, наверное, уже слышали это, но все же):
Никогда не используйте собственный алгоритм для чего-либо практичного, если только вы не Брюс Шнайер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...