“Hill的加密与解密”
Hill加密是另一种多字母代替密码,与多表代替密码不同的是,Hill密码要求将明文分成同等规模的若干个分组(最后一个分组涉及到填充),每一个分组被整体的加密代换,即希尔密码属于分组加密。Hill密码的算法思想是:将一个分组中的d个连续的明文字母通过线性变换转换为d个密文字母。这种变换由d个线性方程决定,其中每个字母被分配一个数值(0,1,。。。,25)。解密只需要做一次逆变换就可以了,密钥就是变换矩阵本身。
设明文为一维矩阵m,密文为一维矩阵c,密钥用k矩阵表示,则:
即密文分组=明文分组*密钥矩阵。
本程序使用的密钥是:
下面是具体的源程序:
—头文件:classical.h #pragma once //古典密码之希尔加密 #include <math.h> #include <string.h> #define ROW 4 //行 #define COL 4 //列 int* plus(int(*K)[COL], int * num) //进行加密 { int *arr = (int *)calloc(sizeof(int),4); int sum = 0; int sub = 0; for (int i = 0; i < ROW; i++) //1*4的行列式与4*4的行列式相乘 { for (int j = 0; j < COL; j++) { sum = (*(num + j)) * (*(*(K + j) + i)); sub = sub + sum; } arr[i] = (arr[i] + sub) % 26; sub = 0; } return arr; } int fun(int i, int j, int(*K)[COL]) //求伴随矩阵 { int num = 0; int arr[ROW][COL] = { 0 }; int left = 0; int right = 0; for (int k1 = 0; k1 < ROW; k1++) { for (int k2 = 0; k2 < COL; k2++) { if (k1 < i && k2 < j) { arr[k1][k2] = *(*(K + k1) + k2); } else if (k1 < i && k2 > j) { arr[k1][k2 - 1] = *(*(K + k1) + k2); } else if (k1 > i && k2 > j) { arr[k1 - 1][k2 - 1] = *(*(K + k1) + k2); } else if (k1 > i && k2 < j) { arr[k1 - 1][k2] = *(*(K + k1) + k2); } } } left = arr[1][1] * arr[2][2] * arr[0][0] + arr[0][1] * arr[1][2] * arr[2][0] + arr[1][0] * arr[2][1] * arr[0][2]; right = arr[0][2] * arr[1][1] * arr[2][0] + arr[0][1] * arr[1][0] * arr[2][2] + arr[0][0] * arr[1][2] * arr[2][1]; num = pow((double)(-1), (i + 1) + (j + 1)) * (left - right); return num; } int* answer(int(*K)[COL], int * str, int det) //希尔解密 { int ptr[ROW][COL] = { 0 }; //ptr为逆矩阵 int* ans = (int *)calloc(sizeof(int), 4); int sum = 0; int sub = 0; int bag = 0; for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { bag = fun(i, j, K) / (det); if (bag < 0) { ptr[j][i] = (26 + bag) % (26); } else { ptr[j][i] = bag % (26); } } } for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { sum = (*(str + j)) * ptr[j][i]; sub = sub + sum; } ans[i] = (ans[i] + sub) % 26; sub = 0; } return ans; } void menu() //菜单 { printf(" ——古典密码 \n\n"); printf("********** 1.加密 *******\n"); printf("********** 2.解密 *******\n"); printf("********** 0:退出 *******\n"); printf("请选择:"); } char* inputclear() //输入明文 { printf("请输入明文:"); char num[20] = {‘\n‘}; char *ptr = num; int i = 0; char ch; fflush(stdin); //清除缓冲区 while ((ch = getchar()) != ‘\n‘) { num[i] = ch; i++; } return ptr; } char* inputsecret() //输入密文 { printf("请输入密文:"); char num[20] = { ‘\n‘ }; char *ptr = num; int i = 0; char ch; fflush(stdin); //清除缓冲区 while ((ch = getchar()) != ‘\n‘) { num[i] = ch; i++; } return ptr; } void judge(int n, int(*K)[4]) //处理加密或解密 { char *ptr, *pln; int src[20]; int num[4] = { 0 }; int *parr = NULL; int *pnum = NULL; int det = -1; //计算K的行列式的值 switch (n) { case 1: //加密 ptr = inputclear(); for (int i = 0; i < strlen(ptr); i++) //将字符串转化为数字 { if (*ptr != ‘\n‘ && *ptr != EOF) { src[i] = *(ptr + i) - ‘A‘; } else { break; } } printf("加密后得到的密文:"); pnum = src; while (*pnum >= 0 && *pnum <= 25) { for (int i = 0; i < ROW; i++) { num[i] = *(pnum + i); } parr = plus(K, num); for (int j = 0; j < ROW; j++) { printf("%c", *(parr+j) + ‘A‘); } pnum = pnum + ROW; } printf("\n"); free(parr); break; case 2: pln = inputsecret(); for (int i = 0; i < strlen(pln); i++) //将字符串转化为数字 { if (*pln != ‘\n‘ && *pln != EOF) { src[i] = *(pln + i) - ‘A‘; } else { break; } } printf("解密后得到的明文:"); pnum = src; while (*pnum >= 0 && *pnum <= 25) { for (int i = 0; i < ROW; i++) { num[i] = *(pnum + i); } parr = answer(K, num, det); for (int j = 0; j < ROW; j++) { printf("%c", *(parr + j) + ‘A‘); } pnum = pnum + ROW; } printf("\n"); free(parr); break; case 0: exit(EXIT_FAILURE); default: break; } } —源文件:test.cpp #define _CRT_SECURE_NO_WARNINGS 1 //希尔加密 #include <stdio.h> #include <stdlib.h> #include "classical.h" int main() { int K[4][4] = { { 8, 6, 9, 5 }, { 6, 9, 5, 10 }, { 5, 8, 4, 9 }, { 10, 6, 11, 4 } }; //密钥 int left=K[0][0] * K[1][1] * K[2][2] * K[3][3] + K[1][0] * K[0][3] * K[3][2] * K[2][1]+ K[2][0] * K[3][1] * K[0][2] * K[1][3] + K[3][0] * K[0][1] * K[1][2] * K[2][3]; int right = K[0][3] * K[1][2] * K[2][1] * K[3][0] + K[0][0] * K[1][3] * K[2][2] * K[3][1]+ K[0][1] * K[1][0] * K[2][3] * K[3][2] + K[0][2] * K[1][1] * K[2][0] * K[3][3]; int n = 0; menu(); scanf("%d", &n); judge(n, K); system("pause"); return 0; }
—运行结果:
Hill加密:
Hill解密:
很明显,Hill密码将解密的长消息分组,分组的长度取决于密钥矩阵的维数,Hill密码的强度在于完全隐藏了单字母的频率。字母和数字的对应也可以更改为其他的方案,使得不容易攻击成功。一般来说,对抗仅有密文的攻击强度较高,但易受到已知明文攻击。
时间: 2024-10-05 16:47:09