首先使用Friedman确定关键词长度
//s为密文,len为密文长度
int friedman(string s,int len)
{
int keyLength = 2; //猜测秘钥长度
double avgIc; //平均重合指数
while(true)
{
vector<string> cipherGroup; //密文分组
avgIc = 0;
double Ic[keyLength]; //重合指数
//根据秘钥长度分组
for(int i=0; i<keyLength; ++i)
{
string temp = "";
for(int j=0; i+j*keyLength<len; ++j)
{
temp += s[i+j*keyLength];
}
cipherGroup.push_back(temp);
}
//计算每一组的重合指数
for(int i=0; i<keyLength; ++i)
{
string subCipher = cipherGroup[i];
int occurrentNumber[26]= {0}; //记录每个字母出现的次数
for(int j=0; j<subCipher.length(); j++)
{
occurrentNumber[subCipher[j]-'a']++;
}
//计算重合指数
double denominator = subCipher.length()/1.0*subCipher.length();
for(int k=0; k<26; k++)
{
double o = occurrentNumber[k]/1.0;
Ic[i] += o*(o-1);
}
Ic[i] /= denominator;
}
//判断退出条件,重合指数的平均值是否大于0.065
for(int i=0; i<keyLength; ++i)
{
avgIc += Ic[i];
}
avgIc /= (keyLength/1.0);
if(avgIc>=0.065)
{
break;
}
else
{
keyLength++;
}
cipherGroup.clear();
}
cout<<"密钥长度为:"<<keyLength<<endl;
return keyLength;
}
再利用重合指数法确定关键词,解出明文
//keyLength为关键词长度,ciphertext为密文
void decryptCipher(int keyLength,string ciphertext)
{
int key[keyLength];
vector<string> cipherGroup;
double probability[] = {0.082,0.015,0.028,0.043,0.127,0.022,0.02,0.061,0.07,0.002,0.008,
0.04,0.024,0.067,0.075,0.019,0.001,0.06,0.063,0.091,0.028,0.01,0.023,0.001,0.02,0.001
};
//根据密钥长度分组
for(int i=0; i<keyLength; ++i)
{
string temp = "";
for(int j=0; i+j*keyLength<ciphertext.length(); ++j)
{
temp += ciphertext[i+j*keyLength];
}
cipherGroup.push_back(temp);
}
//确定密钥
for(int i=0; i<keyLength; ++i)
{
double MG; //重合指数
int flag; //移动位置
int g = 0; //密文移动g个位置
string subCipher=""; //子串
while(true)
{
int occurenceNumber[26]= {0}; //字母出现次数
MG = 0;
flag = g;
subCipher = cipherGroup[i];
//统计字母出现的次数
for(int h=0; h<subCipher.length(); ++h)
{
occurenceNumber[subCipher[h]-'a']++;
}
//计算重合指数
for(int k=0; k<26; ++k,++flag)
{
double p = probability[k];
flag = (flag == 26)? 0:flag;
double f = occurenceNumber[flag]/1.0/subCipher.length();
MG += p*f;
}
//判断退出条件
if(MG >= 0.055)
{
key[i] = g;
break;
}
else
{
g++;
}
}
}
//打印密钥
string keyString = "";
for(int i=0; i<keyLength; ++i)
{
keyString += (char)(key[i]+'a');
}
cout<<"密钥为:"<<keyString<<endl;
//解密
string plainBuffer = "";
cout<<ciphertext<<endl;
for(int i=0; i<ciphertext.length(); i++)
{
int j = i % keyLength;
int k = keyString[j]-'a';
plainBuffer += (ciphertext[i]-'a'+26-k)%26+'a';
}
cout<<"破解后明文为:"<<plainBuffer<<endl;
}
经过测试,关键词长度可准确求出,关键词会有误差。