尝试算法:这个算法有相反的吗?

Experimenting with algorithms: Is there an inverse to this algorithm?

本文关键字:算法      更新时间:2023-10-16

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


我正在研究一种自定义算法,到目前为止,第一部分的结果似乎很好。但是,我用于反向的计算我不确定是否有。

伪代码如下:

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:字典文件

完整来源

#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 << "nn";
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 << "nn";
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;
}

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

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

根据我从代码中可以看出的猜测是,它不是可逆的,因为在大多数情况下映射不会是双射的。由于c的大小,除非在计算dist时发生神奇的事情,否则至少一些字母字符会被映射到非字母字符所采用的代码,从而产生碰撞。

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

还有一个重要的注意事项(你可能已经听说过,但仍然):
永远不要将自己开发的算法用于任何实际的事情,除非你是布鲁斯施奈尔。