多表代换加密(verginia 密码)破解

本文介绍了维吉尼亚密码的破解方法,首先通过计算子串的无偏估计值IC来确定密钥长度,然后利用拟重合指数找出每个字串的密钥,最后解密得到明文。主要步骤包括读取密文、求密钥长度、获取密钥及解密过程。

密文:qqnscgpyjioxaiqksufhsnwvvkwixkbljngjepwelyreazscfufpiaggihlabltngkxngyyrtmrjiwsexwihrglnzbkotrzgtculfctugrihwlqqjkrecbskxlyeeosnavpxkbvmdultxwihbcmyvbzjqaajhyseqqnnsurgsmflxtegnmdtqrtnnrbcgbkotrzgtculpnssbxihxhovftvisufwfvfgvtgcfylaragocmobiugeakfclyoxraaonnwzojyeqgpjjhxlmosviyubkpyotktbwkarkfrxehltpyjcgyozhxobtnnritwwfwkoesanahkowozgdcnxobjrntgygyajyafuuluxpkttuytlmvqdweqgnxmgpcwupzulwwzxaeeonayxkxripyplgmbxripymyltyxqozocmsltnqlnyigszfwlcyoncutimnattomalxwilbtgnwkjltngonognpymyfoofgzflflfknmagdxkaaonxaofmzayotckxuyjcgkdnztqajcrttuvoxwhefonvazajyajolfwqmjsdbarefhtujdtkfijmbbyiamnyoavyttuksyktyxztqosyslbvfnnmegwgqowozjiuyglbnsguplwobwyibttihxobtnnritwwqajagsehlmenwifkoztbdmftnnoqwobaflfurualbbhhnrlyfzbbnngkrgkhcywiigcskxzdwigedultlfseeyhchwxcfsgkwujwpqnpntdagobasaaienzbpyfprxdckvrbxefyogwhccmerdimlbkpfcgovclbbbfnqlunmkbxupbxtofbqrjseklulxactbvmdultcxwhrglnzhrcqiaonakhjntfgneewrrwieerycfzfbxurytbsmknjdgubyltztqeqnhbza


结果:


1.算法思想

首先循环对密文分子串,分别分为一个字串,两个字串等等,然后计算子串的无偏估计值IC,直到字串的无偏估计值的平均值大于0.065为止,然会返回字串的个数,这就是密钥的长度。然后每个字串分别求移位26次的拟重合指数,最大拟重合指数的移位次数加上a就是单个字串的密钥。然后把每个字串的密钥加一起就是密文的密钥。然后根据密钥减a的次数对每个字串移位,即得到明文。

2.步骤

(1)调用input()方法从txt文件引入密文

(2)调用get_keysize()方法求出密钥长度

(3)调用get_keyword()方法求出密钥

(4)调用decode()方法根据密钥解密

 说明:由于把分字串,词频,求单个字串的密钥都定义成了方法,是一层一层调用的,叙述起来很麻烦,于是就只写了几个大的方法。

