我已经在Project Euler处理问题集已有一段时间了,并且很享受所提出的挑战。我目前在Problem 59,涉及加密和解密过程。
问题是,通过任何合理的标准,一个非常简单的解密问题。
我完全理解导入数据,循环遍历所有可能的密钥以及尝试使用每个可能的密钥解密文件数据的过程。我的麻烦是,在使用其中一个密钥进行解密尝试后,如何判断该密钥是否是正确的解密密钥?就计算机而言,每个解密密钥只是将数据从一个值转换为另一个值。该值的含义纯粹是主观的/解释的。如何判断解密密钥是否已将数据解密为有意义的内容(即常用英语单词)
这是我到目前为止的代码(C#):
static void Main(string[] args)
{
/* Get the data from the file and convert to byte array*/
StreamReader inData = new StreamReader(@"C:\Users\thantos\Desktop\cipher1.txt");
string[] strData = inData.ReadLine().Split(new char[] {','});
byte[] fileData = new byte[strData.Length];
foreach (string x in strData) { byte.Parse(x); }
/* for each three character lowercase password */
for (uint i = 0; i < 26; i++) {
for (uint j = 0; j < 26; j++){
for (uint k = 0; k < 26; k++) {
/* create a key */
byte[] key = new byte[3];
key[0] = (byte)(i + 97);
key[1] = (byte)(j + 97);
key[2] = (byte)(k + 97);
/* create temp copy of data */
byte[] dataCopy = new byte[fileData.Length];
fileData.CopyTo(dataCopy, 0);
/* decrypt using key */
for (uint l = 0; l < dataCopy.Length; l++) {
dataCopy[l] = (byte)(dataCopy[l] ^ key[l%key.Length]);
}
/* cannot figure out how to check
* if data is meaningfully decrypted
*/
bool dataIsMeaningful = isMeaningful(dataCopy);
if(dataIsMeaningful) {
/* do stuff with data if correct
* decryption key was found
*/
}
}
}
}
}
我为isMeaningful()
尝试了这种方法:
public static isMeaningful(byte[] inData) {
bool isGood = true;
for (uint i = 0; good && i < inData.Length; i++) {
isGood &= (char.IsLower((char)inData[i]));;
}
return isGood;
}
但是对于所有17576个可能的密钥,它都返回true。
如何确定解密密钥是否已将文件数据解密为有意义的数据?我不是在寻找解决方案代码或Project Euler问题的答案,我正在寻找如何检查您的解密尝试是否成功的解释。
答案 0 :(得分:2)
尝试使用不同的键并将其与正常英语的字母频率进行评分:空格,然后是E,T,A,O,I,N,S,H,R,D,L,U。选择得分最高的键首先进行试验。
答案 1 :(得分:1)
嗯,你可以假设只允许有效的ASCII值(因为它应该是明文)。因此,对于您解码的每个字母,只需检查生成的XOR结果是否为有效值:if(dataCopy[l] < 32 || dataCopy[l] > 122) continue;
这应该有助于消除绝大多数可能的键组合。
实际上,这项技术甚至可以用来缩小你的密钥集。因此,不是在整个1200字符串上迭代循环26 ^ 3次,而是最初迭代26次并跟踪哪个位置仍然有效的字母。
var letters = Enumerable.Repeat(Enumerable.Range((int)'a', 'z'-'a' + 1).Select(e => (char)e), 3).Select (e => e.ToList()).ToList();
for(int i = 0, j = 0; i < passwordBytes.Length; i++)
{
j = i % 3;
for(int k = 0; k < letters[j].Count; k++)
{
byte r = (byte)(letters[j][k] ^ passwordBytes[i]);
if(r < 32 || r > 122) letters[j].RemoveAt(k--);
}
}
这应该让您的有效字符几乎为零,此时您可以迭代剩余的值(这不应该花费太长时间)并查找一些有效的序列(我听说正在寻找{{1} }是个不错的选择。)
答案 2 :(得分:0)
您是否可以发送原始邮件的校验和以及加密邮件?解密后,计算校验和并查看它们是否匹配。
<击> 如果没有,那么测试消息呢?您可以先发送测试消息,例如“这是我的测试消息”,然后检查解密的消息是否逐字匹配。这不是万无一失的,但它可能会掩盖你。
答案 3 :(得分:0)
当您使用密钥解密数据时,它应该已经为您提供了一个文本文本。要检查合法数据,是否可以使用空格字符作为分隔符将文本拆分为文本数组,然后根据英语字典检查数组中的每个“单词”?