密碼學--希爾密碼

一、實驗目的

?1、通過實現簡單的古典密碼算法,理解密碼學的相關概念

??2、理解明文、密文、加密密鑰、解密密鑰、加密算法、解密算法、流密碼與分組密碼等。

二、實驗內容

1、題目內容描述

①定義分組字符長度

隨機生成加密密鑰并驗證密鑰的可行性

plain文件讀入待加密明文

④判斷明文長度是否需要填充

進行希爾密碼加密

⑥將加密后得到的密文放入cipher文件

根據加密密鑰計算解密密鑰

進行解密運算

⑨將解密后的文本放入plain_decrypted文件,與明文進行對比

⑩仿射密碼與希爾密碼的異同

  1. 關鍵代碼的設計、實現與執行

設計思路:

在最開始以宏定義的方式定義分組字符長度,關鍵代碼:
#define M 2 //定義最大分組長度

先以時間產生隨機數作為加密密鑰矩陣enkey,但是這里要通過求最大公因數的方式來驗證加密密鑰enkey的可行性,即密鑰矩陣enkey的行列式detb和N的最大公因數為1,即detb,N互質(其中N為定義在Zn上的N):

下面代碼是運用Euclid算法計算最大公因數的關鍵代碼:

srand(time(NULL));//以時間取隨機數

do {

for (int i = 0; i < M; i++) {

for (int j = 0; j < M; j++) {

enkey[i][j] = rand() % N;//隨機生成密鑰矩陣

}

}

detb = enkey[0][0] * enkey[1][1] - enkey[0][1] * enkey[1][0];//計算加密矩陣的行列式

} while (gcd(detb, N) != 1);//檢驗密鑰的可行性,也就是行列式與N是否互質,能否得到行列式的逆元

得到加密密鑰后,從文件讀入已經準備好的加密明文也可通過記事本修改),下面代碼是以讀的方式打開文件,并判斷是否在文件夾中存在命名的文件的關鍵代碼部分:

?FILE *plain_file = fopen("plain.txt", "r");//以讀的方式打開

????if (plain_file == NULL) {

????????printf("無法打開明文文件!\n");//判斷無法打開給出提示

????????exit(1);//無法打開只能以異常終止結束運行

}

得到明文后,先調用read_palinfile()函數,統計其長度,看是或否剛好為M的倍數,若不是就進行填充,此處對于剩余需要填充的部分都填的x,再重新計算需要加密解密的文本長度,于是有msize = msize + M - r,關鍵代碼部分如下:

int msize = read_plainfile(plain_file, &plain_text[0]);

int r = msize % M;//判斷是否需要填充

if (r < 0)

r += M;

if (r > 0)//如需填充,都填為0,加密后統一得到x

{

for (int i = msize; i < msize + M - r; i++)

plain_text[i] = 23;//x的ASCII碼為120,'a'-'x'=120-97=23

msize = msize + M - r;//重新得到加密或解密文本新的長度

}

在得到明文文件后,調用函數read_plainflie(),將明文文件里的有效內容(即字母)放入字符數組,方便后續分組,且可以有效字符的長度,關鍵代碼部分如下:

while ((ch = getc(plain_file)) != EOF)//getc()用于在打開文件中獲取一個字符

{

if (ch >= 'a' && ch <= 'z')

*plain = ch - 97;//ASCII碼轉換

else if (ch >= 'A' && ch <= 'Z')

*plain = ch - 65;//ASCII碼轉換

else continue;

i++;//計數有效字符數量

*plain++;//指針加加,字符數組向下移一位,好存放下一次的字符

}

return i;//返回文件中有效字符的數量,以方便后續分組

以M為分組數量單位,進行加密,其中運用了二階矩陣的運算,并判斷得到的新的是否有負數,如有,加模,使其轉化為正數,再加上a的ASCII碼,使其統一為大寫字母,*cipher++,指向下一次計算得到的字符存放的地址,關鍵代碼部分如下:

