希尔密码(原理+代码)

目录

希尔密码

1、原理

2、流程图

3、编程实现

4、总结


希尔密码

1、原理

        希尔密码是一种运用基本矩阵论原理的代换密码,由Lester S. Hill在1929年发明。

        首先将字母转换为数字,将字母分成多个n维向量,跟一个n×n的矩阵相乘,再将得出的结果模26。需要注意的是密钥矩阵必须是可逆的,即矩阵的行列式和26互质。

        Hill密码能较好地抵抗统计分析法,对抗唯密文攻击的强度较高,但易受到已知明文攻击。

2、流程图

3、编程实现

        难点:如何根据密钥矩阵求密钥逆矩阵

        行列式可逆的充分条件:方阵的行列式不等于零 在这里行列式的值还需要和26互质 矩阵求逆可以使用伴随矩阵法LU分解法

        为了减少计算量和实现难度,这里使用3*3的密钥矩阵。同时伴随矩阵法求逆一般使用下面公式

                                                                        K^{-1}=d^{-1}\times adj(K)(行列式值的逆乘以伴随矩阵)

        参考:希尔密码  矩阵求逆

        具体代码如下:

        默认输入小写英文字母明文不带空格,以及3*3的密钥矩阵存在逆矩阵且为正整数。(因为这样实现简单。。。)

        主函数:

#include"Hill.h"

int main() {
	while (1) {
		show();		//菜单界面
		keyDown();	//按键处理
		system("pause");
		system("cls");
	}
}

          Hill.h

#pragma once
#include<cstdio>
#include<iostream>
#include<cstring>
#include<Windows.h>
#include<vector>
using namespace std;
void init();
void show();
void keyDown();
void readFile();
void saveFile();
void encrypt();
void decrypt();
int gcd(int a, int b, int& x, int& y);
int getInv(int a, int m);
void getAntiKey(int key[][3]);

        Hill.cpp 

#include "Hill.h"
string fileStr = "";
string finalStr = "";
int x = 0, y = 0;
int antikey[3][3];//密钥的逆
int key[3][3];//密钥
/*
0 11 15
7 0 1
4 19 0
*/
void init()//初始化
{
	x = 0;
	y = 0;
	fileStr = "";
	finalStr = "";
	memset(antikey, 0, sizeof(antikey));
	memset(key, 0, sizeof(key));
}
void show()
{
	cout << "*****************希尔密码*****************" << endl;
	cout << "\t\t1.加密文件" << endl;
	cout << "\t\t2.解密文件" << endl;
	cout << "\t\t3.退出" << endl;
	cout << "******************************************" << endl;

}

void keyDown()//按键处理
{
	int userkey = 0;
	cin >> userkey;
	switch (userkey) {
	case 1:
		cout << "-----------------加密文件-----------------" << endl;
		readFile();
		encrypt();
		saveFile();
		init();
		break;
	case 2:
		cout << "-----------------解密文件-----------------" << endl;
		readFile();
		decrypt();
		saveFile();
		init();
		break;
	case 3:
		exit(0);
		break;
	}
}

void readFile()//读取文件
{
	cout << "请输入文件名:" << endl;
	string fileName;
	cin >> fileName;
	FILE* fp = fopen(fileName.c_str(), "r+");
	if (fp == nullptr) {
		cout << "未找到相关文件" << endl;
		return;
	}
	else {
		cout << "成功打开文件" << endl;
	}
	char ch;
	int pos = 0;
	while ((ch = fgetc(fp)) != EOF) {
		fileStr += ch;
	}
	cout << endl << "待处理的文件为:" << endl;
	cout << fileStr << endl;
	fclose(fp);
}



void saveFile()//保存文件
{
	string fileName;
	cout << endl << "请输入要保存信息的文件名:" << endl;
	cin >> fileName;
	FILE* fp = fopen(fileName.c_str(), "w+");
	if (fp == nullptr) {
		cout << endl << "保存文件失败" << endl;
		return;
	}
	else {
		cout << endl << "保存成功" << endl;
	}
	fprintf(fp, "%s", finalStr.c_str());
	fclose(fp);

}

void encrypt()//加密文件
{
	vector< vector<int> >  c;//明文矩阵
	vector< vector<int> >  a;//密文矩阵 

	if (fileStr.size() % 3 == 1)fileStr += "xx";//补充两个
	if (fileStr.size() % 3 == 2)fileStr += "x";

	int* m = new int[fileStr.size()];//明文按列分组并转化为数字 

	//分成多个3个字母的列向量
	for (int i = 0; i < fileStr.size(); i++) {
		m[i] = fileStr[i] - 'a';
	}

	for (int i = 0; i < fileStr.size(); i += 3) {
		vector<int> temp = { m[i],m[i + 1],m[i + 2] };
		c.push_back(temp);
	}
	cout << endl << "明文矩阵为:" << endl;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < c.size(); j++) {
			cout << c[j][i] << " ";//明文矩阵 
		}
		cout << endl;
	}
	cout << endl;

	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < c.size(); j++) {
			cout << char(c[j][i] + 97) << " ";//明文矩阵 
		}
		cout << endl;
	}
	cout << endl;


	cout << "请输入密钥矩阵(默认矩阵可逆且为整数)" << endl;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			cin >> key[i][j];
		}
	}

	cout << endl << "按下任意键进行加密" << endl;
	char ch = getchar(); ch = getchar();

	//矩阵乘法
	for (int i = 0; i < c.size(); i++) {//矩阵的列数 
		vector<int> temp;
		for (int j = 0; j < 3; j++) {
			int pos = 0;
			for (int k = 0; k < 3; k++) {
				pos += key[j][k] * c[i][k];
			}
			temp.push_back((pos) % 26);
		}
		a.push_back(temp);
	}

	cout << "密文矩阵" << endl;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < a.size(); j++) {
			cout << a[j][i] << " ";//密文矩阵 
		}
		cout << endl;
	}
	cout << endl;

	for (int i = 0; i < a.size(); i++) {
		for (int j = 0; j < a[0].size(); j++) {
			finalStr += char(a[i][j] + 97);
		}
	}

	delete[]m;
	cout << endl << "得到的密文为:" << endl;
	cout << finalStr << endl;
}

