*歡迎閱讀小明哥的博客*
這裏主要介紹的是:古典密碼之 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.退出:
限於目前的水平,僅寫出上述函數,歡迎大家閱讀,加密解密函數,我只寫了hill密碼的一部分,上述代碼還有很多需要完善的地方,歡迎各位大神指點,懇請各位批評指正,謝謝