四、实验原理:
破译关键是求得加密矩阵的逆——解密矩阵。
分析出两个线性无关的明文向量与相应的密文向量,即可利用可逆矩阵求解矩阵方程计算出解密矩阵。即:
五、实验目的:
1、熟悉密码算法的基本破译方法;
2、理解密码算法破译中基于数学的分析方法的基本思路。
六、实验内容:
实现2阶Hill密码在已知明文攻击场景中,基于向量线性无关的破译。
七、实验器材(设备、元器件):
学生每人一台PC,安装Windows 7操作系统及VC++/Python开发环境。
八、实验步骤:
1.密钥生成
(1)
Rand()函数生成条件为模26的二阶矩阵,并且该矩阵的行列值与26互素
-
加密
(1)计算明文的个数若为奇数则把flag置为1进行填充。
将明文字母依次按每两个字母一组查出其表值,得到一组二维向量;通过加密矩阵得到而。
查向量 i 的字母表值,即得到密文
-
解密
(1)利用加密矩阵的逆矩阵,由密文得到明文
-
已知明文攻击原理
(1)只要分析出两个明文向量(线性无关)与相应的密文向量
若有
九、实验数据及结果分析:
1.实验参考代码:
加密:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 60
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int main(){
int p,q,dt;
int flag;
char C[MAX] = {0};
char P[MAX] = {0};
int len;
int T2[MAX] = {0};
int T1[MAX] ={0};
int Temp1[2] = {0}, Temp2[2] = {0};
int i,j;
int key[2][2] = { {0,0},{0,0} };
printf("======= Hill密码加密 =======\n\n");
printf("生成的随机加密矩阵:\n");
do{
key[0][0]=rand()%26;
key[0][1]=rand()%26;
key[1][0]=rand()%26;
key[1][1]=rand()%26;
dt = -1;
for(p=1; dt < 0; p++)
{
dt = ((key[0][0] * key[1][1] - key[0][1] * key[1][0]) + 26 * p)%26; //行列式的值
}
}while(gcd(dt,26)!=1);
for(p=0;p<2;p++){
for(q=0;q<2;q++){
printf("%d ",key[p][q]);}
printf("\n"); }
printf("请输入明文:\n");
scanf("%s", P);
len = strlen(P);
// 当长度为奇数时补齐一位
if(len % 2 == 1)
{
P[len] = P[len-1];
len = strlen(P);
flag=1;
}
for(i=0; i<len; i++)
{
if(P[i] >= 'A' && P[i] <= 'Z')
{
P[i] = P[i] + 32;
}
T1[i] = P[i] - 'a';
}
for(i=0; i<len; i+=2)
{
Temp1[0] = T1[i];
Temp1[1] = T1[i + 1];
// Temp2存储密文int值
Temp2[0] = (Temp1[0] * key[0][0] + Temp1[1] * key[1][0]) % 26;
Temp2[1] = (Temp1[0] * key[0][1] + Temp1[1] * key[1][1]) % 26;
T2[i] = Temp2[0];
T2[i + 1] = Temp2[1];
//printf("密文是%c%c",T2[i],T2[i+1]);
}
if(flag == 1)
{
len = len - 1;
}
for(i=0; i<4; i++)
{
C[i] = T2[i] + 'a';
printf("%c", C[i]);
}
printf("\n");
}
解密:
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
#define MAX 60
int main(){
char P[MAX] = {0};
char C[MAX] = {0};
int i,j;
int len;
int key[2][2] = { {0,0},{0,0} };
int flag;
int T2[MAX] = {0};
int T1[MAX] ={0};
int K2[2][2] = { {0,0},{0,0} };
int Temp1[2] = {0}, Temp2[2] = {0};
int temp,temp1;
printf("======= Hill 密码解密 =======\n\n");
printf("请输入秘钥的值:\n");
for(i=0; i<2; i++)
{
for(j=0; j<2; j++)
{
scanf("%d", &key[i][j]);
}
}
printf("请输入密文:");
scanf("%s", C);
len = strlen(C);
// 当长度为奇数时补齐一位
if(len % 2 == 1)
{
C[len] = C[len-1];
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';
}
temp = -1;
for(i=1; temp < 0; i++)
{
temp = (key[0][0] * key[1][1] - key[0][1] * key[1][0]) + 26 * i;
}
i = 1;
while(1)
{
if((temp * i) % 26 == 1)
{
temp1 = i;
break;
}
else
{
i++;
}
}
K2[0][0] = key[1][1] * temp1;
K2[0][1] = (((-1 * key[0][1]) + 26) * temp1) % 26;
K2[1][0] = (((-1 * key[1][0]) + 26) * temp1) % 26;
K2[1][1] = key[0][0] * temp1;
// printf(" %d %d %d %d %d %d\n",temp, temp1, K2[0][0], K2[0][1], K2[1][0], K2[1][1]);
// system("pause");
// printf(" %d %d %d %d %d %d\n",temp, temp1, K2[0][0]%26, K2[0][1]%26, K2[1][0]%26, K2[1][1]%26);
// system("pause");
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");
}
攻击:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
FILE *fp;
int knownedc[2][2]={21,18,3,19},knowneda[2][2]={20,3,1,15},invcip[2][2]={0},invA[2][2]={0};
int tran1[10000]={0},mes[10000]={0};
int T1[2]={0},msg[2]={0};
int i,j,detcip,invdetcip,len,flag;
char c[10000]={'\0'}; //密文
char pla[10000]={'\0'}; //明文
detcip = -1;
for(i=1; detcip < 0; i++){
detcip = ((knownedc[0][0] * knownedc[1][1] - knownedc[0][1] * knownedc[1][0]) + 26 * i)%26;//令行列式为正数
}
i = 1;
while(1){
if((detcip * i) % 26 == 1){
invdetcip = i;
break;
}
else
i++;
}
invcip[0][0]=(knownedc[1][1]*invdetcip)%26;
invcip[0][1]=(((-1 * knownedc[0][1]) + 26) * invdetcip) % 26;
invcip[1][0]=(((-1 * knownedc[1][0]) + 26) * invdetcip) % 26;
invcip[1][1]=(knownedc[0][0]*invdetcip)%26;
//加密矩阵A在模26下的逆矩阵
invA[0][0]=(knowneda[0][0]*invcip[0][0]+knowneda[0][1]*invcip[1][0])%26;
invA[0][1]=(knowneda[0][0]*invcip[0][1]+knowneda[0][1]*invcip[1][1])%26;
invA[1][0]=(knowneda[1][0]*invcip[0][0]+knowneda[1][1]*invcip[1][0])%26;
invA[1][1]=(knowneda[1][0]*invcip[0][1]+knowneda[1][1]*invcip[1][1])%26;
//输出A逆矩阵
printf("The Inverse of the encryption matrix :\n");
for(i=0;i<2;i++){
for(j=0;j<2;j++){
printf("%d ",invA[i][j]);
}
printf("\n");
}
//打开需要解密的密文
if((fp=fopen("c.txt","r"))==NULL){
printf("Open the file failure...\n");
exit(0);
}
i=0;
while(!feof(fp)){
c[i]=fgetc(fp);
i++;
}
len=strlen(c)-1; //len是密文的长度
// 当长度为奇数时补齐一位
if(len % 2 == 1){
c[len] = 'a';
len = len+1;
flag = 1;
}
for(i=0; i<len; i++){
if(c[i] >= 'A' && c[i] <= 'Z') {//将大写转化为小写
c[i] = c[i] + 32;
}
tran1[i] = c[i] - 'z'; //构建对应表,即a-z对应表值0-25
}
for(i=0; i<len; i+=2){
//储存字母对应表值,便于计算
T1[0] = tran1[i];
T1[1] = tran1[i + 1];
// msg存储解密后明文int值
msg[0] = (T1[0] * invA[0][0] + T1[1] * invA[0][1]) % 26;
msg[1] = (T1[0] * invA[1][0] + T1[1] * invA[1][1]) % 26;
//计算结束,将值赋给mes[],便于输出,mes的功能相当于计算前的tran1
mes[i] = msg[0];
mes[i + 1] = msg[1];
}
//对输入密文长度的判断,如是原密文为奇数则去除补位
if(flag == 1)
len = len - 1;
printf("cracked plain text :\n");
for(i=0; i<len; i++){
pla[i] = mes[i] + 'z'; //根据对应表返回各表值对应的字母
printf("%c", pla[i]);
}
printf("\n");
}