void decrypt()//解密文件
{
	vector< vector<int> >  c;//密文矩阵
	vector< vector<int> >  a;//明文矩阵 

	int* m = new int[fileStr.size()];//密文按列分组并转化为数字 

	//分成多个3个字母的列向量
	for (int i = 0; i < fileStr.size(); i++) {
		m[i] = fileStr[i] - 'a';
	}

	for (int i = 0; i < fileStr.size(); i += 3) {
		vector<int> temp = { m[i],m[i + 1],m[i + 2] };
		c.push_back(temp);
	}

	cout << endl << "密文矩阵为:" << endl;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < c.size(); j++) {
			cout << c[j][i] << " ";//密文矩阵 
		}
		cout << endl;
	}
	cout << endl;

	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < c.size(); j++) {
			cout << char(c[j][i] + 97) << " ";//密文矩阵 
		}
		cout << endl;
	}
	cout << endl;


	cout << "请输入密钥矩阵(默认矩阵可逆且为整数)" << endl;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			cin >> key[i][j];
		}
	}

	getAntiKey(key);//求逆矩阵
	cout << endl << "成功求出密钥矩阵的逆" << endl;

	//密钥矩阵的逆矩阵
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			cout << antikey[i][j] << " ";
		}
		cout << endl;
	}

	cout << endl << "按下任意键进行解密" << endl;
	char ch = getchar(); ch = getchar();

	//矩阵乘法
	for (int i = 0; i < c.size(); i++) {//矩阵的列数 
		vector<int> temp;
		for (int j = 0; j < 3; j++) {
			int pos = 0;
			for (int k = 0; k < 3; k++) {
				pos += antikey[j][k] * c[i][k];
			}
			temp.push_back((pos) % 26);
		}
		a.push_back(temp);
	}

	cout << "解密后的矩阵" << endl;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < a.size(); j++) {
			cout << a[j][i] << " ";
		}
		cout << endl;
	}
	cout << endl;

	for (int i = 0; i < a.size(); i++) {
		for (int j = 0; j < a[0].size(); j++) {
			finalStr += char(a[i][j] + 97);
		}
	}
	delete[]m;
	cout << endl << "得到的明文为:" << endl;
	cout << finalStr << endl;
}

int gcd(int a, int b, int& x, int& y)//求最大公约数
{
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	int g = gcd(b, a % b, x, y);
	int temp = x;
	x = y;
	y = temp - (a / b) * y;
	return g;
}

int getInv(int a, int m)//求乘法逆元
{
	gcd(a, m, x, y);
	return (x % m + m) % m;
}

void getAntiKey(int key[][3]) {

	//求行列式值 
	int v1 = key[0][0] * (key[1][1] * key[2][2] - key[1][2] * key[2][1]);
	int v2 = -key[0][1] * (key[1][0] * key[2][2] - key[2][0] * key[1][2]);
	int v3 = key[0][2] * (key[1][0] * key[2][1] - key[1][1] * key[2][0]);
	//cout<<v1<<" "<<v2<<" "<<v3<<endl;

	int d = (v1 + v2 + v3) % 26;
	//cout<<d<<endl;

	int dinv = getInv(d, 26);
	//cout<<dinv<<endl;

	//求伴随矩阵 
	int temp[4];
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			memset(temp, 0, sizeof(temp));
			int pos = 0;
			for (int x = 0; x < 3; x++) {
				for (int y = 0; y < 3; y++) {
					if (x != i && y != j) {
						temp[pos++] = key[x][y];
					}
				}
			}
			int cur = pow(-1, i + 1 + j + 1) * (temp[0] * temp[3] - temp[2] * temp[1]);
			antikey[j][i] = (dinv * (cur % 26 + 26)) % 26;
		}
	}

}

4、总结

        通过采用线性代数中的矩阵乘法运算和逆运算,能够较好地抵抗频率分析,很难被攻破。当加密矩阵的阶数n越大,破译的难度就会增大,此时计算量也大。

        希尔密码体系为破译者至少设置了三道关口,加大了破译难度。破译希尔密码的关键是猜测文字被转换成几维向量(列矩阵的行数)、所对应的字母表是怎样排列的,更为重要的是要设法获取加密矩阵A。要破解密码,向量的维数、字母的排列表和加密矩阵三者缺一不可。(百度百科)

  • 4
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值