加解密部分代码参考这位老哥Hill密码的加密与解密,做了相应的一些修改,需要注意的是代码中有两个问题尚待解决:
1.代码中补全位没有起到相应作用,如果输入明文为奇数则无法正常加解密。
2.当选取的密钥矩阵求逆后有小数元,无法实现正确解密。
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 60
int main()
{
int K1[2][2] = {0}, K2[2][2] = {0};
int Temp1[2] = {0}, Temp2[2] = {0};
char P[N] = {0}, C[N] = {0};
int T1[N] = {0}, T2[N] = {0};
int len, flag=0, temp, temp1, i, j;
printf("Hill2密码\n\n");
printf("请依次输入密钥矩阵的值:\n");
for(i=0; i<2; i++) //存储密钥
{
for(j=0; j<2; j++)
{
scanf("%d", &K1[i][j]);
}
}
//输入明文
printf("请输入明文:\n");
scanf("%s", P);
len = strlen(P);
// 当长度为奇数时补齐一位
if(len % 2 == 1)
{
P[len] = 'a';
len = strlen(P);
flag = 1;
}
// 将大写转成小写,并赋值给T1数组
for(i=0; i<len; i++)
{
if(P[i] >= 'A' && P[i] <= 'Z')
{
P[i] = P[i] + 32;
}
T1[i] = P[i] - 'a';
}
// 得到加密后结果,存储在T2中
for(i=0; i<len; i+=2)
{
Temp1[0] = T1[i];
Temp1[1] = T1[i + 1];
// Temp2存储密文int值
Temp2[0] = (Temp1[0] * K1[0][0] + Temp1[1] * K1[1][0]) % 26;
Temp2[1] = (Temp1[0] * K1[0][1] + Temp1[1] * K1[1][1]) % 26;
T2[i] = Temp2[0];
T2[i + 1] = Temp2[1];
}
//如果有补全位,输出时去掉补全位
if(flag == 1)
{
len = len - 1;
}
printf("加密结果为:\n");
for(i=0; i<len; i++)
{
C[i] = T2[i] + 'a';
printf("%c ", C[i]);
}
printf("\n");
//解密
printf("请输入密文:\n");
scanf("%s", C);
len = strlen(C);
// 当长度为奇数时补齐一位
if(len % 2 == 1)
{
C[len] = 'a';
len = strlen(C);
flag = 1;
}
//大小写转换
for(i=0; i<len; i++)
{
if(C[i] >= 'A' && C[i] <= 'Z')
{
C[i] = C[i] + 32;
}
T2[i] = C[i] - 'a';
}
// 求K的逆
temp = -1;
for(i=1; temp < 0; i++)
{
temp = (K1[0][0] * K1[1][1] - K1[0][1] * K1[1][0]) + 26 * i;
}
i = 1;
while(1)
{
if((temp * i) % 26 == 1)
{
temp1 = i;
break;
}
else
{
i++;
}
}
K2[0][0] = K1[1][1] * temp1;
K2[0][1] = (((-1 * K1[0][1]) + 26) * temp1) % 26;
K2[1][0] = (((-1 * K1[1][0]) + 26) * temp1) % 26;
K2[1][1] = K1[0][0] * temp1;
// 得到解密后结果,存储在T2中
for(i=0; i<len; i+=2)
{
Temp2[0] = T2[i];
Temp2[1] = T2[i + 1];
// Temp1存储明文int值
Temp1[0] = (Temp2[0] * K2[0][0] + Temp2[1] * K2[1][0]) % 26;
Temp1[1] = (Temp2[0] * K2[0][1] + Temp2[1] * K2[1][1]) % 26;
T1[i] = Temp1[0];
T1[i + 1] = Temp1[1];
}
if(flag == 1)
{
len = len - 1;
}
printf("解密结果为:\n");
for(i=0; i<len; i++)
{
P[i] = T1[i] + 'a';
printf("%c ", P[i]);
}
printf("\n");
return 0;
}
破译原理网上很多利用,利用矩阵运算,再此不赘述,直接放上代码,和加解密一样,明文矩阵的逆若有小数元无法实现正常破译。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#define N 60
int main()
{
int K[2][2] = {0};
int Temp1[2] = {0}, Temp2[2] = {0};
char c[N]={0},m[N]={0},_c[N]={0};
int T1[N] = {0}, T2[N] = {0};
int lenc,lenm,temp,temp1,i,j;
printf("破译Hill2密码\n\n");
//输入已知明文段
printf("请输入已知明文:\n");
scanf("%s", c);
lenc = strlen(c);
//输入已知密文段
printf("请输入已知密文:\n");
scanf("%s", m);
lenm= strlen(m);
//当明密文长度不足4时报错
if(lenc<4||lenm<4)
{
printf("明密文字段不满足破译条件");
assert(0);
}
//取前四位明文,将大写转成小写,并赋值给T1数组
for(i=0; i<4; i++)
{
if(c[i] >= 'A' && c[i] <= 'Z')
{
c[i] = c[i] + 32;
}
T1[i] = c[i] - 'a';
}
//取前四位密文,将大写转成小写,并赋值给T2数组
for(i=0; i<4; i++)
{
if(m[i] >= 'A' && m[i] <= 'Z')
{
m[i] = m[i] + 32;
}
T2[i] = m[i] - 'a';
}
// 求明文数组的逆
temp = -1;
for(i=1; temp < 0; i++)
{
temp = (T1[0]*T1[3]-T1[1]*T1[2]) + 26 * i;
}
i = 1;
while(1)
{
if((temp*i)%26==1)
{
temp1 = i;
break;
}
else
{
i++;
}
}
_c[0]=(T1[3]*temp1)%26;
_c[1]=(((-1*T1[1]+26))*temp1)%26;
_c[2]=(((-1*T1[2]+26))*temp1)%26;
_c[3]=(T1[0]*temp1)%26;
//密文矩阵右乘明文逆矩阵
K[0][0]=(T2[0]*_c[0]+T2[2]*_c[1])%26;
K[0][1]=(T2[1]*_c[0]+T2[3]*_c[1])%26;
K[1][0]=(T2[0]*_c[2]+T2[2]*_c[3])%26;
K[1][1]=(T2[1]*_c[2]+T2[3]*_c[3])%26;
printf("密钥为:");
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
printf("%d ",K[i][j]);
}
}
return 0;
}