实验算法:该算法是否有反函数?

时间:2019-06-10 19:09:10

标签: c++ algorithm encryption c++17

编辑--我重命名了该标题,并更改了问题的措辞,因为有人指出,这似乎更像是一种哈希算法,而不是加密-解密算法。但是,我将保留函数的名称。我还将在末尾附加我的完整代码以及指向您可以找到我正在使用的字典文件的链接,因为有些人不确定我在哪里或如何生成要在算法中使用的数字。 -


到目前为止,我正在研究一种自定义算法,结果对于第一部分来说似乎不错。但是,我用于逆的计算我不确定是否有一个。

伪代码如下:

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';

该文本似乎被打乱了。有办法扭转这种情况吗?


编辑--完整的源代码并链接到字典文件-

Github:Dictionary File

完整源

#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 个答案:

答案 0 :(得分:2)

如果不查看dist的生成方式,就无法确定所执行的操作是否可恢复。但是,有一种相当简单的方法可以找出答案。您的算法所做的实际上是将任何字母字符映射到特定的固定值,该值可以轻松地预先计算:

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

基于我从代码中可以看出的猜测,它是不可逆的,仅仅是因为在大多数情况下映射不会是双射的。由于c的大小,除非在dist的计算中发生不可思议的事情,否则至少某些字母字符将映射到非字母字符所采用的代码,从而产生冲突。

如果要将加密限制为字母字符,则应确保只有那些字符才是有效的输出代码。最后但并非最不重要的一点是,大多数逻辑运算符以及模运算符都会缩减您的数据,这很可能不利于使整个事情变得可逆。

还有一个重要的提示(您可能已经听说过,但是仍然):
除非您是Bruce Schneier,否则切勿将自行开发的算法用于任何实际用途。