*歡迎閱讀小明哥的部落格*
這裡主要介紹的是:古典密碼之 hill密碼加密解密過程的程式設計實作。
首先,請看對我對hill密碼做的簡單介紹。
hill密碼是古典密碼中多表代換密碼部分的重要一環,以下的介紹節選自百度,想要深入了解的請查閱書籍補充相關知識。
原理:希爾密碼(Hill Password)是運用基本矩陣論原理的替換密碼,由Lester S. Hill在1929年發明。每個字母當作26進制數字:A=0, B=1, C=2... 一串字母當成n維向量,跟一個n×n的矩陣相乘,再将得出的結果模26。注意用作加密的矩陣(即密匙)在\mathbb_^n必須是可逆的,否則就不可能譯碼。隻有矩陣的行列式和26互質,才是可逆的。
需要的知識儲備:
1)線性代數基礎知識.
2) 初等數論基礎知識.
約定:
1)希爾密碼常使用Z26字母表,在此貼中,我們也以Z26最為字母表進行講解.在附帶源碼中有兩種字母表選擇.
2) 大家都知道最小的質數是2,1 既不是質數也不是合數. 在此我們定義1對任何質數的模逆為其本身.
因為對于任意質數n,有: 1*1 % n = 1 的. 也應該是很好了解的.
過程:
1)加密:密文=明文*密鑰矩陣 (注:明文要被分割成與密鑰維數相同的一維行列式)
2)解密:明文=密文*密鑰矩陣的逆 (注:要求與加密過程相同)
加密解密過程如下圖:
例: 加密過程: 解密: 對上述過程進行程式設計,主要的函數聲明如下:/*
*
* 頭檔案名稱:hillcrypto.h
* 實作檔案名稱:hillcrypto.cpp
* 項目名稱:多表代換密碼之hill密碼
* 作者:鄒明
* 完成時間:2016.3.14
*
*/
#ifndef __HILLCRTPTO_H__
#define __HILLCRTPTO_H__
#include<iostream>
using namespace std;
#include<assert.h>
#include <iomanip>
#define ROW 4 //密鑰行數為4
#define COV 4 //密鑰列數為4
void InputKeys(float keys[ROW][COV]); //輸入密鑰
void InputWords(char *words); //輸入明文
void InputObwords(char *words); //輸入密文
void PopKeys(float keys[ROW][COV]); //輸出密鑰
void Encryption(float keys[ROW][COV], char *words, char *crypto); //明文加密
void Decode(float keys[ROW][COV], char *words, char *crypto); //密文解密
bool Gauss(float A[ROW][COV], float B[ROW][COV], int n); //高斯消去法求逆矩陣
void ObMatrix(float a[ROW][COV], float b[ROW][COV], int n); //求密鑰逆矩陣
void menu(); //菜單
#endif
函數實作過程中的主函數實作以及菜單函數實作如下:
/* 實作檔案名稱:hillcrypto.cpp */
#include"hillcrypto.h"
int main()
{
menu(); //菜單+選擇
system("pause");
return 0;
}
void menu()
{
float keys[ROW][COV] = { 8, 6, 9, 5, 6, 9, 5, 10, 5, 8, 4, 9, 10, 6, 11, 4 }; //加密矩陣(預設密鑰)
float obkeys[ROW][COV] = { 0 }; //解密矩陣 (密鑰逆矩陣)
char words[100] = { 0 };
char crypto[100] = { 0 };
char obwords[100] = { 0 };
bool flag = true; //菜單選擇
bool chose = false; //密鑰選擇
char cn = 0;
while (flag)
{
int n = 0;
cout << endl;
cout << "\t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl;
cout << "\t\t\t1.輸入密鑰" << endl;
cout << "\t\t\t2.明文加密" << endl;
cout << "\t\t\t3.密文解密" << endl;
cout << "\t\t\t4.退出" << endl << endl;
cout << "\t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl;
cout << "請選擇->:";
cin >> n;
switch (n)
{
case 1:
system("cls");
cout << "預設密鑰為:";
PopKeys(keys);
cout << "請問您要重新輸入密鑰? y/n" << endl << "請選擇->:";
cin >> cn;
if ((cn == 'y') || (cn == 'Y'))
{
InputKeys(keys); //輸入密鑰
}
else if ((cn == 'n') || (cn == 'N'))
{
cout << "感謝您選擇使用預設密鑰!" << endl;
}
else
cout << "輸入有誤,請重新選擇!" << endl;
system("pause");
break;
case 2:
system("cls");
InputWords(words); //輸入明文
Encryption(keys, words, crypto); //加密
cout << "密文是->:" << crypto << endl;
system("pause");
break;
case 3:
system("cls");
InputObwords(crypto); //輸入密文
ObMatrix(keys, obkeys, COV); //計算解密矩陣
Decode(obkeys, obwords, crypto); //解密
cout << "明文是->:" << obwords << endl;
system("pause");
break;
case 4:
system("cls");
cout << endl << endl << endl;
cout << setw(15) << "謝謝使用!" << endl;
flag = false;
system("pause");
break;
default:
cout << "選擇有誤,請重新選擇!" << endl;
system("pause");
break;
}
}
}
輸入明文函數和輸入密文函數:
void InputWords(char *words) //輸入明文
{
assert(words);
cout << "請輸入明文:";
char *start = words;
int flag = 1;
getchar();
while (flag)
{
*words = getchar();
words++;
if (*(words - 1) == '\n')
{
*words = '\0';
flag = 0;
}
}
words = start;
while (*start)
{
if (('A' <= *start) && (*start <= 'Z'))
{
*words = *start;
words++;
}
else if (('a' <= *start) && (*start <= 'z'))
{
*words = *start - 32;
words++;
}
start++;
}
*words = '\0';
cout << "輸入成功 !" << endl;
}
void InputObwords(char *words) //輸入密文
{
assert(words);
cout << "請輸入密文:";
char *start = words;
int flag = 1;
getchar();
while (flag)
{
*words = getchar();
words++;
if (*(words - 1) == '\n')
{
*words = '\0';
flag = 0;
}
}
words = start;
while (*start)
{
if (('A' <= *start) && (*start <= 'Z'))
{
*words = *start;
words++;
}
else if (('a' <= *start) && (*start <= 'z'))
{
*words = *start - 32;
words++;
}
start++;
}
*words = '\0';
cout << "輸入成功 !" << endl;
}
輸入密鑰與輸出密鑰函數:
void InputKeys(float keys[ROW][COV]) //輸入密鑰
{
cout << "請輸入密鑰:" << endl;
for (size_t i = 0; i < ROW; i++)
{
cout << "請輸入第" << i << "行密鑰("<<ROW<<"個數):";
for (size_t j = 0; j < COV; j++)
{
cin >> keys[i][j];
}
}
cout << "輸入成功 !" << endl;
}
void PopKeys(float keys[ROW][COV]) //輸出密鑰
{
cout << "密鑰為:" << endl;
for (size_t i = 0; i < ROW; i++)
{
for (size_t j = 0; j < COV; j++)
{
cout << keys[i][j] << " ";
}
cout << endl;
}
}
加密函數:
void Encryption(float keys[ROW][COV], char *words, char *crypto) //加密函數
{
assert(words);
int len = strlen(words);
char *start = words;
while (len > 0)
{
int matrix[ROW] = { 0 };
for (int i = 0; i < ROW; i++)
{
if (*start)
matrix[i] = *start - 'A';
else
matrix[i] = 0;
start++;
}
len -= ROW;
int cry[ROW] = { 0 };
for (int i = 0; i < ROW; i++)
{
int temp = 0;
for (int j = 0; j < COV; j++)
{
temp = matrix[j] * keys[j][i] + temp;
}
cry[i] = temp % 26;
*crypto = 'A' + cry[i]; //計算密文
crypto++;
}
}
}
解密函數,以及求逆矩陣函數:
void Decode(float obkeys[ROW][COV], char *words, char *crypto)//解密函數
{
assert(crypto);
int len = strlen(crypto);
char *start = crypto;
while (len > 0)
{
int matrix[ROW] = { 0 };
for (int i = 0; i < ROW; i++)
{
if (*start)
matrix[i] = *start - 'A';
else
matrix[i] = 0;
start++;
}
len -= ROW;
int cry[ROW] = { 0 };
for (int i = 0; i < ROW; i++)
{
int temp = 0;
for (int j = 0; j < COV; j++)
{
temp = matrix[j] * obkeys[j][i] + temp;
}
cry[i] = temp % 26;
*words = 'A' + cry[i]; //計算明文
words++;
}
}
}
void ObMatrix( float a[ROW][COV], float b[ROW][COV], int n) //求逆矩陣函數
{
int i, j; //定義矩陣的行列式
if (Gauss(a, b, n))
{
cout << "該方陣的逆矩陣為: \n";
for (i = 0; i < n; i++)
{
cout << setw(4);
for (j = 0; j < n; j++)
{
int temp =b[i][j]/ 1;
float num = b[i][j] - temp;
if (fabs(num) < 0.50)
b[i][j] = (int)temp;
else
b[i][j] = temp + (int)(num * 2);
cout << b[i][j] << setw(10);
}
cout << endl;
}
}
cout << "逆矩陣(mod26):" << endl;
for (int i = 0; i < ROW; i++)
{
cout << setw(4);
for (int j = 0; j < COV; j++)
{
if (b[i][j] >= 0)
{
b[i][j] = (int)b[i][j] % 26;
}
else
{
b[i][j] = 26 + (int)b[i][j] % 26;
}
cout << b[i][j] << setw(6);
}
cout << endl;
}
}
bool Gauss(float A[ROW][COV], float B[ROW][COV], int n) //高斯消去法
{
int i, j, k;
float max, temp;
float t[ROW][COV]; //臨時矩陣
//将A矩陣存放在臨時矩陣t[n][n]中
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
t[i][j] = A[i][j];
}
}
//初始化B矩陣為機關陣
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
B[i][j] = (i == j) ? (int)1 : 0;
}
}
for (i = 0; i < n; i++)
{
//尋找主元
max = t[i][i];
k = i;
for (j = i + 1; j < n; j++)
{
if (fabs(t[j][i]) > fabs(max))
{
max = t[j][i];
k = j;
}
}
//如果主元所在行不是第i行,進行行交換
if (k != i)
{
for (j = 0; j < n; j++)
{
temp = t[i][j];
t[i][j] = t[k][j];
t[k][j] = temp;
//B伴随交換
temp = B[i][j];
B[i][j] = B[k][j];
B[k][j] = temp;
}
}
//判斷主元是否為0, 若是, 則矩陣A不是滿秩矩陣,不存在逆矩陣
if (t[i][i] == 0)
{
cout << "There is no inverse matrix!";
return false;
}
//消去A的第i列除去i行以外的各行元素
temp = t[i][i];
for (j = 0; j < n; j++)
{
t[i][j] = t[i][j] / temp; //主對角線上的元素變為1
B[i][j] = B[i][j] / temp; //伴随計算
}
for (j = 0; j < n; j++) //第0行->第n行
{
if (j != i) //不是第i行
{
temp = t[j][i];
for (k = 0; k < n; k++) //第j行元素 - i行元素*j列i行元素
{
t[j][k] = t[j][k] - t[i][k] * temp;
B[j][k] = B[j][k] - B[i][k] * temp;
}
}
}
}
return true;
}
程式運作結果:
選擇:1
選擇:y
選擇:n
選擇 2.明文加密:
選擇 3.密文解密:
選擇 4.退出: