c++實現希爾密碼


實驗名稱:

希爾密碼的實現(c++版;本文只以26個大寫英文字符作為加密后的密文的可選項)

實驗原理:

引用知識:

記 Zm={0,1,2,...,m-1}
定義1:設A為定義在集合Zm 上的n階方陣,若存在一個定義在Zm上的方陣B,使得
AB=BA=E(mod m)
則稱A模m可逆,B為A的模m逆矩陣,記為
B=A^(-1)(modm)
定義2:設a ∈Zm若存在b∈Zm使得ab=1(mod m),則稱b為a的模m倒數或乘法逆,記作
b = a^(-1) (mod m)

命題:定義在集合Zm上的n階方陣A模m可逆的充要條件是:m和det(A)無公共素數因子,即m 與det(A)互素。

則在模運算下解方程組:AX=Y可得如下:
X=A^(-1)[1] (mod 26)* Y (mod 26)

下面求 A^(-1) (mod 26):

模m逆矩陣的計算:
由 |A|·A^(-1)=A* A為A的伴隨矩陣
設B=KA
為A的模26逆,其中k為待定系數
即:

BA=K·|A|·E
BA=E(mod26)
k·|A|=1(mod26)
k=|A|^(-1)(mod26)

故由上述所得解密矩陣的計算是由以加密矩陣行列式的值作為分母;1作為分子的分數;mod26;再乘以加密矩陣的伴隨矩陣得到的矩陣;最后mod26即得到解密矩陣。

算法分析:

加密:

本次實驗加密矩陣根據用戶輸入的階數由系統自動隨機生成,並判斷是否符合模逆矩陣的條件,如果不符合就生成新的加密矩陣,直到符合條件為止;
原文加密時生成的原文矩陣階數由加密矩陣的階數(記作n)和原文的長度決定,由原文的長度除以加密矩陣的階數向上取整(記作x),原文長度不夠的用字符A補全。然后將原文減去字符A;
即最后會生成一個x行n列的原文矩陣;
加密過程就是用原文矩陣乘以密文矩陣得到的結果mod26。然后用結果加上字符A得到密文。

int** makeMatrix(int param,int param1) {
int** mat = new int* [param];
for (int i = 0; i < param; i++)
{
	mat[i] = new int[param1];
}
for (int i = 0; i < param; i++)
{
	for (int j = 0; j < param1; j++)
	{
		mat[i][j] = 0;
	}
}
return mat;
}
//矩陣與矩陣相乘
std::string  multiply(int **param,int**param1,int param2,int param3){
std::string sum = "";
int** mat3 = makeMatrix(param2, param3);
for (int i = 0; i < param2; i++)
{
	for (int j = 0; j <param3; j++)
	{
		for (int k = 0; k < param3; k++)
		{
			
			mat3[i][j] += param[i][k] * param1[k][j];
			
		}
	
		mat3[i][j] = mat3[i][j] % 26;
		sum += (int)mat3[i][j] + 'A';
		 
	}
}
return sum;
}
//數字與矩陣相乘
int** multiply(int param,int**param1) {

//std::string sum="";
int col = _msize(param1[1]) / sizeof(int);
int** mat = makeMatrix(col, col);
for (int i = 0; i <col; i++)
{
	for (int j = 0; j < col; j++)
	{
		mat[i][j] = ((param1[i][j]* param)%26+26)%26;
		
	}

}

return mat;

}
//判斷生成的矩陣是否合理
void judge(bool &param,int **param1,int param2) {
int det = caculate(param1,param2);
if (det%2==0||det%13==0||det<0)
{
	param = true;
}
else {
	param = false;

}

}


//加密函數入口
void  getCode() {
  std::string orignal;
  int num,zhong;
  bool flag = true;
  std::cout << "請輸入原文:"<<std::endl;
std::cin >> orignal;
std::cout << "請選擇生成的密鑰矩陣的階數" << std::endl;
std::cin >> num;
int len = orignal.length() % num == 0 ? orignal.length() / num : orignal.length() / num + 1;
int** mat1 = makeMatrix(num,num);//密碼矩陣
int** mat2 = makeMatrix(len,num);//明文矩陣
//循環創建符合密碼矩陣要求的秘鑰
while (flag) {
	Sleep(500);
	srand(time(NULL));
	for (int i = 0; i < num; i++)
	{
		for (int j = 0; j < num; j++)
		{
			zhong = rand() % 20;
			mat1[i][j] = zhong == 0 ? 1 : zhong;
		}

	}
	judge(flag, mat1,num);

}
//補充不能夠形成矩陣的字符
int k = 0, le = num - orignal.length() % num;
for (int m = 0; m < le; m++)
{
	orignal += "A";
}
//將字符轉化為原文矩陣
for (int i = 0; i <len ; i++)
{
	for (int j = 0; j < num; j++)
	{
		mat2[i][j] = (orignal[k]-'A');
		k++;
	}
}
    //矩陣相乘
std::string mtext=multiply(mat2, mat1, len, num);
std::cout << "加密矩陣" << std::endl;
for (int i = 0; i < num; i++)
{
	for (int j = 0; j < num; j++)
	{
		std::cout << mat1[i][j]<<" ";
	}
	std::cout << "" << std::endl;
}
std::cout << "密文:" << mtext << std::endl;




}

