臨朐縣網(wǎng)站建設(shè)上海百度整站優(yōu)化服務(wù)
加密常用于通信中,如戰(zhàn)爭中電臺(tái)通訊有明碼和密碼,密碼需要不斷更換密碼本;另外,商用軟件也需要用到加密技術(shù),如根據(jù)電腦的mac地址設(shè)置權(quán)限,防止軟件被惡意傳播。
文章目錄
- 一、介紹
- 1. 單向散列/哈希算法
- 2. 對稱加密算法
- 3. 非對稱加密算法
- 二、加密算法實(shí)現(xiàn)
- 1. 造輪子
- AES算法
- SM4算法
- RSA算法
- MD5
- SHA-1
- sm3
- 2. openssl
- 3. crypto++
- AES算法:
- DES算法:
- RSA算法:
- SHA-256算法:
- 4. botan
- 5. cryptlib
- 三、性能與方案選擇
一、介紹
信息加密技術(shù)是利用數(shù)學(xué)或物理手段,對電子信息在傳輸過程中和存儲(chǔ)介質(zhì)內(nèi)進(jìn)行保護(hù),以防止泄露的技術(shù)。通信加密技術(shù)是信息加密技術(shù)的重要分支,是網(wǎng)絡(luò)安全的重要組成部分。
加密就是通過密碼算法對數(shù)據(jù)進(jìn)行轉(zhuǎn)化,使之成為沒有正確密鑰任何人都無法讀懂的報(bào)文。而這些以無法讀懂的形式出現(xiàn)的數(shù)據(jù)一般被稱為密文。為了讀懂報(bào)文,密文必須重新轉(zhuǎn)變?yōu)樗淖畛跣问健魑?#xff0c;而含有以數(shù)學(xué)方式轉(zhuǎn)換報(bào)文的雙重密碼就是密鑰。
通信加密技術(shù)早期采用單向散列(hash)算法,即明文加密成密文后,不能再解密成明文。這種算法一般用來存儲(chǔ)密碼等信息,驗(yàn)證密碼時(shí),需要將密碼轉(zhuǎn)成的密文與數(shù)據(jù)庫中密文進(jìn)行對比。知名的單向散列算法有MD5、CRC32和SHA-256。
但如果我們只想在傳輸過程加密,收到數(shù)據(jù)后還想將其轉(zhuǎn)換成明文怎么辦呢?
為了解決上述問題,對稱加密算法出現(xiàn)了。明文通過對稱加密算法的密鑰加密成密文,密文又可以通過對稱加密算法的密鑰解密成明文,由于加密和解密過程使用同一把密鑰,所以稱為對稱加密。服務(wù)端和客戶端之間的加密就常用到對稱加密算法。知名的對稱加密算法有DES和AES。
但是這個(gè)密鑰放在哪里呢?如果定義一個(gè)變量,客戶端和服務(wù)端各放一份,我們在發(fā)送前肯定要對明文加密,別人很容易通過OD調(diào)試器追蹤到密鑰;如果只放在服務(wù)端,第一次通信時(shí)發(fā)過去,那別人也可以通過對客戶端抓包找到密鑰;還有就是把密鑰也加密發(fā)過去,那密鑰的密鑰總是明文吧,那就成了套娃。
為了解決以上問題,非對稱加密算法出現(xiàn)了。非對稱加密算法很神奇,它采用了一對密鑰,即公鑰和私鑰。對一串明文,如果你用公鑰加密,就只能用私鑰解密,而用私鑰加密,就只能用公鑰解密。但非對稱加密過程很復(fù)雜,所以處理很慢,比對稱加密慢幾百倍,用于網(wǎng)絡(luò)傳輸不現(xiàn)實(shí)。知名的非對稱加密算法有RSA和ECC。
對稱加密不能確保安全,非對稱加密不能保證效率,那怎么辦呢?
為了解決這個(gè)問題,混合加密策略出現(xiàn)了,即用非對稱加密來解決對稱加密的密鑰傳輸,密鑰傳輸完成后,A和B間采用對稱加密算法通信。對稱加密算法的密鑰由服務(wù)端A生成,A把對稱加密算法的密鑰用B的公鑰加密,B收到后用自己的私鑰解密,即“公鑰加密,私鑰解密”,得到對稱加密算法的密鑰,AB都有對稱加密的密鑰了,雙方就可以正常進(jìn)行對稱加密通信了?;旌霞用懿呗越鉀Q了竊聽的問題,此外,為了防止被逆向跟蹤,最好再搭配反調(diào)試+異步回調(diào)+多線程+時(shí)鐘擾亂,增大逆向難度。
除了竊聽,常見的安全問題還有篡改和冒充。
要解決這個(gè)問題,就來到了下面的數(shù)字簽名技術(shù)。數(shù)字簽名技術(shù)使用了hash算法和非對稱加密算法。利用私鑰加密,公鑰如果能成功解密得到摘要,可以證明發(fā)送方的身份,防止冒充;對消息內(nèi)容進(jìn)行hash,得到摘要,經(jīng)過摘要對比,可以檢測是否被篡改。
服務(wù)端A向客戶端B發(fā)送數(shù)據(jù):先對明文使用hash算法,生成摘要(digest),對這個(gè)摘要用A的私鑰(唯一性,防止冒充)加密,生成數(shù)字簽名(signature),將“明文+數(shù)字簽名”發(fā)送給B。
客戶端B接收數(shù)據(jù):對數(shù)字簽名用A的公鑰解密,得到摘要1;再對明文用hash算法,得到摘要2;對比摘要1和摘要2,若兩者一致,說明數(shù)據(jù)確實(shí)是A發(fā)過來的。
問題都解決了嗎?還沒有。非對稱加密時(shí)要先將A和B的公鑰發(fā)送給對方,在這個(gè)公鑰分發(fā)的過程中,可能會(huì)出現(xiàn)“中間人劫持”現(xiàn)象,即中間人C截獲A和B的公鑰,并將自己偽裝成B和A分別和A和B通信,這樣中間人C獲得了完整的數(shù)據(jù)。
那么如何安全地分發(fā)公鑰呢?即證明A的公鑰確實(shí)是A的,B的公鑰確實(shí)是B的呢?
現(xiàn)實(shí)世界中有公證處,而網(wǎng)絡(luò)世界中也有這樣一種具有公信力的組織,叫CA,它可以給服務(wù)端A頒發(fā)一個(gè)數(shù)字證書,上面有A的信息,包含A的公鑰,這樣如果拿到了證書,也就拿到了可信任的A的公鑰。
那么,證書要怎么安全傳輸呢? 如果證書被篡改了怎么辦?
現(xiàn)在的情況是,需要一種既要能判斷公鑰是否冒充,還要能判斷數(shù)據(jù)是否被篡改的手段, 這不就是剛剛介紹的數(shù)字簽名技術(shù)。具體操作其實(shí)就是把數(shù)字簽名中的"明文"部分替換為 “數(shù)字證書”??蛻舳薆向服務(wù)端A發(fā)送請求時(shí),服務(wù)端A會(huì)返回自己數(shù)字證書給客戶端B。CA公鑰是內(nèi)置在客戶電腦中的。
以上就是對通信加密技術(shù)的簡單介紹。
為了信息安全,我國也開發(fā)了國產(chǎn)密碼算法,簡稱國密算法,是由國家密碼局認(rèn)定的擁有自主知識產(chǎn)權(quán)的密碼算法,在目前應(yīng)用廣泛的有SM2、SM3、SM4。
目前為止,共計(jì)有近200多種加密算法,按國際慣例,將這近200種算法按照雙方收發(fā)的密鑰是否相同的標(biāo)準(zhǔn)劃分為兩大類:一種是常規(guī)算法(也叫私鑰加密算法或?qū)ΨQ加密算法),其特征是收信方和發(fā)信方使用相同的密鑰,即加密密鑰和解密密鑰是相同或等價(jià)的。常規(guī)密碼的優(yōu)點(diǎn)是有很強(qiáng)的保密強(qiáng)度,且經(jīng)受住時(shí)間的檢驗(yàn)和攻擊,但其密鑰必須通過安全的途徑傳送。因此,其密鑰管理成為系統(tǒng)安全的重要因素。知名的私鑰加密算法有:DES、3DES和AES。
另一種是公鑰加密算法(也叫非對稱加密算法),其特征是收信方和發(fā)信方使用的密鑰互不相同,而且?guī)缀醪豢赡軓募用苊荑€推導(dǎo)解密密鑰。比較著名的公鑰密碼算法有:RSA、DSA和ECC等。公鑰密碼的優(yōu)點(diǎn)是可以適應(yīng)網(wǎng)絡(luò)的開放性要求,且密鑰管理問題也較為簡單,尤其可方便的實(shí)現(xiàn)數(shù)字簽名和驗(yàn)證。但其算法復(fù)雜,加密數(shù)據(jù)的速率較低。
縱觀這兩種算法,一個(gè)從DES到3DES再到ADES,一個(gè)從RSA到ECC。其發(fā)展角度無不是從密鑰的簡單性,成本的低廉性,管理的簡易性,算法的復(fù)雜性,保密的安全性以及計(jì)算的快速性這幾個(gè)方面去考慮。因此,未來算法的發(fā)展也必定是從這幾個(gè)角度出發(fā)的,而且在實(shí)際操作中往往把這兩種算法結(jié)合起來,或許將來一種集兩種算法有點(diǎn)于一身的新型算法將會(huì)出現(xiàn),到那時(shí),數(shù)據(jù)通信必將更加快捷與安全。
1. 單向散列/哈希算法
單向散列函數(shù)(也稱Hash函數(shù))指的是根據(jù)輸入消息計(jì)算后,輸出固定長度數(shù)值的算法,輸出數(shù)值也稱為“散列值”或“消息摘要”,其長度通常在128~256位之間。
常用的單向散列算法有MD5、SHA-x系列、CRC系列等。
MD5算法是指輸入任意長度的信息,經(jīng)過處理,輸出為128位的信息(數(shù)字指紋);不同的輸入得到不同的結(jié)果(唯一性);根據(jù)128位的輸出結(jié)果不可能反推出輸入的信息(不可逆)。對安全性要求不高的軟件常用MD5算法。
CRC也叫循環(huán)冗余校驗(yàn)碼,是數(shù)據(jù)通信領(lǐng)域常用的一種查錯(cuò)校驗(yàn)碼,其特征是信息字段和校驗(yàn)字段的長度可以任意選定。循環(huán)冗余檢查(CRC)是一種數(shù)據(jù)傳輸檢錯(cuò)功能,對數(shù)據(jù)進(jìn)行多項(xiàng)式計(jì)算。我們都知道,反碼求和法用的是加法,而CRC算法用的是“除法”,這里不是十進(jìn)制除法,而是二進(jìn)制的異或取余。CRC8最終的余數(shù)是8位,如果不滿8位需要在高位補(bǔ)0,CRC32最終的余數(shù)則是32位。車輛通信報(bào)文校驗(yàn)常用CRC算法。
SHA算法是在MD4算法的基礎(chǔ)上演變而來,由美國國家安全局設(shè)計(jì),有SHA-1和SHA-2兩個(gè)系列。安全性要求一般時(shí)采用SHA-1,安全性要求較高時(shí)則至少采用SHA-256算法,SHA-256是指任意長度的消息文件,通過SHA-256算法加密,最終得到的密文都是256位(32字節(jié)),通常用一個(gè)長度為64的十六進(jìn)制字符串來表示。https簽名算法使用的是帶RSA加密的SHA-256算法。
SM3算法:哈希算法,適用于商用密碼應(yīng)用中的數(shù)字簽名和驗(yàn)證消息認(rèn)證碼的生成與驗(yàn)證以及隨機(jī)數(shù)的生成,可滿足多種密碼應(yīng)用的安全需求。用于替換MD5、SHA-1等國際算法。為了保證雜湊算法的安全性,其產(chǎn)生的雜湊值的長度不應(yīng)太短,例如MD5輸出128比特雜湊值,輸出長度太短,影響其安全性。SHA-1算法的輸出長度為160比特,SM3算法的輸出長度為256比特,因此SM3算法的安全性要高于MD5算法和SHA-1算法。
2. 對稱加密算法
對稱加密算法是應(yīng)用較早的加密算法。在對稱加密算法中,數(shù)據(jù)發(fā)信方將明文和加密密鑰一起經(jīng)過特殊加密算法處理后,使其變成復(fù)雜的加密密文發(fā)送出去。收信方收到密文后,若想解讀原文,則需要使用加密用過的密鑰及相同算法的逆算法對密文進(jìn)行解密,才能使其恢復(fù)成可讀明文。在對稱加密算法中,使用的密鑰只有一個(gè),發(fā)收信雙方都使用這個(gè)密鑰對數(shù)據(jù)進(jìn)行加密和解密,這就要求解密方事先必須知道加密密鑰。
DES是IBM公司1977年為美國政府研制的一種算法。DES是以56位密鑰為基礎(chǔ)的密碼塊加密技術(shù)。它的加密過程一般如下:
- 一次性把64位明文塊打亂置換;
- 把64位明文塊拆成兩個(gè)32位塊;
- 用機(jī)密DES密鑰把每個(gè)32位塊打亂位置16次;
- 使用初始置換的逆置換。
但后來,DES被容易地破解,因此,美國推出DES的改進(jìn)版本——三重加密(triple Data Encryption Standard,3DES)即在使用過程中,收發(fā)雙方都用三把密鑰進(jìn)行加解密,無疑這種3*56式的加密算法大大提升了密碼的安全性,按現(xiàn)在計(jì)算機(jī)的運(yùn)算速度,這種破解幾乎是不可能的。但是我們在為數(shù)據(jù)提供強(qiáng)有力的安全保護(hù)的同時(shí),也要花更多的時(shí)間來對信息進(jìn)行三次加密和對每個(gè)密層進(jìn)行解密。同時(shí)在這種前提下,使用這種密鑰的雙發(fā)都必須擁有3個(gè)密鑰,如果丟失了其中任何一把,其余兩把都成了無用的密鑰。這樣私鑰的數(shù)量一下又提升了3倍,這顯然不是我們想看到的。
于是美國國家標(biāo)準(zhǔn)與技術(shù)研究所推出了一個(gè)新的保密措施來保護(hù)金融交易。高級加密標(biāo)準(zhǔn)(Advanced Encryption Standard,AES)美國國家技術(shù)標(biāo)準(zhǔn)委員會(huì)(NIST)在2000年10月選定了比利時(shí)的研究成果“Rijndael”作為AES的基礎(chǔ)。AES內(nèi)部有更簡潔精確的數(shù)學(xué)算法,而加密數(shù)據(jù)只需一次通過。AES被設(shè)計(jì)成高速,堅(jiān)固的安全性能,而且能夠支持各種小型設(shè)備。AES與3DES相比,不僅是安全性能有重大差別,使用性能和資源有效利用上也有很大差別。
SM4算法:對稱加密算法。主要用于無線局域網(wǎng)標(biāo)準(zhǔn),用于替換DES/AES等算法。要保證一個(gè)對稱密碼算法的安全性的基本條件是其具備足夠的密鑰長度,SM4算法與AES算法具有相同的密鑰長度分組長度128比特,因此在安全性上高于3DES算法。
3. 非對稱加密算法
非對稱加密算法是一種密鑰的保密方法。非對稱加密算法需要兩個(gè)密鑰:公開密鑰 (publickey:簡稱公鑰)和私有密鑰(privatekey:簡稱私鑰)。公鑰與私鑰是一對,如果用公鑰對數(shù)據(jù)進(jìn)行加密,只有用對應(yīng)的私鑰才能解密。因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同的密鑰,所以這種算法稱為非對稱加密算法。
面對在執(zhí)行過程中如何使用和分享密鑰及保持其機(jī)密性等問題,1975年Whitefield Diffe和Marti Hellman提出了公開的密鑰密碼技術(shù)的概念,被稱為Diffie-Hellman技術(shù)。從此公鑰加密算法便產(chǎn)生了。
由于采取了公共密鑰,密鑰的管理和分發(fā)就變得簡單多了,對于一個(gè)n個(gè)用戶的網(wǎng)絡(luò)來說,只需要2n個(gè)密鑰便可達(dá)到密度。同時(shí)使得公鑰加密法的保密性全部集中在及其復(fù)雜的數(shù)學(xué)問題上,它的安全性因而也得到了保證。但是在實(shí)際運(yùn)用中,公共密鑰加密算法并沒有完全的取代私鑰加密算法。其重要的原因是它的實(shí)現(xiàn)速度遠(yuǎn)遠(yuǎn)趕不上私鑰加密算法。又因?yàn)樗陌踩?#xff0c;所以常常用來加密一些重要的文件。
根據(jù)所基于的數(shù)學(xué)難題來分類,有以下三類系統(tǒng)目前被認(rèn)為是安全和有效的:大整數(shù)因子分解系統(tǒng)(代表性的有RSA)、橢圓曲線離散對數(shù)系統(tǒng)(ECC)和離散對數(shù)系統(tǒng)(代表性的有DSA)。
RSA系統(tǒng)是公鑰系統(tǒng)的最具有典型意義的算法,大多數(shù)使用公鑰密碼進(jìn)行加密和數(shù)字簽名的產(chǎn)品和標(biāo)準(zhǔn)使用的都是RSA算法。它的具體算法如下:
- 找兩個(gè)非常大的質(zhì)數(shù),越大越安全。把這兩個(gè)質(zhì)數(shù)叫做P和Q;
- 找一個(gè)能滿足下列條件得數(shù)字E:A.是一個(gè)奇數(shù);B.小于P×Q;C.與(P-1)×(Q-1)互質(zhì),只是指E和該方程的計(jì)算結(jié)果沒有相同的質(zhì)數(shù)因子;
- 計(jì)算出數(shù)值D,滿足下面性質(zhì):((D×E)-1)能被(P-1)×(Q-1)整除。
公開密鑰對是(P×Q,E);私人密鑰是D;公開密鑰是E。
解密函數(shù)是:
假設(shè)T是明文,C是密文。
加密函數(shù)用公開密鑰E和模P×Q;
加密信息=(TE)模P×Q。
解密函數(shù)用私人密鑰D和模P×Q;
解密信息=(CD)模P×Q。
橢圓曲線加密技術(shù)(ECC)是建立在單向函數(shù)(橢圓曲線離散對數(shù))的基礎(chǔ)上,由于它比RAS使用得離散對數(shù)要復(fù)雜得多,而且該單向函數(shù)比RSA得要難,所以與RSA相比,它有安全性高、計(jì)算量小、存儲(chǔ)空間占用小、占用帶寬低等優(yōu)點(diǎn)。
在實(shí)現(xiàn)非對稱加密RSA算法前,服務(wù)端A和客戶端B都要先用openssl(開源密碼庫)生成自己的公鑰和私鑰。命令如下:
genrsa -out private_key.pem 2048 # 制作私鑰
rsa -in private_key.pem -pubout -out public_key.pem # 制作公鑰
注意,公鑰是公開的,因此程序開始A和B會(huì)傳輸各自的公鑰給對方。
通過RSA算法傳輸數(shù)據(jù)的流程如下:
A發(fā)送數(shù)據(jù)給B:A先把明文用B的公鑰進(jìn)行加密,這樣除了B的私鑰,其他都解不了密,B收到后,用自己的私鑰解密,得到明文。
B發(fā)送數(shù)據(jù)給A:B把明文用A的公鑰進(jìn)行加密,A收到后,用自己的私鑰解密得到明文。
規(guī)則就是:你要發(fā)給誰,就用誰的公鑰加密,這樣他收到后,只有他自己的私鑰能解密。
遠(yuǎn)程ssh連接git賬戶時(shí),生成密鑰的算法就是RSA算法。
SM2算法:非對稱加密算法。基于橢圓曲線密碼(ECC)的公鑰密碼算法標(biāo)準(zhǔn),提供數(shù)字簽名、密鑰交換和公鑰加密。用于替換RSA等國際算法。SM2算法與RSA算法不同的是,SM2算法是基于橢圓曲線上點(diǎn)群離散對數(shù)難題,相對于RSA算法,256位的SM2密碼強(qiáng)度已經(jīng)比2048位的RSA密碼強(qiáng)度要高。
二、加密算法實(shí)現(xiàn)
1. 造輪子
自己編寫相關(guān)加密算法。
AES算法
一個(gè)基于C++的AES實(shí)現(xiàn):https://github.com/Urban82/Aes256
aes.h
#ifndef AES_H
#define AES_H/*** 參數(shù) p: 明文的字符串?dāng)?shù)組。* 參數(shù) plen: 明文的長度,長度必須為16的倍數(shù)。* 參數(shù) key: 密鑰的字符串?dāng)?shù)組。*/
void aes(char *p, int plen, char *key);/*** 參數(shù) c: 密文的字符串?dāng)?shù)組。* 參數(shù) clen: 密文的長度,長度必須為16的倍數(shù)。* 參數(shù) key: 密鑰的字符串?dāng)?shù)組。*/
void deAes(char *c, int clen, char *key);#endif
aes.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aes.h"void aes(char *p, int plen, char *key);
void deAes(char *c, int clen, char *key);
/*** S盒*/
static const int S[16][16] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };/*** 逆S盒*/
static const int S2[16][16] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };/*** 獲取int數(shù)據(jù)的低8位的左4個(gè)位*/
static int getLeft4Bit(int num) {int left = num & 0x000000f0;return left >> 4;
}/*** 獲取int數(shù)據(jù)的低8位的右4個(gè)位*/
static int getRight4Bit(int num) {return num & 0x0000000f;
}
/*** 根據(jù)索引,從S盒中獲得元素*/
static int getNumFromSBox(int index) {int row = getLeft4Bit(index);int col = getRight4Bit(index);return S[row][col];
}/*** 把一個(gè)字符轉(zhuǎn)變成整型*/
static int getIntFromChar(char c) {int result = (int) c;return result & 0x000000ff;
}/*** 把16個(gè)字符轉(zhuǎn)變成4X4的數(shù)組,* 該矩陣中字節(jié)的排列順序?yàn)閺纳系较?#xff0c;* 從左到右依次排列。*/
static void convertToIntArray(char *str, int pa[4][4]) {int k = 0;for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++) {pa[j][i] = getIntFromChar(str[k]);k++;}
}/*** 打印4X4的數(shù)組*/
static void printArray(int a[4][4]) {for(int i = 0; i < 4; i++){for(int j = 0; j < 4; j++)printf("a[%d][%d] = 0x%x ", i, j, a[i][j]);printf("\n");}printf("\n");
}/*** 打印字符串的ASSCI,* 以十六進(jìn)制顯示。*/
static void printASSCI(char *str, int len) {for(int i = 0; i < len; i++)printf("0x%x ", getIntFromChar(str[i]));printf("\n");
}/*** 把連續(xù)的4個(gè)字符合并成一個(gè)4字節(jié)的整型*/
static int getWordFromStr(char *str) {int one = getIntFromChar(str[0]);one = one << 24;int two = getIntFromChar(str[1]);two = two << 16;int three = getIntFromChar(str[2]);three = three << 8;int four = getIntFromChar(str[3]);return one | two | three | four;
}/*** 把一個(gè)4字節(jié)的數(shù)的第一、二、三、四個(gè)字節(jié)取出,* 入進(jìn)一個(gè)4個(gè)元素的整型數(shù)組里面。*/
static void splitIntToArray(int num, int array[4]) {int one = num >> 24;array[0] = one & 0x000000ff;int two = num >> 16;array[1] = two & 0x000000ff;int three = num >> 8;array[2] = three & 0x000000ff;array[3] = num & 0x000000ff;
}/*** 將數(shù)組中的元素循環(huán)左移step位*/
static void leftLoop4int(int array[4], int step) {int temp[4];for(int i = 0; i < 4; i++)temp[i] = array[i];int index = step % 4 == 0 ? 0 : step % 4;for(int i = 0; i < 4; i++){array[i] = temp[index];index++;index = index % 4;}
}/*** 把數(shù)組中的第一、二、三和四元素分別作為* 4字節(jié)整型的第一、二、三和四字節(jié),合并成一個(gè)4字節(jié)整型*/
static int mergeArrayToInt(int array[4]) {int one = array[0] << 24;int two = array[1] << 16;int three = array[2] << 8;int four = array[3];return one | two | three | four;
}/*** 常量輪值表*/
static const unsigned int Rcon[10] = { 0x01000000, 0x02000000,0x04000000, 0x08000000,0x10000000, 0x20000000,0x40000000, 0x80000000,0x1b000000, 0x36000000 };
/*** 密鑰擴(kuò)展中的T函數(shù)*/
static int T(int num, int round) {int numArray[4];splitIntToArray(num, numArray);leftLoop4int(numArray, 1);//字循環(huán)//字節(jié)代換for(int i = 0; i < 4; i++)numArray[i] = getNumFromSBox(numArray[i]);int result = mergeArrayToInt(numArray);return result ^ Rcon[round];
}//密鑰對應(yīng)的擴(kuò)展數(shù)組
static int w[44];/*** 擴(kuò)展密鑰,結(jié)果是把w[44]中的每個(gè)元素初始化*/
static void extendKey(char *key) {for(int i = 0; i < 4; i++)w[i] = getWordFromStr(key + i * 4);for(int i = 4, j = 0; i < 44; i++) {if( i % 4 == 0) {w[i] = w[i - 4] ^ T(w[i - 1], j);j++;//下一輪}else {w[i] = w[i - 4] ^ w[i - 1];}}}/*** 輪密鑰加*/
static void addRoundKey(int array[4][4], int round) {int warray[4];for(int i = 0; i < 4; i++) {splitIntToArray(w[ round * 4 + i], warray);for(int j = 0; j < 4; j++) {array[j][i] = array[j][i] ^ warray[j];}}
}/*** 字節(jié)代換*/
static void subBytes(int array[4][4]){for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)array[i][j] = getNumFromSBox(array[i][j]);
}/*** 行移位*/
static void shiftRows(int array[4][4]) {int rowTwo[4], rowThree[4], rowFour[4];//復(fù)制狀態(tài)矩陣的第2,3,4行for(int i = 0; i < 4; i++) {rowTwo[i] = array[1][i];rowThree[i] = array[2][i];rowFour[i] = array[3][i];}//循環(huán)左移相應(yīng)的位數(shù)leftLoop4int(rowTwo, 1);leftLoop4int(rowThree, 2);leftLoop4int(rowFour, 3);//把左移后的行復(fù)制回狀態(tài)矩陣中for(int i = 0; i < 4; i++) {array[1][i] = rowTwo[i];array[2][i] = rowThree[i];array[3][i] = rowFour[i];}
}/*** 列混合要用到的矩陣*/
static const int colM[4][4] = { 2, 3, 1, 1,1, 2, 3, 1,1, 1, 2, 3,3, 1, 1, 2 };static int GFMul2(int s) {int result = s << 1;int a7 = result & 0x00000100;if(a7 != 0) {result = result & 0x000000ff;result = result ^ 0x1b;}return result;
}static int GFMul3(int s) {return GFMul2(s) ^ s;
}static int GFMul4(int s) {return GFMul2(GFMul2(s));
}static int GFMul8(int s) {return GFMul2(GFMul4(s));
}static int GFMul9(int s) {return GFMul8(s) ^ s;
}static int GFMul11(int s) {return GFMul9(s) ^ GFMul2(s);
}static int GFMul12(int s) {return GFMul8(s) ^ GFMul4(s);
}static int GFMul13(int s) {return GFMul12(s) ^ s;
}static int GFMul14(int s) {return GFMul12(s) ^ GFMul2(s);
}/*** GF上的二元運(yùn)算*/
static int GFMul(int n, int s) {int result;if(n == 1)result = s;else if(n == 2)result = GFMul2(s);else if(n == 3)result = GFMul3(s);else if(n == 0x9)result = GFMul9(s);else if(n == 0xb)//11result = GFMul11(s);else if(n == 0xd)//13result = GFMul13(s);else if(n == 0xe)//14result = GFMul14(s);return result;
}
/*** 列混合*/
static void mixColumns(int array[4][4]) {int tempArray[4][4];for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)tempArray[i][j] = array[i][j];for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++){array[i][j] = GFMul(colM[i][0],tempArray[0][j]) ^ GFMul(colM[i][1],tempArray[1][j]) ^ GFMul(colM[i][2],tempArray[2][j]) ^ GFMul(colM[i][3], tempArray[3][j]);}
}
/*** 把4X4數(shù)組轉(zhuǎn)回字符串*/
static void convertArrayToStr(int array[4][4], char *str) {for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)*str++ = (char)array[j][i];
}
/*** 檢查密鑰長度*/
static int checkKeyLen(int len) {if(len == 4)return 1;elsereturn 0;
}/*** 參數(shù) p: 明文的字符串?dāng)?shù)組。* 參數(shù) plen: 明文的長度。* 參數(shù) key: 密鑰的字符串?dāng)?shù)組。*/
void aes(char *p, int plen, char *key){int keylen = strlen(key);if(plen == 0 || plen % 4 != 0) {printf("明文字符長度必須為4的倍數(shù)!\n");exit(0);}if(!checkKeyLen(keylen)) {printf("密鑰字符長度錯(cuò)誤!長度必須為16、24和32。當(dāng)前長度為%d\n",keylen);exit(0);}extendKey(key);//擴(kuò)展密鑰int pArray[4][4];for(int k = 0; k < plen; k += 16) { convertToIntArray(p + k, pArray);addRoundKey(pArray, 0);//一開始的輪密鑰加for(int i = 1; i < 10; i++){//前9輪subBytes(pArray);//字節(jié)代換shiftRows(pArray);//行移位mixColumns(pArray);//列混合addRoundKey(pArray, i);}//第10輪subBytes(pArray);//字節(jié)代換shiftRows(pArray);//行移位addRoundKey(pArray, 10);convertArrayToStr(pArray, p + k);}
}
/*** 根據(jù)索引從逆S盒中獲取值*/
static int getNumFromS1Box(int index) {int row = getLeft4Bit(index);int col = getRight4Bit(index);return S2[row][col];
}
/*** 逆字節(jié)變換*/
static void deSubBytes(int array[4][4]) {for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)array[i][j] = getNumFromS1Box(array[i][j]);
}
/*** 把4個(gè)元素的數(shù)組循環(huán)右移step位*/
static void rightLoop4int(int array[4], int step) {int temp[4];for(int i = 0; i < 4; i++)temp[i] = array[i];int index = step % 4 == 0 ? 0 : step % 4;index = 3 - index;for(int i = 3; i >= 0; i--) {array[i] = temp[index];index--;index = index == -1 ? 3 : index;}
}/*** 逆行移位*/
static void deShiftRows(int array[4][4]) {int rowTwo[4], rowThree[4], rowFour[4];for(int i = 0; i < 4; i++) {rowTwo[i] = array[1][i];rowThree[i] = array[2][i];rowFour[i] = array[3][i];}rightLoop4int(rowTwo, 1);rightLoop4int(rowThree, 2);rightLoop4int(rowFour, 3);for(int i = 0; i < 4; i++) {array[1][i] = rowTwo[i];array[2][i] = rowThree[i];array[3][i] = rowFour[i];}
}
/*** 逆列混合用到的矩陣*/
static const int deColM[4][4] = { 0xe, 0xb, 0xd, 0x9,0x9, 0xe, 0xb, 0xd,0xd, 0x9, 0xe, 0xb,0xb, 0xd, 0x9, 0xe };/*** 逆列混合*/
static void deMixColumns(int array[4][4]) {int tempArray[4][4];for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)tempArray[i][j] = array[i][j];for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++){array[i][j] = GFMul(deColM[i][0],tempArray[0][j]) ^ GFMul(deColM[i][1],tempArray[1][j]) ^ GFMul(deColM[i][2],tempArray[2][j]) ^ GFMul(deColM[i][3], tempArray[3][j]);}
}
/*** 把兩個(gè)4X4數(shù)組進(jìn)行異或*/
static void addRoundTowArray(int aArray[4][4],int bArray[4][4]) {for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)aArray[i][j] = aArray[i][j] ^ bArray[i][j];
}
/*** 從4個(gè)32位的密鑰字中獲得4X4數(shù)組,* 用于進(jìn)行逆列混合*/
static void getArrayFrom4W(int i, int array[4][4]) {int index = i * 4;int colOne[4], colTwo[4], colThree[4], colFour[4];splitIntToArray(w[index], colOne);splitIntToArray(w[index + 1], colTwo);splitIntToArray(w[index + 2], colThree);splitIntToArray(w[index + 3], colFour);for(int i = 0; i < 4; i++) {array[i][0] = colOne[i];array[i][1] = colTwo[i];array[i][2] = colThree[i];array[i][3] = colFour[i];}}/*** 參數(shù) c: 密文的字符串?dāng)?shù)組。* 參數(shù) clen: 密文的長度。* 參數(shù) key: 密鑰的字符串?dāng)?shù)組。*/
void deAes(char *c, int clen, char *key) {int keylen = strlen(key);if(clen == 0 || clen % 4 != 0) {printf("密文字符長度必須為4的倍數(shù)!現(xiàn)在的長度為%d\n",clen);exit(0);}if(!checkKeyLen(keylen)) {printf("密鑰字符長度錯(cuò)誤!長度必須為16、24和32。當(dāng)前長度為%d\n",keylen);exit(0);}extendKey(key);//擴(kuò)展密鑰int cArray[4][4];for(int k = 0; k < clen; k += 16) {convertToIntArray(c + k, cArray);addRoundKey(cArray, 10);int wArray[4][4];for(int i = 9; i >= 1; i--) {deSubBytes(cArray);deShiftRows(cArray);deMixColumns(cArray);getArrayFrom4W(i, wArray);deMixColumns(wArray);addRoundTowArray(cArray, wArray);}deSubBytes(cArray);deShiftRows(cArray);addRoundKey(cArray, 0);convertArrayToStr(cArray, c + k);}
}
參考main.cpp實(shí)現(xiàn):
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>#include "aes.h"#define MAXLEN 1024//獲取字符串
void getString(char *str, int len){int slen = read(0, str, len);for(int i = 0; i < slen; i++,str++){if(*str == '\n'){*str = '\0';break;}}
}//輸出ASCII
void printASCII(char *str, int len) {int c;for(int i = 0; i < len; i++) {c = (int)*str++;c = c & 0x000000ff;//保留低8位printf("0x%x ", c);}printf("\n");
}/*** 從標(biāo)準(zhǔn)輸入中讀取用戶輸入的字符串*/
void readPlainText(char *str, int *len) {int plen;while(1) {getString(str, MAXLEN);plen = strlen(str);if(plen != 0 && plen % 4 == 0) {printf("你輸入的明文為:%s\n", str);break;}else{printf("明文字符長度必須為4的倍數(shù),現(xiàn)在的長度為%d\n", plen);}}*len = plen;
}
/*** 把字符串寫進(jìn)文件*/
void writeStrToFile(char *str, int len, char *fileName) {FILE *fp;fp = fopen(fileName, "wb");for(int i = 0; i < len; i++)putc(str[i], fp);fclose(fp);
}//字符串寫進(jìn)文件
void aesStrToFile(char *key) {char p[MAXLEN];int plen;printf("請輸入你的明文,明文字符長度必須為4的倍數(shù)\n");readPlainText(p,&plen);printf("進(jìn)行AES加密..................\n");aes(p, plen, key);//AES加密printf("加密完后的明文的ASCII為:\n");printASCII(p, plen);char fileName[64];printf("請輸入你想要寫進(jìn)的文件名,比如'test.txt':\n");if(scanf("%s", fileName) == 1) { writeStrToFile(p, plen, fileName);printf("已經(jīng)將密文寫進(jìn)%s中了,可以在運(yùn)行該程序的當(dāng)前目錄中找到它。\n", fileName);}
}
/*** 從文件中讀取字符串*/
int readStrFromFile(char *fileName, char *str) {FILE *fp = fopen(fileName, "rb");if(fp == NULL) {printf("打開文件出錯(cuò),請確認(rèn)文件存在當(dāng)前目錄下!\n");exit(0);}int i;for(i = 0; i < MAXLEN && (str[i] = getc(fp)) != EOF; i++);if(i >= MAXLEN) {printf("解密文件過大!\n");exit(0);}str[i] = '\0';fclose(fp);return i;
}//解密文件
void deAesFile(char *key) {char fileName[64];char c[MAXLEN];//密文字符串printf("請輸入要解密的文件名,該文件必須和本程序在同一個(gè)目錄\n");if(scanf("%s", fileName) == 1) {int clen = readStrFromFile(fileName, c);printf("開始解密.........\n");deAes(c, clen, key);printf("解密后的明文ASCII為:\n");printASCII(c, clen);printf("明文為:%s\n", c);writeStrToFile(c,clen,fileName);printf("現(xiàn)在可以打開%s來查看解密后的密文了!\n",fileName);}
}//加密文件
void aesFile(char *key) {char fileName[64];char fileP[MAXLEN];printf("請輸入要加密的文件名,該文件必須和本程序在同一個(gè)目錄\n");if(scanf("%s", fileName) == 1) {readStrFromFile(fileName, fileP);int plen = strlen(fileP);printf("開始加密.........\n");printf("加密前文件中字符的ASCII為:\n");printASCII(fileP, plen);aes(fileP, plen, key);//開始加密printf("加密后的密文ASCII為:\n");printASCII(fileP, plen);writeStrToFile(fileP,plen,fileName);printf("已經(jīng)將加密后的密文寫進(jìn)%s中了\n",fileName);}
}int main(int argc, char const *argv[]) {clock_t start,finish;start = clock();char key[17];printf("請輸入4個(gè)字符的密鑰:\n");int klen;while(1){getString(key,17);klen = strlen(key);if(klen != 4){printf("請輸入4個(gè)字符的密鑰,當(dāng)前密鑰的長度為%d\n",klen);}else{printf("你輸入的密鑰為:%s\n",key);break;}}printf("輸入's'表示要加密輸入的字符串,并將加密后的內(nèi)容寫入到文件\n");printf("請輸入要功能選項(xiàng)并按回車,輸入'f'表示要加密文件\n");printf("輸入'p'表示要解密文件\n");char c;if(scanf("%s",&c) == 1) {if(c == 's')aesStrToFile(key);//用AES加密字符串,并將字符串寫進(jìn)文件中else if(c == 'p')deAesFile(key);//把文件中的密文解密,并寫回文件中else if(c == 'f')//用AES加密文件aesFile(key);}finish = clock();std::cout << std::endl<<"the time cost is:" << double(finish - start) / CLOCKS_PER_SEC << std::endl;return 0;
}
編譯:
Windows可在VS2017下不依賴其他庫實(shí)現(xiàn);
Linux編譯g++ -o aes -static aes.cpp main.cpp
SM4算法
一個(gè)SM的算法:https://github.com/tonyonce2017/SM4
#ifndef _SM4_H
#define _SM4_H
#include<stdio.h>
#include<time.h>
#include<iomanip>
#include<stdlib.h>typedef unsigned int word;// 密鑰擴(kuò)展
// param:
// mk[4]: 加密密鑰
// return: 輪密鑰
word* keyExpansion(word mk[4]);// 迭代
// param?
// x[4]: 加密結(jié)果
// mk[4]:密鑰 128 bits
// flag: true:加密 flase:解密
void encryption(word x[4], word mk[4], bool flag);// sm4加密,CBC模式
// param?
// result:加密結(jié)果
// arr :待加密數(shù)據(jù)
// bits :待加密數(shù)據(jù)的bit數(shù)
// mk[4] :密鑰,128 bits
// return: 加密結(jié)果result的bit數(shù)
unsigned int sm4_encryption(word*& result, word*& arr, unsigned int bits, word mk[4]);// sm4解密,CBC模式
// param?
// result: 解密結(jié)果
// arr : 待解密數(shù)據(jù)
// bits : 待解密數(shù)據(jù)的bit數(shù)
// mk[4] : 密鑰,128 bits
// return: 解密結(jié)果result的bit數(shù)
unsigned int sm4_decryption(word*& result, word*& arr, unsigned int bits, word mk[4]);const word S[] = {0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05, //00x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, //10x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62, //20xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6, //30x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8, //40x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35, //50x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87, //60xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E, //70xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1, //80xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3, //90x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F, //A0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51, //B0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8, //C0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0, //D0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84, //E0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48 //F
};#define ShiftLeft(x,k) (x>>(32-k)|(x<<k))
#define L(x) (x^ShiftLeft(x,2)^ShiftLeft(x,10)^ShiftLeft(x,18)^ShiftLeft(x,24))//????L
#define LL(x) (x^ShiftLeft(x,13)^ShiftLeft(x,23))//?????????
#define F(x) (T(x))
#define lamda(x) ((S[x >> 24 & 0xff] << 24) | (S[x >> 16 & 0xff] << 16) | (S[x >> 8 & 0xff] << 8) | S[x & 0xff])//?????//密鑰擴(kuò)展函數(shù)
word* keyExpansion(word mk[4]) {word* rk = new word[32];word Fk[4] = { 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc };word CK[32], k[4];for (int i = 0; i < 32; i++) {CK[i] = 0;for (int j = 0; j < 4; j++)CK[i] = CK[i] * 256 + ((4 * i + j) * 7) % 256;}for (int i = 0; i < 4; i++) {k[i] = mk[i] ^ Fk[i];}word temp;for (int i = 0; i < 32; i++) {temp = k[1] ^ k[2] ^ k[3] ^ CK[i];temp = lamda(temp);temp = k[0] ^ LL(temp);k[0] = k[1]; k[1] = k[2]; k[2] = k[3]; k[3] = temp;rk[i] = temp;}return rk;
}//迭代
void encryption(word x[4], word mk[4], bool flag) {word temp;word* rk = keyExpansion(mk);for (int i = 0; i < 32; i++) {temp = x[1] ^ x[2] ^ x[3];if (flag == false) temp ^= rk[31 - i];else temp ^= rk[i];temp = lamda(temp);temp = L(temp) ^ x[0];x[0] = x[1]; x[1] = x[2]; x[2] = x[3]; x[3] = temp;}temp = x[0]; x[0] = x[3]; x[3] = temp;temp = x[1]; x[1] = x[2]; x[2] = temp;delete[] rk;
}//sm4加密函數(shù),CBC模式
unsigned int sm4_encryption(word*& result, word*& arr, unsigned int bits, word mk[4]) {//return bitsword* temp;unsigned int temp_size;unsigned int s = 128 - bits % 128;//s:填充的比特?cái)?shù)if (s == 0)s = 128;else if (s == 1)s += 128;temp_size = 4 + ((bits + s) >> 5);temp = new unsigned int[temp_size];int i;for (i = 4; i < 4 + ((bits + 31) >> 5); i++)temp[i] = arr[i - 4];for (; i < temp_size; i++)temp[i] = 0;temp[i - 1] |= s;//用零填充,最后8比特用s填充srand((int)time(0));for (i = 0; i < 4; i++)temp[i] = rand();//前128比特為初始向量result = new unsigned int[temp_size];for (i = 0; i < 4; i++)result[i] = temp[i];for (i = 4; i < temp_size; i += 4) {result[i] = temp[i] ^ result[i - 4];result[i + 1] = temp[i + 1] ^ result[i - 3];result[i + 2] = temp[i + 2] ^ result[i - 2];result[i + 3] = temp[i + 3] ^ result[i - 1];encryption(&result[i], mk, true);}return temp_size * 32;
}//sm4解密,CBC模式
unsigned int sm4_decryption(word*& result, word*& arr, unsigned int bits, word mk[4]) {unsigned int size = bits / 32 - 4;result = new unsigned int[size];unsigned int i;for (i = 0; i < size; i += 4) {result[i] = arr[i + 4];result[i + 1] = arr[i + 5];result[i + 2] = arr[i + 6];result[i + 3] = arr[i + 7];encryption(&result[i], mk, false);result[i] ^= arr[i];result[i + 1] ^= arr[i + 1];result[i + 2] ^= arr[i + 2];result[i + 3] ^= arr[i + 3];}i = result[size - 1] & 0xff;return size * 32 - i;
}#endif
RSA算法
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include<string.h>
#include <math.h>
#include<algorithm>
#include <time.h>using namespace std;
typedef long long ll;// e是公鑰
// d是私鑰ll e, d, n;ll gcd(ll a, ll b) //求最大公約數(shù)
{ll c = 0;if(a<b) swap(a,b);c = b;do{b = c;c = a%b;a = b;}while (c != 0);return b;
}// 0不是 1是
ll isPrime(ll i) //判斷i是否是素?cái)?shù)
{ll flag=0;for(ll a=2; a<i; a++){if(i%a==0){flag=1;break;}}if(flag==1) return 0;else return 1;}ll myPow(ll a, ll b, ll n) //求a^b mod n
{ll y;/*使用二進(jìn)制平方乘法計(jì)算 pow(a,b) % n*/y=1;while(b != 0){/*對于b中的每個(gè)1,累加y*/if(b & 1)y = (y*a) % n;/*對于b中的每一位,計(jì)算a的平方*/a = (a*a) % n;/*準(zhǔn)備b中的下一位*/b = b>>1;}return y;
}void extgcd(ll a,ll b,ll& d,ll& x,ll& y)
{if(!b){d=a;x=1;y=0;}else{extgcd(b,a%b,d,y,x);y-=x*(a/b);}
}ll ModularInverse(ll a,ll b) //獲取(1/a)mod b的結(jié)果
{ll d,x,y;extgcd(a,b,d,x,y);return d==1?(x+b)%b:-1;}void KeyGeneration() //獲取公鑰密鑰
{ll p, q;ll phi_n;do{dop = rand();while (p % 2 == 0);}while (!isPrime(p)); // 得到素?cái)?shù) p do{doq = rand();while (q % 2 == 0);}while (!isPrime(q)); // 得到素?cái)?shù)q n = p * q;phi_n = (p - 1) * (q - 1);doe = rand() % (phi_n - 2) + 2; // 1 < e < phi_nwhile (gcd(e, phi_n) != 1);d = ModularInverse(e,phi_n);
}// 一位一位地輸出加密的結(jié)果
ll Encryption(ll value) //加密
{ll cipher;cipher = myPow(value, e, n);cout<<cipher;return cipher;
}// 一位一位地輸出解 密的結(jié)果
void Decryption(ll value) //解密
{ll decipher;decipher = myPow(value, d, n);cout<<decipher;
}
int main()
{clock_t start,finish;start = clock();// 對6位的數(shù)字進(jìn)行穩(wěn)定加密 ll num;cout<<"請輸入要加密的明文數(shù)字,enter結(jié)束"<<endl;//while(cin>>num){cin >> num;ll de;cout<<"輸入的明文為"<<num<<endl; KeyGeneration(); //獲取公鑰密鑰cout<<"加密密鑰:"<<e<<endl; cout<<"加密結(jié)果為:";de = Encryption( num );cout<<"\n私鑰為:"<<d;
// cout<<"de="<<de<<endl;cout<<"\n解密結(jié)果"; Decryption(de); cout<<"\n-------------"<<endl;//}finish = clock();cout <<endl<<"the time cost is:" << double(finish - start) / CLOCKS_PER_SEC<<endl;return 0;
}
MD5
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <time.h>using namespace std;#define A 0x67452301
#define B 0xefcdab89
#define C 0x98badcfe
#define D 0x10325476const char str16[] = "0123456789abcdef";const unsigned int T[] = {0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391 };//行*列16*4const unsigned int s[] = { 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21};//行*列4*16class MD5 {
private:unsigned int tempA, tempB, tempC, tempD, strlength;
public:MD5() {tempA = A;tempB = B;tempC = C;tempD = D;strlength = 0;}// F函數(shù)unsigned int F(unsigned int b, unsigned int c, unsigned int d) {return (b & c) | ((~b) & d);}// G函數(shù)unsigned int G(unsigned int b, unsigned int c, unsigned int d) {return (b & d) | (c & (~d));}// H函數(shù)unsigned int H(unsigned int b, unsigned int c, unsigned int d) {return b ^ c ^ d;}// I函數(shù)unsigned int I(unsigned int b, unsigned int c, unsigned int d) {return c ^ (b | (~d));}// 移位操作函數(shù)unsigned int shift(unsigned int a, unsigned int n) {return (a << n) | (a >> (32 - n));}// 編碼函數(shù)(重要)string encode(string src) {vector<unsigned int> rec = padding(src);//填充字符串for(unsigned int i = 0; i < strlength/16; i++) {unsigned int num[16];for(int j = 0; j < 16; j++) {num[j] = rec[i*16+j];}iterateFunc(num, 16);//循環(huán)壓縮}return format(tempA) + format(tempB) + format(tempC) + format(tempD);//整理輸出}// 循環(huán)壓縮void iterateFunc(unsigned int* X, int size = 16) {unsigned int a = tempA,b = tempB,c = tempC,d = tempD,rec = 0,g, k;for(int i = 0; i < 64; i++) {if(i < 16) {// F迭代g = F(b, c, d);k = i;}else if(i < 32) {// G迭代g = G(b, c, d);k = (1 + 5*i) % 16;}else if(i < 48) {// H迭代g = H(b, c, d);k = (5 + 3*i) % 16;}else {// I迭代g = I(b, c, d);k = (7*i) % 16;}rec = d;d = c;c = b;b = b + shift(a + g + X[k] + T[i], s[i]);a = rec;}tempA += a;tempB += b;tempC += c;tempD += d;}// 填充字符串vector<unsigned int> padding(string src) {// 以512位,64個(gè)字節(jié)為一組unsigned int num = ((src.length() + 8) / 64) + 1;vector<unsigned int> rec(num*16);strlength = num*16;for(unsigned int i = 0; i < src.length(); i++){// 一個(gè)unsigned int對應(yīng)4個(gè)字節(jié),保存4個(gè)字符信息rec[i>>2] |= (int)(src[i]) << ((i % 4) * 8);}// 補(bǔ)充1000...000rec[src.length() >> 2] |= (0x80 << ((src.length() % 4)*8));// 填充原文長度rec[rec.size()-2] = (src.length() << 3);return rec;}// 整理輸出string format(unsigned int num) {string res = "";unsigned int base = 1 << 8;for(int i = 0; i < 4; i++) {string tmp = "";unsigned int b = (num >> (i * 8)) % base & 0xff;for(int j = 0; j < 2; j++) {tmp = str16[b%16] + tmp;b /= 16;}res += tmp;}return res;}
};int main() {clock_t start,finish;start = clock();MD5 test;string a = "";cout << "請輸入密碼: ";getline(cin,a);cout << "MD5單向加密result: " << test.encode(a) << endl;finish = clock();cout <<endl<<"the time cost is:" << double(finish - start) / CLOCKS_PER_SEC<<endl;
}//解密網(wǎng)站:https://www.cmd5.com/
SHA-1
#include <iostream>
#include <string>
#include <bitset>
#include <math.h>
#include <time.h>using namespace std;long long pad[75] = { 0 };
int lenth_pad = 0;bitset<32> Kt[4] = { 0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6 };
bitset<32> Ht[5] = { 0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0 };//Ft函數(shù)
bitset<32> Ft(int t, bitset<32> B, bitset<32> C, bitset<32> D)
{if (0 <= t && t <= 19){return ((B&C) | ((~B)&D));}else if (20 <= t && t <= 39){return (B^C^D);}else if (40 <= t && t <= 59){return ((B&C) | (B&D) | (C&D));}else if (60 <= t && t <= 79){return (B^C^D);}
}//字符串的拓展函數(shù)
void SHA_PAD(string x)
{long long l = x.length();long long i = 0;pad[i] = 128;i++;l += 1;if ((l * 8) % 512 != 448){for (; (l * 8) % 512 != 448; l++){i++;}}l = x.length();l = l * 8;int a = 1;pad[i + 7] = l % 256;while (l / 256 > 0){l = l / 256;pad[i + 7 - a] = l % 256;a++;}for (; a < 8; a++){pad[i + 7 - a] = 0;}lenth_pad = i + 7;
}//循環(huán)左移函數(shù)
bitset<32> ROTL(int s, bitset<32> W)
{bitset<32>m = W << s;for (int i = 0; i < s; i++){m[i] = W[32 - s + i];}return m;
}//模2^32加函數(shù)
bitset<32> ADD(bitset<32>a, bitset<32>b)
{bitset<32> c;int d = 0;for (int i = 0; i < 32; i++){c[i] = (a[i] + b[i] + d) % 2;if (a[i] + b[i] + d >= 2){d = 1;}else if (a[i] + b[i] + d < 2){d = 0;}}return c;
}//循環(huán)體
void DO(bitset<512> M)
{bitset<32> Wt[80] = { 0 };for (int i = 0; i < 16; i++){for (int n = 0; n < 32; n++){Wt[i][n] = M[(15 - i) * 32 + n];}}for (int t = 16; t <= 79; t++){Wt[t] = ROTL(1, Wt[t - 3] ^ Wt[t - 8] ^ Wt[t - 14] ^ Wt[t - 16]);}bitset<32> A = Ht[0];bitset<32> B = Ht[1];bitset<32> C = Ht[2];bitset<32> D = Ht[3];bitset<32> E = Ht[4];for (int t = 0; t <= 79; t++){bitset<32> temp = ADD(ADD(ADD(ROTL(5, A), Ft(t, B, C, D)), ADD(E, Wt[t])), Kt[t/20]);E = D;D = C;C = ROTL(30, B);B = A;A = temp;}Ht[0] = ADD(Ht[0], A);Ht[1] = ADD(Ht[1], B);Ht[2] = ADD(Ht[2], C);Ht[3] = ADD(Ht[3], D);Ht[4] = ADD(Ht[4], E);
}int main()
{clock_t start,finish;start = clock();string x;cout << "please enter the text:";getline(cin, x);SHA_PAD(x);long long l = 0;//循環(huán)體while (l < x.length()){long long i = l;string Sx;for (; (i < 64 + l) && (i < x.length()); i++){bitset<8> mark = int(x[i]);Sx += mark.to_string();}l += 64;if (i == x.length()){if(lenth_pad<=63)for (int n = 0; n <= lenth_pad; n++){bitset<8> mark = pad[n];Sx += mark.to_string();}else{int n = 0;for (; i < l; i++){bitset<8> mark = pad[n];n++;Sx += mark.to_string();}bitset<512>Mx(Sx);DO(Mx);string last_Sx;for (; n <= lenth_pad; n++){bitset<8> mark = pad[n];last_Sx += mark.to_string();}bitset<512>last_Mx(last_Sx);DO(last_Mx);break;}}bitset<512> Mx(Sx);DO(Mx);}//輸出cout << "The hash of text is:";for (int i = 0; i < 5; i++){string s = Ht[i].to_string();for (int n = 0; n < 32;){int result = 0;for (int m = 0; m < 4; m++){result += (s[n + m] - '0')*pow(2, 3 - m);}cout << hex << result;n += 4;}}cout << "\n";//getchar();finish = clock();cout << "the time cost is: " << double(finish-start) / CLOCKS_PER_SEC << endl;return 0;
}
sm3
#include <iostream>
#include <string>
#include <cmath>
#include <time.h>
using namespace std;//二進(jìn)制轉(zhuǎn)換為十六進(jìn)制函數(shù)實(shí)現(xiàn)
string BinToHex(string str) {string hex = "";//用來存儲(chǔ)最后生成的十六進(jìn)制數(shù)int temp = 0;//用來存儲(chǔ)每次四位二進(jìn)制數(shù)的十進(jìn)制值while (str.size() % 4 != 0) {//因?yàn)槊克奈欢M(jìn)制數(shù)就能夠成為一個(gè)十六進(jìn)制數(shù),所以將二進(jìn)制數(shù)長度轉(zhuǎn)換為4的倍數(shù)str = "0" + str;//最高位添0直到長度為4的倍數(shù)即可}for (int i = 0; i < str.size(); i += 4) {temp = (str[i] - '0') * 8 + (str[i + 1] - '0') * 4 + (str[i + 2] - '0') * 2 + (str[i + 3] - '0') * 1;//判斷出4位二進(jìn)制數(shù)的十進(jìn)制大小為多少if (temp < 10) {//當(dāng)?shù)玫降闹敌∮?0時(shí),可以直接用0-9來代替hex += to_string(temp);}else {//當(dāng)?shù)玫降闹荡笥?0時(shí),需要進(jìn)行A-F的轉(zhuǎn)換hex += 'A' + (temp - 10);}}return hex;
}//十六進(jìn)制轉(zhuǎn)換為二進(jìn)制函數(shù)實(shí)現(xiàn)
string HexToBin(string str) {string bin = "";string table[16] = { "0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111" };for (int i = 0; i < str.size(); i++) {if (str[i] >= 'A'&&str[i] <= 'F') {bin += table[str[i] - 'A' + 10];}else {bin += table[str[i] - '0'];}}return bin;
}//二進(jìn)制轉(zhuǎn)換為十進(jìn)制的函數(shù)實(shí)現(xiàn)
int BinToDec(string str) {int dec = 0;for (int i = 0; i < str.size(); i++) {dec += (str[i] - '0')*pow(2, str.size() - i - 1);}return dec;
}//十進(jìn)制轉(zhuǎn)換為二進(jìn)制的函數(shù)實(shí)現(xiàn)
string DecToBin(int str) {string bin = "";while (str >= 1) {bin = to_string(str % 2) + bin;str = str / 2;}return bin;
}//十六進(jìn)制轉(zhuǎn)換為十進(jìn)制的函數(shù)實(shí)現(xiàn)
int HexToDec(string str) {int dec = 0;for (int i = 0; i < str.size(); i++) {if (str[i] >= 'A'&&str[i] <= 'F') {dec += (str[i] - 'A' + 10)*pow(16, str.size() - i - 1);}else {dec += (str[i] - '0')*pow(16, str.size() - i - 1);}}return dec;
}//十進(jìn)制轉(zhuǎn)換為十六進(jìn)制的函數(shù)實(shí)現(xiàn)
string DecToHex(int str) {string hex = "";int temp = 0;while (str >= 1) {temp = str % 16;if (temp < 10 && temp >= 0) {hex = to_string(temp) + hex;}else {hex += ('A' + (temp - 10));}str = str / 16;}return hex;
}string padding(string str) {//對數(shù)據(jù)進(jìn)行填充 string res = "";for (int i = 0; i < str.size(); i++) {//首先將輸入值轉(zhuǎn)換為16進(jìn)制字符串res += DecToHex((int)str[i]);}cout << "輸入字符串的ASCII碼表示為:" << endl;for (int i = 0; i < res.size(); i++) {cout << res[i];if ((i + 1) % 8 == 0) {cout << " ";}if ((i + 1) % 64 == 0 || (i + 1) == res.size()) {cout << endl;}}cout << endl;int res_length = res.size() * 4;//記錄的長度為2進(jìn)制下的長度res += "8";//在獲得的數(shù)據(jù)后面添1,在16進(jìn)制下相當(dāng)于是添加8while (res.size() % 128 != 112) {res += "0";//“0”數(shù)據(jù)填充}string res_len = DecToHex(res_length);//用于記錄數(shù)據(jù)長度的字符串while (res_len.size() != 16) {res_len = "0" + res_len;}res += res_len;return res;
}string LeftShift(string str, int len) {//實(shí)現(xiàn)循環(huán)左移len位功能string res = HexToBin(str);res = res.substr(len) + res.substr(0, len);return BinToHex(res);
}string XOR(string str1, string str2) {//實(shí)現(xiàn)異或操作string res1 = HexToBin(str1);string res2 = HexToBin(str2);string res = "";for (int i = 0; i < res1.size(); i++) {if (res1[i] == res2[i]) {res += "0";}else {res += "1";}}return BinToHex(res);
}string AND(string str1, string str2) {//實(shí)現(xiàn)與操作string res1 = HexToBin(str1);string res2 = HexToBin(str2);string res = "";for (int i = 0; i < res1.size(); i++) {if (res1[i] == '1' && res2[i] == '1') {res += "1";}else {res += "0";}}return BinToHex(res);
}string OR(string str1, string str2) {//實(shí)現(xiàn)或操作string res1 = HexToBin(str1);string res2 = HexToBin(str2);string res = "";for (int i = 0; i < res1.size(); i++) {if (res1[i] == '0' && res2[i] == '0') {res += "0";}else {res += "1";}}return BinToHex(res);
}string NOT(string str) {//實(shí)現(xiàn)非操作string res1 = HexToBin(str);string res = "";for (int i = 0; i < res1.size(); i++) {if (res1[i] == '0') {res += "1";}else {res += "0";}}return BinToHex(res);
}char binXor (char str1, char str2) {//實(shí)現(xiàn)單比特的異或操作return str1 == str2 ? '0' : '1';
}char binAnd(char str1, char str2) {//實(shí)現(xiàn)單比特的與操作return (str1 == '1'&&str2 == '1') ? '1' : '0';
}string ModAdd(string str1, string str2) {//mod 2^32運(yùn)算的函數(shù)實(shí)現(xiàn)string res1 = HexToBin(str1);string res2 = HexToBin(str2);char temp = '0';string res = "";for (int i = res1.size() - 1; i >= 0; i--) {res = binXor(binXor(res1[i], res2[i]), temp) + res;if (binAnd(res1[i], res2[i]) == '1') {temp = '1';}else {if (binXor(res1[i], res2[i]) == '1') {temp = binAnd('1', temp);}else {temp = '0';}}}return BinToHex(res);
}string P1(string str) {//實(shí)現(xiàn)置換功能P1(X)return XOR(XOR(str, LeftShift(str, 15)), LeftShift(str, 23));
}string P0(string str) {//實(shí)現(xiàn)置換功能P0(X)return XOR(XOR(str, LeftShift(str, 9)), LeftShift(str, 17));
}string T(int j) {//返回Tj常量值的函數(shù)實(shí)現(xiàn)if (0 <= j && j <= 15) {return "79CC4519";}else {return "7A879D8A";}
}string FF(string str1, string str2, string str3, int j) {//實(shí)現(xiàn)布爾函數(shù)FF功能if (0 <= j && j <= 15) {return XOR(XOR(str1, str2), str3);}else {return OR(OR(AND(str1, str2), AND(str1, str3)), AND(str2, str3));}
}string GG(string str1, string str2, string str3, int j) {//實(shí)現(xiàn)布爾函數(shù)GG功能if (0 <= j && j <= 15) {return XOR(XOR(str1, str2), str3);}else {return OR(AND(str1, str2), AND(NOT(str1), str3));}
}
string extension(string str) {//消息擴(kuò)展函數(shù)string res = str;//字符串類型存儲(chǔ)前68位存儲(chǔ)擴(kuò)展字W值for (int i = 16; i < 68; i++) {//根據(jù)公式生成第17位到第68位的W值res += XOR(XOR(P1(XOR(XOR(res.substr((i-16)*8,8), res.substr((i - 9) * 8, 8)), LeftShift(res.substr((i - 3) * 8, 8), 15))), LeftShift(res.substr((i - 13) * 8, 8), 7)), res.substr((i - 6) * 8, 8));}cout << "擴(kuò)展后的消息:" << endl;cout << "W0,W1,……,W67的消息:" << endl;for (int i = 0; i < 8; i++) {for (int j = 0; j < 8; j++) {cout << res.substr(i * 64 + j * 8, 8) << " ";}cout << endl;}cout << res.substr(512, 8) << " " << res.substr(520, 8) << " " << res.substr(528, 8) << " " << res.substr(536, 8) << endl;cout << endl;for (int i = 0; i < 64; i++) {//根據(jù)公式生成64位W'值res += XOR(res.substr(i * 8, 8), res.substr((i + 4) * 8, 8));}cout << "W0',W1',……,W63'的消息:" << endl;for (int i = 0; i < 8; i++) {for (int j = 0; j < 8; j++) {cout << res.substr(544+i * 64 + j * 8, 8) << " ";}cout << endl;}cout << endl;return res;
}string compress(string str1, string str2) {//消息壓縮函數(shù)string IV = str2;string A = IV.substr(0, 8), B = IV.substr(8, 8), C = IV.substr(16, 8), D = IV.substr(24, 8), E = IV.substr(32, 8), F = IV.substr(40, 8), G = IV.substr(48, 8), H = IV.substr(56, 8);string SS1 = "", SS2 = "", TT1 = "", TT2 = "";cout << "迭代壓縮中間值: " << endl;cout << " A B C D E F G H " << endl;cout << A << " " << B << " " << C << " " << D << " " << E << " " << F << " " << G << " " << H << endl;for (int j = 0; j < 64; j++) {SS1 = LeftShift(ModAdd(ModAdd(LeftShift(A, 12), E), LeftShift(T(j), (j%32))), 7);SS2 = XOR(SS1, LeftShift(A, 12));TT1 = ModAdd(ModAdd(ModAdd(FF(A, B, C, j), D), SS2), str1.substr((j + 68) * 8, 8));TT2 = ModAdd(ModAdd(ModAdd(GG(E, F, G, j), H), SS1), str1.substr(j * 8, 8));D = C;C = LeftShift(B, 9);B = A;A = TT1;H = G;G = LeftShift(F, 19);F = E;E = P0(TT2);cout << A << " " << B << " " << C << " " << D << " " << E << " " << F << " " << G << " " << H << endl;}string res = (A + B + C + D + E + F + G + H);cout << endl;return res;
}string iteration(string str) {//迭代壓縮函數(shù)實(shí)現(xiàn)int num = str.size() / 128;cout << "消息經(jīng)過填充之后共有 " + to_string(num) + " 個(gè)消息分組。" << endl;cout << endl;string V = "7380166F4914B2B9172442D7DA8A0600A96F30BC163138AAE38DEE4DB0FB0E4E";string B = "", extensionB = "", compressB = "";for (int i = 0; i < num; i++) {cout << "第 " << to_string(i+1) << " 個(gè)消息分組:" << endl;cout << endl;B = str.substr(i * 128, 128);extensionB = extension(B);compressB = compress(extensionB, V);V = XOR(V, compressB);}return V;
}int main() {//主函數(shù)clock_t start, finish;//clock_t為CPU時(shí)鐘計(jì)時(shí)單元數(shù)start = clock();//clock()函數(shù)返回此時(shí)CPU時(shí)鐘計(jì)時(shí)單元數(shù)string str[2];str[0] = "abcdabcdabcdabcd";str[1] = "1234567812345678";for (int num = 0; num < 2; num++) {cout << "示例 " + to_string(num + 1) + " :輸入消息為字符串: " + str[num] << endl;cout << endl;string paddingValue = padding(str[num]);cout << "填充后的消息為:" << endl;for (int i = 0; i < paddingValue.size() / 64; i++) {for (int j = 0; j < 8; j++) {cout << paddingValue.substr(i * 64 + j * 8, 8) << " ";}cout << endl;}cout << endl;string result = iteration(paddingValue);cout << "雜湊值:" << endl;for (int i = 0; i < 8; i++) {cout << result.substr(i * 8, 8) << " ";}cout << endl;cout << endl;}finish = clock();//clock()函數(shù)返回此時(shí)CPU時(shí)鐘計(jì)時(shí)單元數(shù)cout <<endl<<"the time cost is:" << double(finish - start) / CLOCKS_PER_SEC<<endl;//finish與start的差值即為程序運(yùn)行花費(fèi)的CPU時(shí)鐘單元數(shù)量,再除每秒CPU有多少個(gè)時(shí)鐘單元,即為程序耗時(shí)return 0;
}
2. openssl
OpenSSL is written in C, and has an Apache style license. It is distinguished by its support for the SSL and TLS protocols, as well as a family of command line applications.
openssl現(xiàn)在的狀態(tài)不佳,自從心臟出血事件之后,可謂是墻倒眾人推,網(wǎng)上也有好多人說它的代碼寫的很差,沒有良好的代碼規(guī)范,基于這些理由,又是項(xiàng)目中使用的,所以,還是不去冒這個(gè)險(xiǎn)了。
地址:http://www.openssl.org/
OpenSSL是一個(gè)安全套接字層密碼庫,其包括常用的密碼算法、常用的密鑰生成和證書封裝管理功能及SSL協(xié)議,并提供了豐富的應(yīng)用程序以供測試。
OpenSSL 是一個(gè)開源項(xiàng)目,其組成主要包括一下三個(gè)組件:
- openssl:多用途的命令行工具
- libcrypto:加密算法庫
- libssl:加密模塊應(yīng)用庫,實(shí)現(xiàn)了ssl及tls
安裝參考:https://blog.csdn.net/weixin_39274753/article/details/107958283
應(yīng)用如下:
1.單向散列加密應(yīng)用
OpenSSL單向加密的子命令為dgst,其語法如下:
openssl dgst [-md5|-md4|-md2|-sha1|-sha|-mdc2|-ripemd160|-dss1] [-c] [-d] [-hex] [-binary] [-out filename] [-sign filename] [-keyform arg] [-passin arg] [-verify filename] [-prverify filename] [-signature filename] [-hmac key] [file…]
其常用的選項(xiàng)為:
[-md5|-md4|-md2|-sha1|-sha|-mdc2|-ripemd160|-dss1]:指定一種單向加密算法;
-out FILENAME:將加密的內(nèi)容保存到指定的文件中;
單向加密除了 openssl dgst 工具還有: md5sum,sha1sum,sha224sum,sha256sum ,sha384sum,sha512sum
生成指定文件的特征碼案例:openssl dgst -md5 /tmp/fstab
md5sum /tmp/fstab
echo hello,world | md5sum
echo hello,world | openssl dgst -md5
2.對稱加密算法應(yīng)用
OpenSSL一共提供了8種對稱加密算法,其中7種是分組加密算法,僅有的一種流加密算法是RC4。這7種分組加密算法分別是AES、DES、Blowfish、CAST、IDEA、RC2、RC5。利用OpenSSL作對稱加密需要使用其子命令enc,其用法為:
openssl enc -ciphername [-in filename] [-out filename] [-pass arg] [-e] [-d] [-a/-base64] [-A] [-k password] [-kfile filename] [-K key] [-iv IV] [-S salt] [-salt] [-nosalt] [-z] [-md] [-p] [-P] [-bufsize number] [-nopad] [-debug] [-none] [-engine id]
其中常用的選項(xiàng)為:
-e:加密;
-d:解密;
-ciphername:ciphername為相應(yīng)的對稱加密算法名字,如-des3、-ase128、-cast、-blowfish等等。
-a/-base64:使用base-64位編碼格式;
-salt:自動(dòng)插入一個(gè)隨機(jī)數(shù)作為文件內(nèi)容加密,默認(rèn)選項(xiàng);
-in FILENAME:指定要加密的文件的存放路徑;
-out FILENAME:指定加密后的文件的存放路徑;
加密字符串案例:echo "hello,world" | openssl enc -aes128 -e -a –salt -in
加解密文件案例:openssl enc -des3 -e -a -in /etc/fstab -out /tmp/fstab
openssl enc -d -des3 -a -salt -in /tmp/fstab
3.非對稱加密算法應(yīng)用
OpenSSL一共實(shí)現(xiàn)了4種非對稱加密算法,包括DH算法、RSA算法、DSA算法和橢圓曲線算法(EC)。DH算法一般用戶密鑰交換。RSA算法既可以用于密鑰交換,也可以用于數(shù)字簽名。
利用openssl命令的子命令genrsa生成私鑰,然后再使用子命令rsa私鑰中提取公鑰。
genrsa的語法如下:
openssl genrsa [-out filename] [-passout arg] [-des] [-des3] [-idea] [-f4] [-3] [-rand file(s)] [-engine id] [numbits]
常用選項(xiàng):
-out FILENAME:將生成的私鑰保存至指定的文件中;
[-des] [-des3] [-idea]:指定加密算法;
numbits:指明生成的私鑰大小,默認(rèn)是512;
通常來說秘鑰文件的權(quán)限一般只能由管理員訪問,因此可以結(jié)合umask命令來設(shè)置生成的密鑰文件的權(quán)限,如:
(umask 077;openssl genrsa -out CA.key 4096)
隨后可利用rsa子命令生成的私鑰文件中提取公鑰,rsa子命令的語法為:
openssl rsa [-inform PEM|NET|DER] [-outform PEM|NET|DER] [-in filename] [-passin arg] [-out filename] [-passout arg] [-sgckey] [-des] [-des3] [-idea] [-text] [-noout] [-modulus] [-check] [-pubin] [-pubout] [-engine id]
常用選項(xiàng)為:
-in FILENAME:指明私鑰文件的存放路徑;
-out FILENAME:指明將公鑰的保存路徑;
-pubout:根據(jù)提供的私鑰,從中提取出公鑰;
使用案例:openssl rsa -pubout -in CA.key
利用公鑰加密、私鑰解密數(shù)據(jù):
使用rsautl進(jìn)行加密和解密操作,語法如下:
openssl rsautl [-in file] [-out file] [-inkey file] [-pubin] [-certin] [-sign] [-verify] [-encrypt] [-decrypt] [-pkcs] [-ssl] [-raw] [-hexdump] [-asn1parse]
openssl rsautl -h
Usage: rsautl [options]
-in file input file 輸入文件
-out file output file 輸出文件
-inkey file input key 指定私有密鑰文件,格式是RSA私有密鑰文件
-keyform arg private key format - default PEM 指定私鑰格式
-pubin input is an RSA public 指定輸入的是RSA公鑰
-certin input is a certificate carrying an RSA public key 指定輸入的是證書文件
-ssl 使用SSLv2的填充方式
-raw 不進(jìn)行填充
-pkcs 使用V1.5的填充方式(默認(rèn))
-oaep 使用OAEP的填充方式
-sign 使用私鑰做簽名
-verify 使用公鑰認(rèn)證簽名
-encrypt 使用公鑰加密
-decrypt 使用私鑰解密
-hexdump 以16進(jìn)制打印
-engine e 指定三方庫或者硬件設(shè)備
-passin arg pass phrase source 傳遞密碼來源
操作示例:
/*創(chuàng)建需要加密的文件*/
echo "123456789 hello world!" > plain.txt
/*生成RSA密鑰,采用des3對稱加密私鑰*/
openssl genrsa -des3 -passout pass:123456 -out RSA.pem
/*提取公鑰*/
openssl rsa -in RSA.pem -passin pass:123456 -pubout -out pub.pem
/*使用RSA作為密鑰進(jìn)行加密,實(shí)際上使用其中的公鑰進(jìn)行加密*/
openssl rsautl -encrypt -in plain.txt -inkey RSA.pem -passin pass:123456 -out enc.txt
/*使用RSA作為密鑰進(jìn)行解密,實(shí)際上使用其中的私鑰進(jìn)行解密*/
openssl rsautl -decrypt -in enc.txt -inkey RSA.pem -passin pass:123456 -out replain.txt
4.生成隨機(jī)數(shù)
openssl命令也支持生成隨機(jī)數(shù),其子命令為rand,對應(yīng)的語法為:
openssl rand [-out file] [-rand file(s)] [-base64] [-hex] num
常用選項(xiàng)有:
-base64:以base64編碼格式輸出;
-hex:使用十六進(jìn)制編碼格式;
-out FILE:將生成的內(nèi)容保存在指定的文件中;
使用案例:openssl rand -base64 10
5.加密密碼
OpenSSL還支持生成密碼的hash離散值,其子命令為passwd,語法如下:
openssl passwd [-crypt] [-1] [-apr1] [-salt string] [-in file] [-stdin] [-noverify] [-quiet] [-table] {password}
常用選項(xiàng)為:
-salt STRING:添加隨機(jī)數(shù);
-in FILE:對輸入的文件內(nèi)容進(jìn)行加密;
-stdin:對標(biāo)準(zhǔn)輸入的內(nèi)容進(jìn)行加密;
生成密碼的hash值案例:openssl passwd -1 -salt 123456 PASSWORD
6. 數(shù)字簽名
和非對稱加密相反,如果是用私鑰進(jìn)行加密,公鑰解密叫做數(shù)字簽名,因?yàn)樗借€只有一份,用公鑰解密出來驗(yàn)證確認(rèn)是你用這個(gè)私鑰做的簽名,這就是簽名和驗(yàn)證。
先用pkcs8子命令提取出pkcs8格式的私鑰,rsa默認(rèn)生成pkcs1格式的私鑰,當(dāng)然也可以直接使用默認(rèn)的來做簽名和驗(yàn)證,在用java等一些開發(fā)中需要要求私鑰是pkcs8格式,pkcs8子命令格式以及參數(shù)如下:
openssl pkcs8
[-inform PEM|DER] [-outform PEM|DER] [-in filename] [-passin arg] [-out filename]
[-passout arg] [-topk8] [-noiter] [-nocrypt] [-nooct] [-embed] [-nsdb] [-v2 alg]
[-v1 alg] [-engine id]
參數(shù)說明:
-inform PEM|DER :輸入文件格式,DER或者PEM格式。DER格式采用ASN1的DER標(biāo)準(zhǔn)格式。一般用的多的都是PEM格式,就是base64編碼格式。
-outform DER|PEM :輸出文件格式,DER或者PEM格式。
-in filename :輸入的密鑰文件,默認(rèn)為標(biāo)準(zhǔn)輸入。如果密鑰被加密,會(huì)提示輸入一個(gè)密鑰口令。
-passin arg :輸入文件口令保護(hù)來源。
-out filename :輸出文件,默認(rèn)為標(biāo)準(zhǔn)輸出。如果任何加密操作已經(jīng)執(zhí)行,會(huì)提示輸入一個(gè)密鑰值。輸出的文件名字不能和輸入的文件名一樣。
-passout arg :輸出文件口令保護(hù)來源。
-topk8 :通常的是輸入一個(gè)pkcs8文件和傳統(tǒng)的格式私鑰文件將會(huì)被寫出。設(shè)置了此選項(xiàng)后,位置轉(zhuǎn)換過來:輸入一個(gè)傳統(tǒng)格式的私鑰文件,輸出一個(gè)PKCS#8格式的文件。
-noiter :MAC保護(hù)計(jì)算次數(shù)為1。
-nocrypt :PKCS#8密鑰產(chǎn)生或輸入一般用一個(gè)適當(dāng)?shù)孛荑€來加密PKCS#8 EncryptedPrivateKeyInfo結(jié)構(gòu)。設(shè)置了此選項(xiàng)后,一個(gè)不加密的PrivateKeyInfo結(jié)構(gòu)將會(huì)被輸出。這個(gè)選項(xiàng)一直不加密私鑰文件,在絕對必要的時(shí)候才能夠使用。某些軟件例如一些JAVA代碼簽名軟件使用不加密的私鑰文件。
-nooct :這個(gè)選項(xiàng)產(chǎn)生的RSA私鑰文件是一個(gè)壞的格式,一些軟件將會(huì)使用。特別的是,私鑰文件必須附上一個(gè)八位組字符串,但是一些軟件僅僅包含本身的結(jié)構(gòu)體沒有使八位組字符串所環(huán)繞。不采用八位組表示私鑰。
-embed :這個(gè)選項(xiàng)產(chǎn)生的RSA私鑰文件是一個(gè)壞的格式。在私鑰結(jié)構(gòu)體中采用嵌入式DSA參數(shù)格式。在這個(gè)表單中,八位組字符串包含了ASN1 SEQUENCE中的兩種結(jié)構(gòu):一個(gè)SEQUENCE包含了密鑰參數(shù),一個(gè)ASN1 INTEGER包含私鑰值。
-nsdb :這個(gè)選項(xiàng)產(chǎn)生的RSA私鑰文件是一個(gè)壞的格式并兼容了Netscape私鑰文件數(shù)據(jù)庫。采用NetscapeDB的DSA格式。
-v2 alg :采用PKCS#5 v2.0,并指定加密算法,默認(rèn)的是PKCS#8私鑰文件被叫做B<pbeWithMD5AndDES-CBC>(該算法用56字節(jié)的DES加密但是在PKCS#5 v1.5中有更加強(qiáng)壯的加密算法)的加密算法用口令進(jìn)行加密。用B<-v2>選項(xiàng),PKCS#5 v2.0相關(guān)的算法將會(huì)被使用,可以是des3(168字節(jié))和rc2(128字節(jié)),推薦des3。
-v1 alg :采用PKCS#5 v1.5或pkcs12,并指定加密算法。-engine id :指定硬件引擎。
然后用rsautl子命令-sign生成簽名,-verify驗(yàn)證,示例如下:
/*提取PCKS8格式的私鑰*/
openssl pkcs8 -topk8 -in RSA.pem -passin pass:123456 -out pri.pem –nocrypt
/*使用私鑰生成簽名*/
openssl rsautl -sign -in plain.txt -inkey pri.pem -out sign.txt
/*使用公鑰對簽名進(jìn)行驗(yàn)證*/
openssl rsautl -verify -in sign.txt -inkey pub.pem -pubin -out replain.txt
/*用默認(rèn)的rsa生成的pkcs1格式私鑰生成簽名*/
openssl rsautl -sign -in plain.txt -inkey RSA.pem -passin pass:123456 -out sign1.txt
/*用公鑰驗(yàn)證簽名*/
openssl rsautl -verify -in sign1.txt -inkey pub.pem -pubin -out replain1.txt
/*查看解密內(nèi)容*/
xxd replain1.txt
3. crypto++
Crypto++ is written in C++, and is mostly public domain files, although there are a few restrictions on the use of the collection. Crypto++ includes a set of ECC functions.
基于c++的cryptlib,這個(gè)庫在網(wǎng)上的評價(jià)還算不錯(cuò)的,支持多種加密算法。
這里暫時(shí)選擇Cryto++這個(gè)庫,選擇這個(gè)庫主要是因?yàn)楝F(xiàn)在手頭找到的關(guān)于它的資料文檔最多,容易快速上手。
地址:http://www.cryptopp.com/
AES算法:
#include <iostream>
#include <aes.h>#pragma comment( lib, "cryptlib.lib" )
using namespace std;
using namespace CryptoPP;
int main()
{
//AES中的固定參數(shù)是以類AES中定義的enum數(shù)據(jù)類型,而不是成員函數(shù)或變量
cout << "AES Parameters: " << endl;
cout << "Algorithm name : " << AES::StaticAlgorithmName() << endl; //Crypto++庫中一般用字節(jié)數(shù)來表示長度
cout << "Block size : " << AES::BLOCKSIZE * 8 << endl;
cout << "Min key length : " << AES::MIN_KEYLENGTH * 8 << endl;
cout << "Max key length : " << AES::MAX_KEYLENGTH * 8 << endl;//AES中只包含一些固定的數(shù)據(jù),而加密解密的功能由AESEncryption和AESDecryption來完成
//加密過程
AESEncryption aesEncryptor; //加密器 unsigned char aesKey[AES::DEFAULT_KEYLENGTH]; //密鑰
unsigned char inBlock[AES::BLOCKSIZE] = "123456789"; //要加密的數(shù)據(jù)塊
unsigned char outBlock[AES::BLOCKSIZE]; //加密后的密文塊
unsigned char xorBlock[AES::BLOCKSIZE]; //必須設(shè)定為全零memset( xorBlock, 0, AES::BLOCKSIZE ); //置零aesEncryptor.SetKey( aesKey, AES::DEFAULT_KEYLENGTH ); //設(shè)定加密密鑰
aesEncryptor.ProcessAndXorBlock( inBlock, xorBlock, outBlock ); //加密//以16進(jìn)制顯示加密后的數(shù)據(jù)
for( int i=0; i<16; i++ ) {
cout << hex << (int)outBlock[i] << " ";
}
cout << endl;//解密
AESDecryption aesDecryptor;
unsigned char plainText[AES::BLOCKSIZE];aesDecryptor.SetKey( aesKey, AES::DEFAULT_KEYLENGTH );
aesDecryptor.ProcessAndXorBlock( outBlock, xorBlock, plainText );for( int i=0; i<16; i++ )
{
cout << plainText[i];
}
cout << endl;return 0;}
DES算法:
#include <iostream>
#include <des.h>#pragma comment( lib, "cryptlib.lib" )using namespace std;
using namespace CryptoPP;int main( void )
{cout << "DES Parameters: " << endl;cout << "Algorithm name : " << DES::StaticAlgorithmName() << endl;unsigned char key[ DES::DEFAULT_KEYLENGTH ];unsigned char input[ DES::BLOCKSIZE ] = "12345";unsigned char output[ DES::BLOCKSIZE ];unsigned char txt[ DES::BLOCKSIZE ];cout << "input is: " << input << endl;//首先構(gòu)造一個(gè)加密器DESEncryption encryption_DES;//設(shè)置密匙。encryption_DES.SetKey( key, DES::KEYLENGTH );//進(jìn)行加密encryption_DES.ProcessBlock( input, output );//顯示結(jié)果//for和for之后的cout可有可無,主要為了運(yùn)行的時(shí)候看加密結(jié)果//把字符串的長度寫成一個(gè)常量其實(shí)并不被推薦。//這里主要是把output也就是加密后的內(nèi)容,以十六進(jìn)制的整數(shù)形式輸出。for( int i = 0; i < 5; i++ ){cout << hex << (int)output[ i ] << ends;}cout << endl;//構(gòu)造一個(gè)解密器DESDecryption decryption_DES;//加密和解密都是同一個(gè)密匙,decryption_DES.SetKey( key, DES::KEYLENGTH );//進(jìn)行解密,把結(jié)果寫到txt中//decryption_DES.ProcessAndXorBlock( output, xorBlock, txt );decryption_DES.ProcessBlock( output, txt );//驗(yàn)證加密前的明文和解密后的譯文是否相等。if ( memcmp( input, txt, 5 ) != 0 ){cerr << "DES Encryption/decryption failed.\n";abort();}cout << "DES Encryption/decryption succeeded.\n";return 0;
}
RSA算法:
#include "randpool.h"
#include "rsa.h"
#include "hex.h"
#include "files.h"
#include <iostream>using namespace std;
using namespace CryptoPP;#pragma comment(lib, "cryptlib.lib")void GenerateRSAKey( unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed );
string RSAEncryptString( const char *pubFilename, const char *seed, const char *message );
string RSADecryptString( const char *privFilename, const char *ciphertext );
RandomPool & GlobalRNG();void main( void ){char priKey[ 128 ] = { 0 };char pubKey[ 128 ] = { 0 };char seed[ 1024 ] = { 0 };// 生成 RSA 密鑰對strcpy( priKey, "pri" ); // 生成的私鑰文件strcpy( pubKey, "pub" ); // 生成的公鑰文件strcpy( seed, "seed" );GenerateRSAKey( 1024, priKey, pubKey, seed );// RSA 加解密char message[ 1024 ] = { 0 };cout<< "Origin Text:\t" << "Hello World!" << endl << endl;strcpy( message, "Hello World!" );string encryptedText = RSAEncryptString( pubKey, seed, message ); // RSA 公匙加密cout<<"Encrypted Text:\t"<< encryptedText << endl << endl;string decryptedText = RSADecryptString( priKey, encryptedText.c_str() ); // RSA 私匙解密
}// 生成密鑰對
void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed)
{RandomPool randPool;randPool.Put((byte *)seed, strlen(seed));RSAES_OAEP_SHA_Decryptor priv(randPool, keyLength);HexEncoder privFile(new FileSink(privFilename));priv.DEREncode(privFile);privFile.MessageEnd();RSAES_OAEP_SHA_Encryptor pub(priv);HexEncoder pubFile(new FileSink(pubFilename));pub.DEREncode(pubFile);pubFile.MessageEnd();return ;
}// RSA加密
string RSAEncryptString( const char *pubFilename, const char *seed, const char *message )
{FileSource pubFile( pubFilename, true, new HexDecoder );RSAES_OAEP_SHA_Encryptor pub( pubFile );RandomPool randPool;randPool.Put( (byte *)seed, strlen(seed) );string result;StringSource( message, true, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(result))) );return result;
}// RSA解密
string RSADecryptString( const char *privFilename, const char *ciphertext )
{FileSource privFile( privFilename, true, new HexDecoder );RSAES_OAEP_SHA_Decryptor priv(privFile);string result;StringSource( ciphertext, true, new HexDecoder(new PK_DecryptorFilter(GlobalRNG(), priv, new StringSink(result))) );return result;
}// 定義全局的隨機(jī)數(shù)池
RandomPool & GlobalRNG()
{static RandomPool randomPool;return randomPool;
}
SHA-256算法:
//參考 http://hi.baidu.com/magic475/blog/item/19b37a8c1fa15a14b21bbaeb.html
#include <iostream>
#include <string.h>#include "sha.h"
#include "secblock.h"
#include "modes.h"
#include "hex.h"#pragma comment( lib, "cryptlib.lib")using namespace std;
using namespace CryptoPP;void CalculateDigest(string &Digest, const string &Message);
bool VerifyDigest(const string &Digest, const string &Message);int main( void )
{string strMessage( "Hello world" );string strDigest; // 摘要//string strMessage2( "hello world" ); //只是第一個(gè)字母不同//string strDigest2;CalculateDigest( strDigest, strMessage ); //計(jì)算Hash值并打印一些debug信息cout << "the size of Digest is: " << strDigest.size() << endl;cout << "Digest is: " << strDigest << endl;bool bIsSuccess = false;bIsSuccess = VerifyDigest( strDigest, strMessage );//通過校驗(yàn),看看strDigest是否對應(yīng)原來的messageif( bIsSuccess ){cout << "sussessive verify" << endl;cout << "origin string is: " << strMessage << endl << endl;}else{cout << "fail!" << endl;}//通過strDigest2與strMessage進(jìn)行校驗(yàn),要是相等,//就證明strDigest2是對應(yīng)的strMessage2跟strMessage1相等。/*CalculateDigest( strDigest2, strMessage2 );bIsSuccess = VerifyDigest( strDigest2, strMessage );if( !bIsSuccess ){cout << "success! the tiny modification is discovered~" << endl;cout << "the origin message is: \n" << strMessage << endl;cout << "after modify is: \n" << strMessage2 << endl;}*/return 0;
}void CalculateDigest(string &Digest, const string &Message)
{SHA256 sha256;int DigestSize = sha256.DigestSize();char* byDigest;char* strDigest;byDigest = new char[ DigestSize ];strDigest = new char[ DigestSize * 2 + 1 ];sha256.CalculateDigest((byte*)byDigest, (const byte *)Message.c_str(), Message.size());memset(strDigest, 0, sizeof(strDigest));//uCharToHex(strDigest, byDigest, DigestSize);Digest = byDigest;delete []byDigest;byDigest = NULL;delete []strDigest;strDigest = NULL;return;
}bool VerifyDigest(const string &Digest, const string &Message)
{bool Result;SHA256 sha256;char* byDigest;byDigest = new char[ sha256.DigestSize() ];strcpy( byDigest, Digest.c_str() );//HexTouChar(byDigest, Digest.c_str(), Digest.size());Result = sha256.VerifyDigest( (byte*)byDigest, (const byte *)Message.c_str(), Message.size() );delete []byDigest;byDigest = NULL;return Result;
}
獲取設(shè)備mac物理地址程序:
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif // !_CRT_SECURE_NO_WARNINGS//#include "stdafx.h"
#include <windows.h>
#include <wincon.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <Nb30.h>#include <fstream>
#include <iostream>
#include <string>
#pragma comment(lib,"netapi32.lib")int GetMac(char * mac)
{NCB ncb;typedef struct _ASTAT_{ADAPTER_STATUS adapt;NAME_BUFFER NameBuff[30];}ASTAT, *PASTAT;ASTAT Adapter;typedef struct _LANA_ENUM{UCHAR length;UCHAR lana[MAX_LANA];}LANA_ENUM;LANA_ENUM lana_enum;UCHAR uRetCode;memset(&ncb, 0, sizeof(ncb));memset(&lana_enum, 0, sizeof(lana_enum));ncb.ncb_command = NCBENUM;ncb.ncb_buffer = (unsigned char *)&lana_enum;ncb.ncb_length = sizeof(LANA_ENUM);uRetCode = Netbios(&ncb);if (uRetCode != NRC_GOODRET)return uRetCode;for (int lana = 0; lana < lana_enum.length; lana++){ncb.ncb_command = NCBRESET;ncb.ncb_lana_num = lana_enum.lana[lana];uRetCode = Netbios(&ncb);if (uRetCode == NRC_GOODRET)break;}if (uRetCode != NRC_GOODRET)return uRetCode;memset(&ncb, 0, sizeof(ncb));ncb.ncb_command = NCBASTAT;ncb.ncb_lana_num = lana_enum.lana[0];strcpy((char*)ncb.ncb_callname, "*");ncb.ncb_buffer = (unsigned char *)&Adapter;ncb.ncb_length = sizeof(Adapter);uRetCode = Netbios(&ncb);if (uRetCode != NRC_GOODRET)return uRetCode;sprintf(mac, "%02X-%02X-%02X-%02X-%02X-%02X",Adapter.adapt.adapter_address[0],Adapter.adapt.adapter_address[1],Adapter.adapt.adapter_address[2],Adapter.adapt.adapter_address[3],Adapter.adapt.adapter_address[4],Adapter.adapt.adapter_address[5]);return 0;
}int main(int argc, char* argv[])
{//1.未授權(quán)的鑰匙int is_authorized = 0;char mac_empty[200] = "asghjkkklll";//電腦mac地std::string key_file_name = "key.txt";std::ofstream outfile(key_file_name);std::ifstream infile(key_file_name);//寫入文件夾std::fstream file(key_file_name, std::ios::out);//文件夾清空outfile << std::to_string(is_authorized) << std::endl;outfile << mac_empty << std::endl;char mac_empty1[200] = "000000000";//電腦mac地int is_authorized1 = 0;if (!infile.is_open()){std::cout << "文件夾已經(jīng)打開!" << std::endl;return -1;}//2.讀取密鑰信息std::string mac_name;std::string is_authorized2_str;if (!infile.is_open()){std::cout << "文件夾已經(jīng)打開!" << std::endl;return -1;}std::getline(infile, is_authorized2_str);std::getline(infile, mac_name);const std::string is_authorized11 = is_authorized2_str;int is_authorized3 = std::stoi(is_authorized11);//3.判定如果軟件還未授權(quán),則授權(quán)if (is_authorized3 == 0){GetMac(mac_empty);is_authorized = 1;std::fstream file(key_file_name, std::ios::out);//文件夾清空outfile << is_authorized << std::endl;outfile << mac_empty << std::endl;printf("授權(quán)成功!/n");}//4.再次讀取授權(quán)狀態(tài)if (!infile.is_open()){std::cout << "文件夾已經(jīng)打開!" << std::endl;return -1;}std::getline(infile, is_authorized2_str);std::getline(infile, mac_name);const std::string is_authorized12 = is_authorized2_str;is_authorized3 = std::stoi(is_authorized12);if (is_authorized3 == 1){ char mac_real[200] = "1111111";//電腦mac地GetMac(mac_real);if (strcmp(mac_real, mac_name.c_str()) == 0){std::cout << "mac 地址正確!" << std::endl;}else{std::cout << "mac 地址錯(cuò)誤,軟件未授權(quán)!" << std::endl;}}printf("The Mac Address is : %s \n", mac_empty);system("pause");return 0;
}
4. botan
這個(gè)庫沒有太多的了解,也僅僅是剛知道,也是支持多種加密算法的。
地址:http://botan.randombit.net/
5. cryptlib
基于c的加密庫。
地址:http://www.cryptlib.com/
如果應(yīng)用涉及到 SSL 等 PKI 協(xié)議,應(yīng)該使用 openssl,如果只是應(yīng)用一些加密算法,則建議使用 Cryptlib。
三、性能與方案選擇
加密技術(shù)包括兩個(gè)元素:算法和密鑰。密鑰是用來對數(shù)據(jù)進(jìn)行編碼和解碼的一種方法;而算法是將明文與密鑰結(jié)合,產(chǎn)生不可理解的密文的步驟。
單向散列算法誕生較早,技術(shù)成熟,運(yùn)行速度最快,但只能單向加密;對稱加密算法是指客戶端和服務(wù)端共用一套密鑰,用相同的密鑰去加密和解密,運(yùn)行速度較快,安全性也較高;非對稱加密算法有公鑰和私鑰,較難破解,安全等級最高,但運(yùn)行速度較慢。
常用加密算法性能和安全性對比:
通過了解各種算法的實(shí)現(xiàn)方式、優(yōu)缺點(diǎn)及相關(guān)應(yīng)用,得出以下結(jié)論:校驗(yàn)時(shí),可以使用單向散列算法(如MD5、CRC32),一般加密需求時(shí),可以使用對稱加密算法(如AES、DES);但加密要求較高時(shí),建議選用混合加密策略,即用非對稱加密算法(如RSA)來解決對稱加密的密鑰傳輸,密鑰傳輸完成后,A和B之間采用對稱加密算法(如AES)進(jìn)行通信。這樣做既可以保證密鑰的安全性,也能保證數(shù)據(jù)正常傳輸過程中的運(yùn)行效率。
以上。