#include<iostream>
#include<map>
#include<string>
#include <fstream>
using namespace std;
map<char, int> get_count(string s)
{
	map<char, int> word_count;
	size_t i = 0;
	string words = s;
	while (i != s.size())
	{
		++word_count[words[i]];//统计字符个数,按字母顺序排列
		++i;
	}
	return word_count;
}
void print(map<char, int> m)
{
	map<char, int> word_count = m;
	map<char, int>::const_iterator iter = m.begin();
	while (iter != m.end())
	{
		cout << iter->first << ":"<<iter->second<<endl;
		++iter;
	}
}
float get_per_ic(string s)
{
	map<char, int> word_count = get_count(s);
	map<char, int>::const_iterator iter = word_count.begin();
	fl
float sum=0;
	float l = (float)s.size();
	while (iter != word_count.end())
	{
		float count = float(iter->second);
		float ic = (count*(count - 1)) / (l*(l - 1));//计算无偏估计值
		sum += ic;
		++iter;
	}
	return sum;
	
}
string* divid_str(string s, int n)
{
	int i=0,l=(int)s.size();
	string *a = new string[n];
	float *ic = new float[n];
	for (int i = 0; i < n; i++)
	{
		int distance =i;
		for (int j = 0; j < l; j++)
		{
			if (distance >= l)break;//越界退出
			a[i] += s[distance];
			distance+= n;//每次移动n位
		}
	}
	return a;
}
float get_mean_ic(string s, int n)
{
	float ic=0;
	string *a = divid_str(s,n);
	for (size_t i = 0; i < n; i++)
	{
		ic += get_per_ic(a[i]);//总的无偏估计值
	}
	return ic / n;
}
double get_prob(char i)
{
	double prob = 0;
	switch (i)
	{
	case 'a':prob = 0.0805; break;
	case 'b':prob = 0.0162; break;
	case 'c':prob = 0.0320; break;
	case 'd':prob = 0.0365; break;
	case 'e':prob = 0.1231; break;
	case 'f':prob = 0.0228; break;
	case 'g':prob = 0.0161; break;
	case 'h':prob = 0.0514; break;
	case 'i':prob = 0.0718; break;
	case 'j':prob = 0.0010; break;
	case 'k':prob = 0.0052; break;
	case 'l':prob = 0.0403; break;
	case 'm':prob = 0.0225; break;
	case 'n':prob = 0.0719; break;
	case 'o':prob = 0.0794; break;
	case 'p':prob = 0.0229; break;
	case 'q':prob = 0.0020; break;
	case 'r':prob = 0.0603; break;
	case 's':prob = 0.0659; break;
	case 't':prob = 0.0959; break;
	case 'u':prob = 0.0310; break;
	case 'v':prob = 0.0093; break;
	case 'w':prob = 0.0203; break;
	case 'x':prob = 0.0020; break;
	case 'y':prob = 0.0188; break;
	case 'z':prob = 0.0009; break;
	}
	return prob;
}
double get_m(string s)
{
	map<char, int> wordcount = get_count(s);
	map<char, int>::const_iterator iter = wordcount.begin();
	double m=0.0;
	size_t l = s.size();
	while (iter != wordcount.end())
	{
		int count = iter->second;
		m += get_prob(iter->first)*count / l;//拟重合指数
		++iter;
	}
	return m;
}
char move_position(string s)
{
	string temp;
	size_t i;
	float max_ic = 0;
	int max_i = 0;
	for (i = 1; i <=26; i++)
	{
		temp = s;
		int n = 0;
		char c = temp[0];
		for (size_t j = 0; j < temp.size(); j++)
		{
			n= temp[j] - 97;
			char c =((n - i+26)%26)+97;//移位
			temp[j] = c;
		}
		float ic = get_m(temp);
		if (ic>max_ic)
		{
			max_ic = ic;//最大值
			max_i = i;
		}
		
	}
	char c = 'a' + max_i%26;
	return c;
}
string get_keyword(string s, int n)
{
	string keyword = "";
	string *a = divid_str(s,n);
	for (size_t i = 0; i < n; i++)
	{
		keyword += move_position(a[i]);
		
	}
	return keyword;

}
int get_keysize(string s)
{
	int i;
	for ( i = 1; i>0; i++)
	{
		float ic = get_mean_ic(s,i);
		if (ic >= 0.065)break;

	}
	return i;

}
string input(string filename)
{
	ifstream in(filename);
	string line,str;
	if (in) // 有该文件  
	{
		while (getline(in, line)) // line中不包括每行的换行符  
		{
			str += line;
		}
	}
	else // 没有该文件  
	{
		return "no such file";
	}
	return line;

}
string decode(string s)
{
	string str = s;
	string keyword = get_keyword(s, get_keysize(s));
	int keysize = (int)keyword.size();
	string decode(s.size(),' ');
	for (int i = 0; i < keysize; i++)
	{
		int n,distance=i;
		for (int j = 0; j < s.size(); j++)
		{
			if (distance >= s.size())break;//越界退出
			n = (int)s[distance] - 97;
			int move = keyword[i] - 97;
			str[distance] = ((n - move + 26) % 26) + 97;
			distance += keysize;//每次移动n位
		}
		

	}
	return str;
}





评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值