解密:

由上述的引用知識點知:解密矩陣由加密矩陣的行列式分之一mod26然后乘以加密矩陣的伴隨矩陣得到的結果mod26得到。

①分數求模

對於分數求模,我借用了mod運算的分配律
(a×b) mod c=(a mod c * b mod c) mod c
即把分數求模轉化為了整數求模,借助於少於30次的的循環,即可得出結果,代碼如下。

注釋:param參數為行列式的值mod26得到的值

int gradeMode(int param) {

for (int i = 1; ; )
{
	if ((26 * i+1) % param == 0)
	{
		return (26*i+1)/param;
		break;
	}
	i += 1;
}

}

②伴隨矩陣的求解

本次實驗我是用了求行列式calaulate()函數和求代數余子式surplus()函數的函數遞歸得到,兩函數代碼如下:。

int caculate(int **param,int param1){
int row = param1;
if (row==2)
{
	return param[0][0]*param[1][1]-param[0][1]*param[1][0];
}
else {
	int sum = 0;
	for (int i = 0; i < row; i++)
	{
		sum += param[0][i]*surplus(param,0,i,param1);
	}
	return sum;
}
}

int surplus(int **param,int x,int y,int param1) {
if (param1==2)
{
	return pow(-1, x + y + 2)*param[1-x][1-y];
}
else {

	int row = param1, col = param1;
	int xflag = 0, yflag = 0;
	int** mat = makeMatrix(row - 1, col - 1);
	for (int i = 0; i < row; i++)
	{
		if (i!=x)
		{
			yflag = 0;
			for (int j = 0; j < col; j++)
			{
				if (j != y )
				{
					mat[xflag][yflag] = param[i][j];
					yflag++;
				}

			}
		xflag++;
		}			
		
	}
	return pow(-1, x + y + 2) * caculate(mat, param1 - 1);


}


}

借助①②即可得到解密的矩陣:具體代碼如下:

void putcode() {
int num;
std::string dense;
std::cout << "請輸入密文" << std::endl;
std::cin >> dense;
std::cout << "請輸入階數:" << std::endl;
std::cin >> num;
int** mat1 = makeMatrix(num,num);//接受加密矩陣
int** mat2 = makeMatrix(dense.length() / num, num);//密文矩陣
int** mat3 = makeMatrix(num,num);//

std::cout << "請輸入加密矩陣:" << std::endl;
    //獲取加密矩陣
for (size_t i = 0; i < num; i++)
{
	for (size_t j = 0; j < num; j++)
	{
		std::cin >> mat1[i][j];
	}
}

    //轉換密文維密文矩陣
int k=0;
for (size_t i = 0; i < dense.length()/num; i++)
{
	for (size_t j = 0; j < num; j++)
	{
		mat2[i][j] = (dense[k] - 'A');
		k++;
	}
}

    //算密碼矩陣的伴隨矩陣
for (int k = 0; k < num; k++)
{
	for (int j = 0; j < num; j++)
	{
		mat3[k][j] = surplus(mat1, j, k, num);
	}
}


int num1=caculate(mat1,num)%26;//計算行列式
int** mat4 = multiply(gradeMode(num1), mat3);//解碼矩陣

for (int k = 0; k < num; k++)
{
	for (int j = 0; j < num; j++)
	{
		std::cout<<mat4[k][j]<<" " ;
	}
	std::cout << "" << std::endl;
}


std::string  original = multiply(mat2, mat4,dense.length()/num,num); //原文

std::cout << "解密結果為:"<<original;




}

程序實現界面:

主程序部分代碼:

#include "decode.h"
#include "Encryption.h"

void main() {
while (true)
{
	system("cls");
	int select=0;
	std::cout << "加密--1;解密--2" << std::endl;
	std::cin >> select;
	switch (select)
	{
	case 1:
		getCode();
		system("pause");
		break;
	case 2:
		putcode();
		system("pause");
		break;
	default:
		break;
	}
	
}


}

加密:

解密:


  1. 這表示A的逆 ↩︎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM