维吉尼亚密码是一种多表替换密码,暴力破解相对来说比单表置换密码难一些。在网上找基于重合互指数法的破解代码,java、python都有,本菜鸟只有c++用的相对熟练一点,就用c++写了暴力破解过程。代码耗时提高效率什么的暂没考虑。
维吉尼亚方阵是26*26的方阵,第一行代表明文字母,第一列代表密钥字母,每一行都是一个凯撒加密。
在只知道密文的情况下想要破解维吉尼亚加密,首先要确定密钥的长度。
确定密钥长度有两种方式:
1.Kasiski测试法
搜索长度至少为2的相邻的一对对相同的密文段,记下它们之间的距离。而密钥长度d可能就是这些距离的最大公因子。
2.重合指数法
公式:
代码:
void Miyaolenth(char c[])
{
int klen=1; //密钥长度
int clen=strlen(c); //密文的长度
while(1)
{
float IC[klen]; //重合指数
float avgIC=0; //平均重合指数
for(int i=0;i<klen;i++) //统计分组字母个数
{
int out[26]={ 0 }; //盛放字母个数的数组
for(int j=0;i+j*klen<clen;j++)
out[(int)(c[i+j*klen]-'A')]++;
float e=0.000f;
int L=0;
for(int k=0;k<26;k++) //子串密文长度
L+=out[k];
L*=(L-1);
for(int k=0;k<26;k++) //分组计算重合指数IC
if(out[k]!=0)
e=e+((float)out[k]*(float)(out[k]-1))/(float)L;
IC[i]=e;
}
for(int i=0;i<klen;i++)
avgIC+=IC[i];
avgIC/=klen; //求IC的平均值
if (avgIC >= 0.06) break; //判断退出条件,重合指数的平均值是否大于0.06
else klen++;
}
cout<<"密钥长度为:"<<klen<<endl;
}
确定好密钥长度之后开始求密钥。
重合互指数法求密钥:
根据密钥的长度对密文进行分组,每一组都是一个凯撒加密。计算拟重合指数,通过拟重合指数可以确定每组的移位密钥,从而求出整个的密钥。
公式:
代码:
float p[] = {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};
int key[100]={ 0 }; //存放密钥
for(int i=0;i<klen;i++) //统计分组字母个数
{
int g=0; //密文移动g个位置
for(int t=0;t<26;t++)
{
float x=0.000f; //拟重合指数
int out[26]={ 0 }; //盛放字母个数的数组
for(int j=0;i+j*klen<clen;j++)
out[(int)(c[i+j*klen]-'A')]++;
int L=0;
for(int k=0;k<26;k++) //子串密文长度
L+=out[k];
for(int k=0;k<26;k++)
x=x+p[k]*out[(k+g)%26];
if(x/L>0.055)
{
key[i]=g;
break;
}
else g++;
}
}
cout<<"加密密钥为:";
for(int i=0;i<klen;i++) //输出密钥字
cout<<char ('a'+key[i]);
cout<<endl;
求出密钥之后解密就很容易啦,查表即可。