C++希尔密码的实现以及运用

希尔密码(Hill Cipher)是运用基本矩阵论原理的替换密码,由Lester S. Hill在1929年发明。每个字母当作26进制数字:A=0, B=1, C=2... 一串字母当成n维向量,跟一个n×n的矩阵相乘,再将得出的结果mod26。注意用作加密的矩阵(即密匙)在\mathbb_^n必须是可逆的,否则就不可能译码。只有矩阵的行列式和26互质,才是可逆的。

实验内容及要求

1、学生自己随机选取一个5×5矩阵,判断是否可以作为密钥

2、利用所选密钥,对任意给定的5元明文信息进行加解密

3、对加密得到的密文进行解密,验证结果的正确性

4、现截获一段密文:

WFHNESISDLMMBIOKRKXTGHMMNVNZSTCTCPTPKZZUWUHFYCOPCWMVKQCFNZLPKIZLVDLZENBZCDB

经分析这段密文是用希尔密码编译的,且这段密文的最后25个字母依次代表字母aftertommorrowiswednesday,破译这段密文的内容。

分析

1、我们需要写一个求矩阵行列式的函数,然后判断他是否与26互素,若为则可以作为密钥;

2、这里需要写一个加密函数,主要就是向量与矩阵的乘积(明文需要转换成字母的次序),故需要写一个转换函数;

3、这里需要求密钥的逆,在通过密文的矩阵乘于密钥的逆即可,这里需要将字母的次序转换成字母,也需要一个转换函数;

4、通过已知的明密文对照求密钥,将25个明文化为5X5的矩阵为X,密文为Y;由Y=XK推出K=X^-1Y(X^-1为X的逆)求得密钥,然后即可对密文进行解密,明文=密文*密钥的逆;

代码如下:

#include <iostream>
#include <vector>
#include<string.h>
#include<stdio.h>
#define N 5
using namespace std;


int exgcd(int A,int &x,int B,int &y)
{
    int x1,y1,x0,y0;
    x0=1;y0=0;
    x1=0;y1=1;
    int r=(A%B+B)%B;
    int q=(A-r)/B;
    x=0;y=1;
    while(r)
    {
        x=x0-q*x1;
        y=y0-q*y1;
        x0=x1;
        y0=y1;
        x1=x;y1=y;
        A=B;B=r;r=A%B;
        q=(A-r)/B;
    }
    return B;
}
int modq(int a,int n,int x,int y)
{
int b=1;
   int d=exgcd(a,x,n,y);
        if(b%d==0)
        {
            x=(x%(n/d)+n/d)%(n/d);
            if(!x)x++;
            return x;
        }
        else printf("Not Exist\n");
}
//计算矩阵的行列式 
int getA(int A[N][N],int n)
{
if(n==1)   return A[0][0];
int num=0;
int temp[N][N]={0.0};
int i,j,k;
for(i=0;i<n;i++)
{
for(j=0;j<n-1;j++)
{
for(k=0;k<n-1;k++)
{
if(k>=i)   temp[j][k]=A[j+1][k+1];
else       temp[j][k]=A[j+1][k];
}
}
int t=getA(temp,n-1);
if(i%2==0)  num+=A[0][i]*t;
else        num-=A[0][i]*t;
}
return num%26;
}
//求矩阵的伴随矩阵 
void getAstart(int A[N][N],int n,int newA[N][N]) 
{
if(n==1)
{
newA[0][0]=1;
return;
}
int i,j,k,t;
int temp[N][N];
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
for(k=0;k<n-1;k++)
{
for(t=0;t<n-1;t++)
{
temp[k][t]=A[(k>=i)?k+1:k][(t>=j)? t+1:t];
}
}
newA[j][i]=(getA(temp,n-1));
if((i+j)%2==1)  newA[j][i]=-newA[j][i];
newA[j][i]=newA[j][i]%26;
if(newA[j][i]<0)  newA[j][i]=(newA[j][i]+26)%26;
}
}
}
//求矩阵的逆
void  getInverse(int A[N][N],int n,int I[N][N])
{
int t[N][N]={0.0};
int flag=getA(A,n);
int x,y;
int e=modq(flag,26,x,y);
if(e==0)  return;
else
{
getAstart(A,n,t);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
I[i][j]=(t[i][j]*e)%26;
if(I[i][j]<0)  I[i][j]=(I[i][j]+26)%26;
}
}
}


int gcd(int m,int n)
{
int r=0;
if(m==0||n==0)  return 0;
if(m==1||n==1)  return 1;
else
{
if(n>m)
{
int s=m;
m=n;n=s;
}
r=m%n;
while(r!=0)
{
m=n;
n=r;
r=m%n;
if(r==0)
{
return n;
}
}
}
}

bool IsInverse(int A[N][N],int n)//判断矩阵是否可作为密钥 
{
int t=getA(A,n);
if(gcd(t,26)==1)  return true;
else   return false;
}

vector<int> add(int A[N][N],int n,vector<int>num)//加密 
{
vector<int>aft;
for(int i=0;i<n;i++)
{
int temp=0;
for(int j=0;j<n;j++)
{
temp+=(num[j]*A[j][i]);
}
temp=temp%26;
if(temp<0) temp=(temp+26)%26;
aft.push_back(temp);
}
return aft;
}

vector<int> count(int A[N][N],int n,vector<int> num)//解密 
{
vector<int>aft;
int I[N][N];
getInverse(A,n,I);
for(int i=0;i<n;i++)
{
int temp=0;
for(int j=0;j<n;j++)
{
temp+=(I[j][i]*num[j]);
}
temp=temp%26; 
if(temp<0)  temp=(temp+26)%26;
aft.push_back(temp);
}
return aft;
}

 vector<int> change1(string s) //将明文密文转化为字母表中的次序,A为0,依次类推 
 {
  vector<int>v;
  for(int i=0;i<s.size();i++)
  {
  if(s[i]>='A'&&s[i]<='Z')
  v.push_back(s[i]-'A');
  if(s[i]>='a'&&s[i]<='z')
  v.push_back(s[i]-'a');
}
return v;
 }

 string change2(vector<int>v)//将字母的次序转化为小写字母 
 {
  string s="";
  for(int i=0;i<v.size();i++) 
  {
  char a=v[i]+97;
  s+=a;
}
return s;
 }
 string change3(vector<int>v)//将字母的次序转化为大写字母 
 {
  string s="";
  for(int i=0;i<v.size();i++) 
  {
  char a=v[i]+65;
  s+=a;
}
return s;
 }
int main()
{
//检测矩阵是否可作为密钥 
cout<<"..............执行实验步骤123.............."<<endl;
string fiveletters;
vector<int> fivenums;
int ars[5][5];
cout<<"请输入5x5矩阵:"<<endl; 
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++)
{
cin>>ars[i][j];
}
}
int I[5][5]={0.0};
getInverse(ars ,5,I);
if(IsInverse(ars,5))
{
cout<<"该矩阵可作为密钥"<<endl;
cout<<"请输入五元明文:"<<endl; 
cin>>fiveletters;
fivenums=change1(fiveletters);
        vector<int> nnums;
        nnums=add(ars,5,fivenums);
        string small="";
        small=change2(nnums);
cout<<"加密结果如下:"<<endl;
cout<<small<<endl;
vector<int> oldnums;
oldnums=count(ars,5,nnums);
cout<<"解密结果如下:"<<endl;
string big="";
big=change3(oldnums);
cout<<big<<endl;
}
else
{
cout<<"矩阵不可作为密钥"<<endl; 

//破译密文
cout<<".........执行实验第四步解密密文得到明文............."<<endl; 
string b="MVKQCFNZLPKIZLVDLZENBZCDB";//密文 
string c="aftertommorrowiswednesday";//明文 
vector<int> bnum;vector<int> cnum;
bnum=change1(b);
cnum=change1(c);
int matrix1[5][5]={0.0};
int matrix2[5][5]={0.0};
for(int i=0;i<25;i++)
{
matrix1[i/5][i%5]=bnum[i];
matrix2[i/5][i%5]=cnum[i];
}
int inmatrix1[5][5]={0.0};
int inmatrix2[5][5]={0.0};
getInverse(matrix2,5,inmatrix2);
int key[5][5];
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++)
{
int temp=0;
for(int k=0;k<5;k++)
{
temp+=inmatrix2[i][k]*matrix1[k][j];
}
key[i][j]=temp%26;
}
}
cout<<"求得密钥为:"<<endl;
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++)
{
cout<<key[i][j]<<" ";
}
cout<<endl;
}

int inkey[5][5]={0.0};
getInverse(key,5,inkey);
string miwen="WFHNESISDLMMBIOKRKXTGHMMNVNZSTCTCPTPKZZUWUHFYCOPCWMVKQCFNZLPKIZLVDLZENBZCDB";
vector<int> minum;
minum=change1(miwen);
int mimatrix[15][5]={0.0};
for(int i=0;i<75;i++)
{
mimatrix[i/5][i%5]=minum[i];
}
int mingmatrix[15][5]={0.0};
for(int i=0;i<15;i++)
{
for(int j=0;j<5;j++)
{
int temp=0;
for(int k=0;k<5;k++)
{
temp+=mimatrix[i][k]*inkey[k][j];
}
mingmatrix[i][j]=temp%26;
}
}
vector<int> mingnum;
for(int i=0;i<15;i++)
{
for(int j=0;j<5;j++)
{
mingnum.push_back(mingmatrix[i][j]);
cout<<endl;
cout<<"解密结果为"<<endl;
string mingwen;
mingwen=change2(mingnum);
cout<<mingwen<<endl;

结果如下:


©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页