for (i = 0; i < M; i++)//矩陣乘法

{

tmp = 0;

for (j = 0; j < M; j++)

tmp = tmp + plain[j] * enkey[j][i];// 分組加密計算

tmp %= N;//模N

if (tmp < 0)

tmp += N;//負數轉正數

*cipher = tmp + 97;//統一轉換為大寫字母

*cipher++;

將字符數組分組,并調用分組加密的函數進行加密。tmpplain,tmpcipher是以M為單位長度的字符數組,將需要加密的文本分組放入tmpplain,再調用encrypt_block進行以M為單位長度的分組加密,得到的結果返回給同樣是長度為M的tmpcipher字符數組,再依此傳給cipher,關鍵代碼部分如下:

for (i = 0; i < msize; i = i + M)//依此從字符數組中取M個字符,調用分組函數encrypt_block()進行加密或解密

{

for (j = 0; j < M; j++)

tmpplain[j] = plain[i + j];//在要加密或者解密的文件中連續截取M個字符放入存放M個字符的數組進行加密或解密

encrypt_block(tmpplain, enkey, &tmpcipher[0]);//調用分組加密函數

for (j = 0; j < M; j++)//將加密或者解密后得到的字母依次放入cipher數組

{

*cipher = tmpcipher[j];//賦值

*cipher++;//指針后移,下依此循環存放新的字幕

}

}

計算解密矩陣,由于計算矩陣的逆矩陣,是行列式的倒數(也就是此處的逆元)*伴隨矩陣,二階矩陣的伴隨矩陣直接用口訣主對調,副變號即可,過程即是先調用inverse_a()計算行列式逆元,并判斷其是否為負數,如是,加上N,使其轉化成正數,再通過公式計算出解密矩陣,并判斷矩陣中每個數是否為負數,如是,加上N使其轉化成正數,得到解密所需的解密矩陣,以下是關鍵代碼部分:

int a1 = inverse_a(detb);//計算加密矩陣行列式的逆元

if (a1 < 0)

a1 += N;

dekey[0][0] = enkey[1][1] * a1 % N;//主對調,副變號

dekey[0][1] = (-enkey[0][1] * a1) % N;

dekey[1][0] = (-enkey[1][0] * a1) % N;

dekey[1][1] = enkey[0][0] * a1 % N;

for (int i = 0; i < M; i++)//遍歷檢查解密矩陣中是否有負數,如有,加N,轉換成正數

{

for (int j = 0; j < M; j++)

{

if (dekey[i][j] < 0)

dekey[i][j] += N;//加N

}

}

結果截圖如下:

3、實驗結果分析

多測幾組后實驗得到結果下:

由以上結果即分析可知加密的時候程序自動跳過了空格即字符進行了加密解密,且最后全部由小寫字母輸出,當然也可全部由大寫字母輸出,只需要將+97換成+65即可,因為分別對應著小寫字母‘a’的ASCII碼和大寫字母‘A’的ASCII碼

而在第二個實驗的結果和第三個實驗的結果發現多出了x,這是因為在以2分組時,會有剩余,于是由x進行了填充。

對于仿射密碼和希爾密碼的異同:
綜上可知,希爾密碼和仿射密碼都是需要求逆元,只是仿射密碼是直接對密鑰求逆元得到的就是解密的密鑰,而希爾是對加密矩陣的行列式求逆元,得到的也只是行列式的逆元,而還需要*加密矩陣的伴隨矩陣,得到的新的矩陣才是解密的矩陣

在代碼中也可以看到,希爾密碼和仿射密碼一樣解密和加密幾乎一樣只是密鑰矩陣不一樣,步驟一樣,所以可以直接調用一個函數,只是傳參不一樣。

不同的是,仿射密碼是直接對明文的每個字符進行依此進行加密解密,而希爾密碼需要對對需要加密或者解密問文本進行分組,每M個一組一起進行加密或者解密,如是在n個M組以后還有剩余不夠M個,即進行填充,可以以任何形式進行填充,在此次實驗中,我選擇了小寫字母x,因為在一般情況下,其出現頻率最小。

三、實驗思考

1、實驗過程總結

在此次實驗中,直接在仿射密碼的代碼上進行修改,就簡單很多,只需要將不同的地方進行修改即可,如最大公因式函數、求逆元函數、以及文件打開等部分都保持不變,但在隨機生成函數部分,由一個改成一個矩陣,然后就是分組進行加密解密部分進行修改。

但是在代碼實現過程中由于編程能力問題,傳參部分一直出現問題,最終經過查詢相關知識得以解決,此外,在解密過程中,一開始沒有調用read_plainfile()函數,讀cipher文件里的東西直接進行解密,導致解密出來的的文本與明文一直不匹配,經過不斷看看,分析代碼,發現問題進行修改后解密出來的文本終于能夠和原明文匹配。

通過此次實驗使我加深了對希爾密碼的理解,清晰了希爾密碼加密解密每一步的原理,也知道了希爾密碼和仿射密碼的區別和相同點,同時加強了我自己的代碼能力。

  1. 回答實驗指導書最后提出的問題

對合密鑰是一種弱密鑰,不應該在實際加密中使用,這是為什么?

對合密鑰使用了相同的密鑰進行加密解密,這意味著加密和解密在同一個用戶之間進行,這使得對合密鑰的安全性受到很大的限制,因為如果一個用戶失去了對合密鑰的控制,他也將無法保護自己的信息;而如果兩個用戶使用同一個對合密鑰進行加密和解密操作,那么他們的信息很容易被第三方竊取。這是因為他們涉及一個公共密鑰,這意味著第三方也可以用這個公共密鑰進行通信,從而獲得敏感信息。

②若仿射密碼定義在Z26上,其對合密鑰有多少個?

仿射密碼的加密函數為E(x) = (ax + b) mod 26,解密函數為D(x) = a^-1(x - b) mod 26,其中a和b為密鑰,a^-1為a的模26乘法逆元。

由于對合函數要求f(f(x))=x,即E(E(x))=x,則有(E(E(x))) mod 26 = x,即((a(ax + b) + b) mod 26) mod 26 = x。解方程得到a^2x + ab + b = x,整理得到(a^2 - 1)x = (1 - ab) mod 26。

因為a^2 - 1必須是26的乘法逆元,所以a^2 - 1的因子必須是26的因子,即a^2 - 1必須是2或13的倍數,即a^2與26互質。根據這個條件,可以求出滿足條件的a的取值,而對b沒有什么限制,最后計算出滿足條件的對合密鑰的數量,代碼計算結果如下:

若2×2的希爾密碼定義在Z26上,其對合密鑰有多少個?

希爾密碼的加密函數為E(x) = Kx mod 26,其中K為2×2的密鑰矩陣,解密函數為D(x) = K^-1x mod 26,其中K^-1為K的模26乘法逆元的矩陣。

對合函數要求f(f(x))=x,即E(E(x))=x,則有(E(E(x))) mod 26 = x,即((KKx) mod 26) mod 26 = x。解方程得到(KKx) mod 26 = x,即K*K是26n的單位矩陣[1,0;0,1]。根據這個條件,可以求出滿足條件的2×2的對合密鑰的數量。

以上是對合密鑰數量的計算過程及代碼運行結果。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/905165.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/905165.shtml
英文地址,請注明出處:http://en.pswp.cn/news/905165.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[C++] 一個線程打印奇數一個線程打印偶數

要求開辟兩個線程打印從0-100的數&#xff0c;一個線程打印奇數一個線程打印偶數&#xff0c;要求必須按照1,2,3,4,5,6…100這種按照順序打印 使用std::shared_mutex的版本 #ifndef PrintNumber2_H_ #define PrintNumber2_H_#include <shared_mutex>class PrintNumber2…

MySQL全量、增量備份與恢復

目錄 數據備份 一、數據備份類型 二、常見備份方法 擴展&#xff1a;GTID與XtraBackup ?一、GTID&#xff08;全局事務標識符&#xff09;? ?1. 定義與核心作用? ?2. GTID在備份恢復中的意義? ?3. GTID配置與啟用? ?二、XtraBackup的意義與核心價值? ?1. 定…

木馬查殺篇—Opcode提取

【前言】 介紹Opcode的提取方法&#xff0c;并探討多種機器學習算法在Webshell檢測中的應用&#xff0c;理解如何在實際項目中應用Opcode進行高效的Webshell檢測。 Ⅰ 基本概念 Opcode&#xff1a;計算機指令的一部分&#xff0c;也叫字節碼&#xff0c;一個php文件可以抽取出…

DeepSeek-R1-Distill-Qwen-1.5B代表什么含義?

DeepSeek?R1?Distill?Qwen?1.5B 完整釋義與合規須知 一句話先行 這是 DeepSeek?AI?把自家?R1?大模型?的知識&#xff0c;通過蒸餾壓縮進一套 Qwen?1.5B 架構 的輕量學生網絡&#xff0c;并以寬松開源許可證發布的模型權重。 1?|?名字逐段拆解 片段意義備注DeepSee…

Megatron系列——張量并行

本文整理自bilibili Zomi視頻 1、行切分和列切分 注意&#xff1a; &#xff08;1&#xff09;A按列切分時&#xff0c;X無需切分&#xff0c;split復制廣播到A1和A2對應設備即可。最后Y1和Y2需要拼接下&#xff0c;即All Gather &#xff08;2&#xff09;A按行切分時&#…

java agent技術

從JDK1.5之后引入了java angent技術 Java Agent 是一種強大的技術&#xff0c;它允許開發者在 JVM 啟動時或運行期間動態地修改類的字節碼&#xff0c;從而實現諸如性能監控、日志記錄、AOP&#xff08;面向切面編程&#xff09;等功能 java agent依賴于Instrumentation API&…

LLaMA Factory 深度調參

注意&#xff0c;本文涵蓋從基礎調參到前沿研究的完整知識體系&#xff0c;建議結合具體業務場景靈活應用。一篇“參考文獻”而非“可運行的代碼”。https://github.com/zysNLP/quickllm 初始指令&#xff1a; llamafactory-cli train \--stage sft \--do_train True \--mode…

Linux驅動:驅動編譯流程了解

要求 1、開發板中的linux的zImage必須是自己編譯的 2、內核源碼樹,其實就是一個經過了配置編譯之后的內核源碼。 3、nfs掛載的rootfs,主機ubuntu中必須搭建一個nfs服務器。 內核源碼樹 解壓 tar -jxvf x210kernel.tar.bz2 編譯 make x210ii_qt_defconfigmakeCan’t use ‘…

Redis集群模式、持久化、過期策略、淘汰策略、緩存穿透雪崩擊穿問題

Redis四種模式 單節點模式 架構??&#xff1a;單個Redis實例運行在單臺服務器。 ??優點??&#xff1a; ??簡單??&#xff1a;部署和配置容易&#xff0c;適合開發和測試。 ??低延遲??&#xff1a;無網絡通信開銷。 ??缺點??&#xff1a; ??單點故障??&…

1.2 函數

函數的本質是描述變量間的依賴關系&#xff1a;??一個變量&#xff08;自變量&#xff09;的變化會唯一確定另一個變量&#xff08;因變量&#xff09;的值??。 ??基本構成??&#xff1a;通過符號&#xff08;如YF(X)&#xff09;表達規則&#xff0c;X輸入 → F處理 …

2025數字孿生技術全景洞察:從工業革命到智慧城市的跨越式發展

引言 數字孿生技術&#xff0c;這一融合物理世界與虛擬鏡像的革新性工具&#xff0c;正以驚人的速度重塑產業格局。2025年&#xff0c;中國數字孿生市場規模預計達214億元&#xff0c;工業制造領域占比超40%&#xff0c;其技術深度與行業落地成果令人矚目。本文將結合最新數據與…

RabbitMQ 工作模式

RabbitMQ 一共有 7 中工作模式&#xff0c;可以先去官網上了解一下&#xff08;一下截圖均來自官網&#xff09;&#xff1a;RabbitMQ 官網 Simple P&#xff1a;生產者&#xff0c;要發送消息的程序&#xff1b;C&#xff1a;消費者&#xff0c;消息的接受者&#xff1b;hell…

VBA會被Python代替嗎

VBA不會完全被Python取代、但Python在自動化、數據分析與跨平臺開發等方面的優勢使其越來越受歡迎、兩者將長期并存且各具優勢。 Python以其易于學習的語法、強大的開源生態系統和跨平臺支持&#xff0c;逐漸成為自動化和數據分析領域的主流工具。然而&#xff0c;VBA依舊在Exc…

【開源工具】深度解析:基于PyQt6的Windows時間校時同步工具開發全攻略

&#x1f552; 【開源工具】深度解析&#xff1a;基于PyQt6的Windows時間校時同步工具開發全攻略 &#x1f308; 個人主頁&#xff1a;創客白澤 - CSDN博客 &#x1f525; 系列專欄&#xff1a;&#x1f40d;《Python開源項目實戰》 &#x1f4a1; 熱愛不止于代碼&#xff0c;熱…

大模型項目:普通藍牙音響接入DeepSeek,解鎖語音交互新玩法

本文附帶視頻講解 【代碼宇宙019】技術方案&#xff1a;藍牙音響接入DeepSeek&#xff0c;解鎖語音交互新玩法_嗶哩嗶哩_bilibili 目錄 效果演示 核心邏輯 技術實現 大模型對話&#xff08;技術&#xff1a; LangChain4j 接入 DeepSeek&#xff09; 語音識別&#xff08;…

qt命名空間演示

#ifndef CIR_H #define CIR_Hnamespace cir {double PI3.141592653;//獲取圓行周長double getLenthOfCircle(double radius){return 2*PI*radius;}//獲取圓形面積double getAreaOfCircle(double radius){return PI*radius*radius;}} #endif // CIR_H#include <iostream> …

使用 Java 反射動態加載和操作類

Java 的反射機制(Reflection)是 Java 語言的一大特色,它允許程序在運行時檢查、加載和操作類、方法、字段等元信息。通過 java.lang.Class 和 java.lang.reflect 包,開發者可以動態加載類、創建實例、調用方法,甚至在運行時構造新類。反射是 Java 靈活性的核心,廣泛應用于…

《 C++ 點滴漫談: 三十七 》左值?右值?完美轉發?C++ 引用的真相超乎你想象!

摘要 本文全面系統地講解了 C 中的引用機制&#xff0c;涵蓋左值引用、右值引用、引用折疊、完美轉發等核心概念&#xff0c;并深入探討其底層實現原理及工程實踐應用。通過詳細的示例與對比&#xff0c;讀者不僅能掌握引用的語法規則和使用技巧&#xff0c;還能理解引用在性能…

【AutoGen深度解析】下一代AI代理編程框架實戰指南

目錄 &#x1f31f; 前言&#x1f3d7;? 技術背景與價值&#x1f6a7; 當前技術痛點&#x1f6e0;? 解決方案概述&#x1f465; 目標讀者說明 &#x1f50d; 一、技術原理剖析&#x1f5bc;? 核心概念圖解&#x1f4a1; 核心作用講解?? 關鍵技術模塊說明&#x1f504; 技術…

Python-AI調用大模型 給出大模型人格案例

Python調用通義千問模擬原神雷電將軍口吻 最近在用AI編輯器寫AI對話 嘗試給AI對話增加人格 以下是使用阿里通義千問大模型模擬《原神》中雷電將軍(雷電影)口吻的代碼案例&#xff0c;包含典型的高傲威嚴、略帶古風的說話風格。 完整后端代碼示例 import dashscope from dash…