<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          加密與解密

          共 1609字,需瀏覽 4分鐘

           ·

          2021-01-19 02:05

          涉及到安全的領(lǐng)域總離不開(kāi)數(shù)據(jù)加密,如通訊、文件保護(hù)游戲核心數(shù)據(jù)等等
          加密技術(shù)博大高深,涉及深厚的數(shù)學(xué)原理。加密方式亦有多種,比如飄云閣的一套密碼學(xué)工具就提供了多種方式:
          本文將介紹一些密碼學(xué)知識(shí)(其實(shí)是對(duì)19年文章的更新),并提供一個(gè)方便使用的接口庫(kù),這些功能基于cryptopp(見(jiàn)第5節(jié))。
          之后,你會(huì)發(fā)現(xiàn)要編寫個(gè)類似上面的工具,其實(shí)并不難。

          1

          簡(jiǎn)單加密

          在加密技術(shù)中,一個(gè)最底層的工具就是mod運(yùn)算,即按位異或運(yùn)算。
          異或運(yùn)算的法則是:當(dāng)兩個(gè)操作數(shù)中只有一個(gè)為1的時(shí)候,結(jié)果為真(1),否則結(jié)果為假(0)。如:
          ???10010011?^
          ???00111101
          ----------------
          =?10101110
          除此以外,異或運(yùn)算還擁有交換律、結(jié)合律,即:
          A?^?B?==?B?^?A
          A?^?B?^?C?==?(A?^?B)?^?C?==?A?^?(B?^?C)
          A?^?B?=?C??-->??A?=?B?^?C??-->??B?=?A?^?C
          所以,對(duì)一串?dāng)?shù)據(jù)進(jìn)行一次異或運(yùn)算,就能夠?qū)?shù)據(jù)進(jìn)行「加密」,再進(jìn)行一次異或運(yùn)算就能夠?qū)?shù)據(jù)進(jìn)行「解密」
          基于此,我們便可以寫一個(gè)很簡(jiǎn)單的用于加密文件的小程序:
          1void?EncrytFile(const?char*?plain_file,?const?char*?cipher_file)
          2
          {
          3????if?(nullptr?==?plain_file?||?nullptr?==?cipher_file)
          4????????throw?std::runtime_error("名稱為空");
          5
          6????//?打開(kāi)欲加密文件
          7????std::ifstream?fsPlainFile(plain_file,?
          8????????std::ios_base::in?|?std::ios_base::binary)
          ;
          9????if?(!fsPlainFile.is_open())
          10????????throw?std::runtime_error("打開(kāi)文件失敗");
          11
          12????//?打開(kāi)輸出文件
          13????std::ofstream?fsCipherFile(cipher_file,?std::ios_base::out?|?std::ios_base::binary);
          14????if?(!fsCipherFile)
          15????{
          16????????fsPlainFile.close();
          17????????throw?std::runtime_error("打開(kāi)文件失敗");
          18????}
          19
          20????const?int?key?=?0x7F;
          21
          22????//?加密
          23????char?temp?=?fsPlainFile.get()?^?key;
          24????while?(!fsPlainFile.eof())
          25????{
          26????????fsCipherFile.put(temp);
          27????????temp?=?fsPlainFile.get()?^?key;
          28????}
          29
          30????fsPlainFile.close();
          31????fsCipherFile.close();
          32}
          可以使用這個(gè)函數(shù)來(lái)加密任何類型的文件,因?yàn)檫@里是以二進(jìn)制模式對(duì)文件進(jìn)行操作的。
          比如可以對(duì)文本類型進(jìn)行加密:
          1try?{
          2????EncrytFile(".//1.txt",?".//encrypted.txt");
          3}
          4catch?(const?std::exception&?e)
          5{
          6????std::cerr?<std::endl;
          7}
          加密之后文本變成了亂碼文件:
          只要再對(duì)加密文件進(jìn)行一次加密,那么就可將文件解密:
          1try?{
          2????EncrytFile(".//encrypted.txt",?".//decrypted.txt");
          3}
          4catch?(const?std::exception&?e)
          5{
          6????std::cerr?<std::endl;
          7}
          解密結(jié)果:
          對(duì)數(shù)據(jù)進(jìn)行加密后,只有能夠完整解密,才能稱之為「加密」。若是加密之后,無(wú)法進(jìn)行解密,那么就不叫做加密,純屬是數(shù)據(jù)破壞。

          2

          對(duì)稱密碼

          在上面的代碼中,加密與解密用的是同一個(gè)密鑰,那么使用這種加密方式的密碼就稱為「對(duì)稱密碼」

          2.1

          DES

          DES是一種將64bits的明文加密成64bits密文的「對(duì)稱加密算法」,它的密鑰長(zhǎng)度為64bits,但是會(huì)在每7bits設(shè)置一個(gè)用于錯(cuò)誤檢查的位,因此實(shí)際上它的密鑰長(zhǎng)度為56bits。
          這種加密方式起初一直被政府與銀行機(jī)構(gòu)使用,不過(guò)現(xiàn)在已經(jīng)能夠在短時(shí)間內(nèi)被破解,所以已經(jīng)不推薦使用了。
          DES每次只能加密64bits的數(shù)據(jù),那么64bits就是它的基本單位,這個(gè)單位在密碼學(xué)中被稱為「分組」。
          要想加密更長(zhǎng)的數(shù)據(jù),就得把這些數(shù)據(jù)按64bits分成一個(gè)個(gè)的分組,那么這種以分組為單位進(jìn)行加密的密碼算法就被稱為「分組密碼」
          對(duì)數(shù)據(jù)進(jìn)行分組有許多方式,具體的分組方式稱為「模式」,比如ECB、CBC、CFB、OFB、CTR等等。
          DES的結(jié)構(gòu)使用了Feistel網(wǎng)絡(luò),在這個(gè)結(jié)構(gòu)中,加密的一個(gè)步驟稱為一個(gè)「輪」,要全部加密就要進(jìn)行若干次「輪循」。
          圖中,左邊部分為加密操作,右邊部分為解密操作。
          每輪的密鑰都不能相同,所以Key1只是一個(gè)局部變量,僅作為當(dāng)輪加密使用,所以把這種密鑰稱為「子密鑰」。
          在加密操作中,將數(shù)據(jù)分為左右兩部分,DES是一次加密64bits的明文,所以L0就指的是前32bits,R0就將的是后32bits,F(xiàn)就是加密時(shí)使用的輪函數(shù),K0、K1…Kn就是每輪加密的「子密鑰」,這里進(jìn)行了N輪的加密操作。
          每輪只會(huì)將L0,即左半部分的數(shù)據(jù)與輪函數(shù)生成的比特序列進(jìn)行異或運(yùn)算,右半部分直接輸出。之后進(jìn)行翻轉(zhuǎn),左部分變成右部分,右部分變成左部分,如此進(jìn)行多輪循環(huán)加密。

          2.2

          AES

          由于DES不再安全,所以就需要一種新的加密算法來(lái)代替其成為標(biāo)準(zhǔn)。美國(guó)標(biāo)準(zhǔn)化機(jī)構(gòu)組織了一次公開(kāi)競(jìng)選,能被選中的密碼算法將成為美國(guó)的加密標(biāo)準(zhǔn),其實(shí)也就相當(dāng)于世界的加密標(biāo)準(zhǔn)。
          參與者必須提供詳細(xì)的設(shè)計(jì)和程序代碼實(shí)現(xiàn),由于完全公開(kāi),所以不同的參與者都能看清別人的設(shè)計(jì)。這些參與者都是來(lái)自各個(gè)國(guó)家的密碼學(xué)專家或數(shù)學(xué)大師,如果連他們也無(wú)法找出其他參與者算法中存在的漏洞,那么就能保證加密算法的強(qiáng)度。
          這些加密算法不僅需要高強(qiáng)度,還需要有高速度、簡(jiǎn)易性。最終,Rijndael(即后來(lái)的AES標(biāo)準(zhǔn)算法)力壓群雄,成為了AES標(biāo)準(zhǔn)。
          Rijndael和DES使用了不同的結(jié)構(gòu),SPN結(jié)構(gòu):
          其中每一輪主要分成四個(gè)步驟:
          1. SubBytes(字節(jié)替換)

          2. ShiftRow(平移行)

          3. MixColumn(混合列)

          4. AddRoundKey(與輪密鑰進(jìn)行異或運(yùn)算)

          首先,它會(huì)以每個(gè)字節(jié)值,準(zhǔn)備一張擁有256個(gè)值的替換表,即ASCII碼表的中0-255個(gè)值,再以替換表中的值來(lái)逐字節(jié)地替換明文分組中的值。
          第二步和第三步,如同扭魔方一樣,先對(duì)數(shù)據(jù)的行進(jìn)行平移操作,再對(duì)數(shù)據(jù)的列進(jìn)行混合操作,混合中會(huì)將上一步得出的數(shù)據(jù)與替換表中的數(shù)據(jù)進(jìn)行矩陣運(yùn)算。
          最后,將得到的結(jié)果再與替換表中的數(shù)據(jù)進(jìn)行異或運(yùn)算,所有的數(shù)據(jù)在一輪操作后都會(huì)被加密,所以它比DES所需的輪數(shù)就要少。
          是不是覺(jué)得好深?yuàn)W?這些算法都有嚴(yán)謹(jǐn)?shù)臄?shù)學(xué)原理支撐,要想真正搞明白的確不易,我們只需了解它的設(shè)計(jì)思路就可以了。

          3

          非對(duì)稱密碼

          在對(duì)稱密碼中,加密與解密的密鑰都是一樣的,而「接收者」要解密就必須需要密鑰,所以這就產(chǎn)生了一個(gè)問(wèn)題,如何將密鑰安全地交到接收者手中呢?這個(gè)問(wèn)題就被稱為「密鑰配送問(wèn)題」。
          在公鑰密碼,即非對(duì)稱密碼中,密鑰分為「公鑰」和「私鑰」,一組公鑰與私鑰稱為一個(gè)「密鑰對(duì)」由「公鑰」加密的密文,只有使用對(duì)應(yīng)的「私鑰」才能完成解密
          如此一來(lái),「接收者」只需事先生成好密鑰對(duì),將公鑰發(fā)送給「發(fā)送者」,「發(fā)送者」使用「公鑰」對(duì)明文進(jìn)行加密,然后發(fā)送給「接收者」,「接收者」此時(shí)可以直接使用「私鑰」進(jìn)行解密。
          這樣就解決了「密鑰配送問(wèn)題」。

          3.1

          RSA

          RSA屬于公鑰密碼算法,它的名稱由三位發(fā)明人的名字首字母組成,這三人也因?yàn)檫@項(xiàng)發(fā)明獲得了圖靈獎(jiǎng)。
          所以,在RSA中,依舊需要「公鑰」和「私鑰」。可以從這張圖來(lái)看:
          其中主要分為以下幾個(gè)步驟:
          1. 選擇兩個(gè)很大的質(zhì)數(shù)p和q

          2. 根據(jù)p和q,計(jì)算出n,再求出p-1和q-1的最小公倍數(shù)v

          3. 找出一個(gè)數(shù)k,這個(gè)數(shù)要滿足:1 < k < v,并且k和v的最大公約數(shù)要為1

          4. 找出一個(gè)數(shù)d,這個(gè)數(shù)要滿足:1 < d < v,并且(d * k) % v要等于1

          其中,「公鑰」即為(k,n),「私鑰」即為(d, n),事實(shí)上,由于公鑰是可以隨意傳播的,而n又是公鑰的一部分,所以也可以說(shuō)私鑰就是d。
          之后,加密可以使用:密文 = 明文 ^ k % n,而解密則使用:明文 = 密文 ^ d % n
          這東西實(shí)現(xiàn)起來(lái)不難,但是比較麻煩,因?yàn)樾枰獙?duì)很大的數(shù)進(jìn)行運(yùn)算,這些數(shù)long long都不夠存儲(chǔ),只能通過(guò)字符串來(lái)搞,所以依舊明白它的思路就可以了。當(dāng)然,若是對(duì)取兩個(gè)很小的質(zhì)數(shù),也可以手動(dòng)驗(yàn)證上面步驟是否真的可以對(duì)數(shù)據(jù)進(jìn)行加密和解密。
          其實(shí),已經(jīng)有C++庫(kù)完美地實(shí)現(xiàn)了前面所介紹的加密算法,我們主要就來(lái)學(xué)習(xí)這些庫(kù)的使用就可以了。
          需要注意的是,在同等長(zhǎng)度的密鑰下,公鑰密碼處理速度只有對(duì)稱密碼的幾百分之一,所以公鑰密碼不適合加密過(guò)長(zhǎng)的內(nèi)容
          那么我們什么時(shí)候用公鑰密碼呢?不要忘記了對(duì)稱密碼的缺點(diǎn),以及公鑰密碼解決了什么問(wèn)題。
          公鑰密碼主要針對(duì)的是「密鑰配送問(wèn)題」,密鑰一般都不會(huì)太長(zhǎng),所以它的效率就會(huì)很高。
          總結(jié)一下就是,用對(duì)稱密碼來(lái)加密信息,而用公鑰密碼來(lái)解決密鑰的配送,同時(shí)使用這兩種的密碼就稱為「混合密碼」
          舉個(gè)例子,在一個(gè)通訊系統(tǒng)中,客戶端要發(fā)送數(shù)據(jù)到服務(wù)器,那么這些數(shù)據(jù)就可以使用對(duì)稱密碼來(lái)進(jìn)行加密。使用對(duì)稱密碼時(shí),服務(wù)器無(wú)法得知客戶端的加密密鑰,客戶端也無(wú)法直接將密鑰發(fā)送給服務(wù)器,因?yàn)樗绻軌蛑苯訉⒚荑€安全地發(fā)送過(guò)去,那么它也就可以安全地將數(shù)據(jù)傳送過(guò)去。
          這時(shí)就可以使用對(duì)稱密碼,通過(guò)服務(wù)器生成一個(gè)密鑰對(duì),將公鑰發(fā)送給客戶端,客戶端通過(guò)公鑰來(lái)對(duì)密鑰進(jìn)行加密,之后再發(fā)送給服務(wù)器。服務(wù)器通過(guò)私鑰對(duì)信息進(jìn)行解密,從而得到客戶端加密的密鑰,之后就能解開(kāi)客戶端的傳來(lái)的數(shù)據(jù)。

          4

          單向散列函數(shù)

          單向散列函數(shù)就是平時(shí)所說(shuō)的hash函數(shù),用于驗(yàn)證數(shù)據(jù)的完整性。
          在前面解決了如何將數(shù)據(jù)安全地傳遞給接收者,那么若此信息在發(fā)送期間被破壞者惡意篡改,你如何確保數(shù)據(jù)是完整而未被篡寫的呢?
          這就是單向散列函數(shù)的作用,它可以提取出一段信息的特征,輸出一段經(jīng)過(guò)嚴(yán)格計(jì)算的「散列值」
          若是一個(gè)算法對(duì)于不同的信息所計(jì)算的散列值不會(huì)重復(fù),那么就說(shuō)它具有「強(qiáng)抗碰撞性」。若一個(gè)算法的強(qiáng)抗碰撞性被攻破,即對(duì)于不同的信息,會(huì)產(chǎn)生相同的散列值,那么這個(gè)算法就不算安全。
          通過(guò)對(duì)比散列值是否一致,就可以驗(yàn)證文件是否完整比如,許多安全軟件在提供下載的地址處就給出了軟件所對(duì)應(yīng)的散列值,下載者可通過(guò)自己計(jì)算散列值來(lái)和所提供的散列值對(duì)比,以確認(rèn)下載的是正確的軟件。
          單向散列函數(shù)也有許多算法,例如MD5、SHA256、SHA512等等。不過(guò)如今MD5的強(qiáng)抗碰撞性已被攻破,已經(jīng)不推薦使用。現(xiàn)在安全的是SHA-3,這個(gè)也和AES一樣通過(guò)標(biāo)準(zhǔn)競(jìng)選所得,經(jīng)過(guò)了安全考驗(yàn),我們現(xiàn)在就可以使用這個(gè)。

          5

          基于Cryptopp加密庫(kù)的加密組件

          Cryptopp是使用C++開(kāi)發(fā)的一套密碼學(xué)程序庫(kù),其中使用了大量GP技術(shù),可以說(shuō)是一個(gè)非常高深的庫(kù),很有參考與使用價(jià)值。
          其中囊括了幾乎所有公開(kāi)的加密算法,比如上面所說(shuō)的對(duì)稱密碼DES、AES,以及公鑰密碼RSA,還有散列函數(shù)MD5、SHA3。加密的分組模式也通過(guò)GP實(shí)現(xiàn)了ECB,CBC,CFB,FOB,CTR這些。總之總結(jié)起來(lái)就兩個(gè)字:NB。
          我們將常用算法提煉到一個(gè)類中,名為okcrypt,以此來(lái)簡(jiǎn)化每次加解密的操作。這里提供代碼:https://github.com/gxkey/okcrypt,里面也包含cryptopp庫(kù),可以包含項(xiàng)目和lib目錄直接使用。
          下面簡(jiǎn)單分述下各個(gè)模塊。

          5.1

          MD5

          MD5是單向散列函數(shù),可以得出一段信息的散列值,雖說(shuō)其強(qiáng)抗碰撞性已被攻破,但仍有不少地方在使用。
          下面是MD5的使用:

          1const?std::string?okcrypt::EncryptMD5(std::string?const&?msg)
          2{????
          3????std::string?digest;
          4????Weak1::MD5?hash;
          5????hash.Update((const?byte*)msg.data(),?msg.size());
          6????digest.resize(hash.DigestSize());
          7????hash.Final((byte*)&digest[0]);
          8
          9????return?ToHex(digest);
          10}

          MD5在namespace Weak1之下,通過(guò)Update()設(shè)置原始數(shù)據(jù),通過(guò)Final()獲得消息摘要。
          要將得到的消息摘要轉(zhuǎn)換成十六進(jìn)制的才適合查看,不然看起來(lái)像是一堆二進(jìn)制亂碼。轉(zhuǎn)換十六進(jìn)制的函數(shù)實(shí)現(xiàn)如下:

          1static?const?std::string?ToHex(std::string?const&?digest)?{
          2????std::stringstream?ss;
          3????HexEncoder?encoder(new?FileSink(ss));
          4????(void)StringSource(digest,?true,?new?Redirector(encoder));
          5????return?ss.str();
          6}

          通過(guò)StringSource類可以將加密結(jié)果輸出到指定流,這里將它輸出到HexEncoder的保存的數(shù)據(jù)流中。

          5.2

          Base64

          Base64是一種編碼方式,使用如下:

          1const?std::string?okcrypt::EncryptBase64(std::string?const&?plainData)
          2{
          3????std::string?encoded;
          4
          5????StringSource?ss((const?byte*)plainData.data(),?plainData.size(),?
          6????????true,?new?Base64Encoder(new?StringSink(encoded))
          7????)
          ;
          8
          9????return?encoded;
          10}

          同樣借助了StringSource,編碼結(jié)果輸出到string中。

          5.3

          SHA

          SHA也是單向散列函數(shù),分為SHA-1、SHA-2,SHA-3。SHA-1的強(qiáng)抗碰撞性在2005年已被攻破,所以只說(shuō)SHA-2和SHA-3。
          SHA-2和SHA-3的散列長(zhǎng)度分為224、256、384、512比特,所以各提供4個(gè)版本:

          1//?SHA2
          2static?const?std::string?EncryptSHA224(std::string?const&?msg);
          3static?const?std::string?EncryptSHA256(std::string?const&?msg);
          4static?const?std::string?EncryptSHA384(std::string?const&?msg);
          5static?const?std::string?EncryptSHA512(std::string?const&?msg);
          6
          7//?SHA3
          8static?const?std::string?EncryptSHA3_224(std::string?const&?msg);
          9static?const?std::string?EncryptSHA3_256(std::string?const&?msg);
          10static?const?std::string?EncryptSHA3_384(std::string?const&?msg);
          11static?const?std::string?EncryptSHA3_512(std::string?const&?msg);

          由于cryptopp提供的算法接口都相同,只是類型不同,為了可復(fù)用性,我們使用函數(shù)模板實(shí)現(xiàn):

          1template<class?SHAType>
          2static?const?std:
          :string?EncryptSHA(std::string?const&?msg)?{
          3????SHAType?hash;
          4????std::string?digest;
          5????hash.Update((const?byte*)msg.data(),?msg.size());
          6????digest.resize(hash.DigestSize());
          7????hash.Final((byte*)&digest[0]);
          8
          9????return?ToHex(digest);
          10}

          可以看到和MD5的用法相似,這是因?yàn)檫@些散列函數(shù)都派生自HashTransformation,這里提供了Update、Final、Verify這些函數(shù)。
          現(xiàn)在直接調(diào)用EncryptSHA,并傳入不同的類型就能實(shí)現(xiàn)不同的SHA摘要,如下:

          1const?std::string?okcrypt::EncryptSHA224(std::string?const&?msg)
          2{
          3????return?EncryptSHA(msg);
          4}
          5
          6const?std::string?okcrypt::EncryptSHA256(std::string?const&?msg)
          7{
          8????return?EncryptSHA(msg);
          9}
          10
          11const?std::string?okcrypt::EncryptSHA384(std::string?const&?msg)
          12{
          13????return?EncryptSHA(msg);
          14}
          15
          16const?std::string?okcrypt::EncryptSHA512(std::string?const&?msg)
          17{
          18????return?EncryptSHA(msg);
          19}
          20
          21const?std::string?okcrypt::EncryptSHA3_224(std::string?const&?msg)
          22{
          23????return?EncryptSHA(msg);
          24}
          25
          26const?std::string?okcrypt::EncryptSHA3_256(std::string?const&?msg)
          27{
          28????return?EncryptSHA(msg);
          29}
          30
          31const?std::string?okcrypt::EncryptSHA3_384(std::string?const&?msg)
          32{
          33????return?EncryptSHA(msg);
          34}
          35
          36const?std::string?okcrypt::EncryptSHA3_512(std::string?const&?msg)
          37{
          38????return?EncryptSHA(msg);
          39}

          5.4

          DES

          現(xiàn)在來(lái)說(shuō)對(duì)稱密碼,DES分為DES和3DES,后者是三重加強(qiáng)版本。
          先定義如下函數(shù):

          1//?DES
          2static?void?InitalizeDESKey();
          3static?const?std::string?GetDESKey();
          4static?void?SetDESKey(std::string?const&?key);
          5static?void?EncryptDES(std::string?const&?plainData,?std::string&?cipherData);
          6static?void?DecryptDES(std::string?const&?cipherData,?std::string&?recoveredData);
          7
          8//?3DES
          9static?void?Initalize3DESKey();
          10static?const?std::string?Get3DESKey();
          11static?void?Set3DESKey(std::string?const&?key);
          12static?void?Encrypt3DES(std::string?const&?plainData,?std::string&?cipherData);
          13static?void?Decrypt3DES(std::string?const&?cipherData,?std::string&?recoveredData);

          還需要變量來(lái)保存密鑰和一個(gè)初始化向量(IV),IV用于用于在分組模式中提供第一次比特?cái)?shù)據(jù)。

          1static?SecByteBlock?m_desKey;
          2static?byte?m_desIV[DES_EDE2::BLOCKSIZE];
          3
          4static?SecByteBlock?m_3desKey;
          5static?byte?m_3desIV[DES_EDE3::BLOCKSIZE];

          因?yàn)槭庆o態(tài)變量,所以還需要在類外定義:

          1SecByteBlock????????okcrypt::m_desKey(0x00,?DES_EDE2::DEFAULT_KEYLENGTH);
          2byte???????????????????????okcrypt::m_desIV[DES_EDE2::BLOCKSIZE];
          3
          4SecByteBlock????????okcrypt::m_3desKey(0x00,?DES_EDE3::DEFAULT_KEYLENGTH);
          5byte???????????????????????okcrypt::m_3desIV[DES_EDE3::BLOCKSIZE];

          下面只說(shuō)3DES的使用,先初始化密鑰:

          1void?okcrypt::Initalize3DESKey()
          2{
          3????AutoSeededRandomPool?rng;
          4
          5????rng.GenerateBlock(m_3desKey,?m_3desKey.size());
          6????rng.GenerateBlock(m_3desIV,?sizeof(m_3desIV));
          7}

          可以通過(guò)隨機(jī)數(shù)池AutoSeededRandomPool來(lái)生成密鑰與IV。也可手動(dòng)設(shè)置和獲取密鑰:

          1const?std::string?okcrypt::Get3DESKey()
          2{
          3????std::string?key((char?*)m_3desKey.data(),?m_3desKey.size());
          4????return?key;
          5}
          6
          7void?okcrypt::Set3DESKey(std::string?const&?key)
          8{
          9????SecByteBlock?s((const?byte*)key.data(),?key.size());
          10????m_3desKey?=?s;
          11}

          加解密操作使用的是CBC分組模式,CBC對(duì)于每組明文是先異或后加密。實(shí)現(xiàn)如下:

          1void?okcrypt::Encrypt3DES(std::string?const&?plainData,?std::string?&cipherData)
          2{
          3????try?{
          4????????CBC_Mode::Encryption?e;
          5????????e.SetKeyWithIV(m_3desKey,?m_3desKey.size(),?m_3desIV);
          6
          7????????StringSource?ss(plainData,?true,
          8????????????new?StreamTransformationFilter(e,?new?StringSink(cipherData)
          )
          9????????)
          ;
          10????}
          11????catch?(const?CryptoPP::Exception&?e)
          12????{
          13????????throw?e;
          14????}
          15}
          16
          17void?okcrypt::Decrypt3DES(std::string?const&?cipherData,?std::string?&recoveredData)
          18{
          19????try?{
          20????????CBC_Mode::Decryption?d;
          21????????d.SetKeyWithIV(m_3desKey,?m_3desKey.size(),?m_3desIV);
          22
          23????????StringSource?ss(cipherData,?true,
          24????????????new?StreamTransformationFilter(d,?new?StringSink(recoveredData)
          )
          25????????)
          ;
          26????}
          27????catch?(const?CryptoPP::Exception&?e)
          28????{
          29????????throw?e;
          30????}
          31}

          5.5

          AES

          AES也是對(duì)稱密碼,所以也聲明相同的接口:

          1//?AES
          2static?void?InitalizeAESKey();
          3static?const?std::string?GetAESKey();
          4static?void?SetAESKey(std::string?const&?key);
          5static?void?EncryptAES(std::string?const&?plainData,?std::string&?cipherData);
          6static?void?DecryptAES(std::string?const&?cipherData,?std::string&?recoveredData);

          聲明密鑰和IV變量:

          1static?SecByteBlock?m_aesKey;
          2static?SecByteBlock?m_aesIV;

          類外定義:

          1SecByteBlock????????okcrypt::m_aesKey(0x00,?AES::DEFAULT_KEYLENGTH);
          2SecByteBlock????????okcrypt::m_aesIV(AES::BLOCKSIZE);

          隨機(jī)初始化密碼和IV:

          1void?okcrypt::InitalizeAESKey()
          2{
          3????AutoSeededRandomPool?rng;
          4
          5????//?生成隨機(jī)密鑰
          6????rng.GenerateBlock(m_aesKey,?m_aesKey.size());
          7
          8????//?生成隨機(jī)IV
          9????rng.GenerateBlock(m_aesIV,?m_aesIV.size());
          10}

          加密與解密:

          1void?okcrypt::EncryptAES(std::string?const&?plainData,?std::string?&cipherData)
          2{
          3????//?加密
          4????CFB_Mode::Encryption?e(m_aesKey,?m_aesKey.size(),?m_aesIV);
          5????cipherData.resize(plainData.size());
          6????e.ProcessData((byte*)&cipherData[0],?(byte*)plainData.data(),?plainData.size());
          7}
          8
          9void?okcrypt::DecryptAES(std::string?const&?cipherData,?std::string?&recoveredData)
          10{
          11????//?解密
          12????CFB_Mode::Decryption?d(m_aesKey,?m_aesKey.size(),?m_aesIV);
          13????recoveredData.resize(cipherData.size());
          14????d.ProcessData((byte*)&recoveredData[0],?(byte*)cipherData.data(),?cipherData.size());
          15}

          盡管AES的原理非常麻煩,但通過(guò)這些接口,可以很方便地使用它們。這里使用的不同的分組模式CFB,這種模式和CBC模式的區(qū)別是:CBC對(duì)于每組明文是先異或后加密,而CFB對(duì)于每組明文是先加密后異或。

          5.6

          RSA

          RSA是非對(duì)稱密碼,擁有公鑰和私鑰,定義的函數(shù)接口盡量也和對(duì)稱密碼一致:

          1//?RSA
          2static?void?InitalizeRSAKeys(size_t?bits?=?1024);
          3static?const?std::string?GetRSAPublicKey();
          4static?void?SetRSAPublicKey(std::string&?key);
          5static?void?EncryptRSA(std::string?const&?plainData,?std::string&?cipherData);
          6static?void?DecryptRSA(std::string?const&?cipherData,?std::string&?recoveredData);

          聲明公鑰和私鑰:

          1static?RSA::PublicKey?m_rsaPublicKey;
          2static?RSA::PrivateKey?m_rsaPrivateKey;

          類外定義:

          1RSA::PublicKey??????okcrypt::m_rsaPublicKey;
          2RSA::PrivateKey?????okcrypt::m_rsaPrivateKey;

          通過(guò)偽隨機(jī)數(shù)生成器自動(dòng)生成密鑰對(duì):

          1void?okcrypt::InitalizeRSAKeys(size_t?bits)
          2{
          3????//?偽隨機(jī)數(shù)生成器
          4????AutoSeededRandomPool?rng;
          5
          6????//?生成參數(shù)
          7????InvertibleRSAFunction?params;
          8????params.GenerateRandomWithKeySize(rng,?bits);
          9
          10????//?創(chuàng)建密鑰對(duì)
          11????m_rsaPrivateKey?=?params;
          12????m_rsaPublicKey?=?params;
          13}

          手動(dòng)設(shè)置和獲取公鑰:

          1const?std::string?okcrypt::GetRSAPublicKey()
          2{
          3????std::string?pubKey;
          4????StringSink?ss(pubKey);
          5????m_rsaPublicKey.Save(ss);
          6
          7????return?pubKey;
          8}
          9
          10void?okcrypt::SetRSAPublicKey(std::string&?key)
          11{
          12????StringSink?ss(key);
          13????m_rsaPublicKey.Load(ss);
          14}

          公鑰加密,私鑰解密:

          1void?okcrypt::EncryptRSA(std::string?const&?plainData,?std::string?&cipherData)
          2{
          3????//?偽隨機(jī)數(shù)生成器
          4????AutoSeededRandomPool?rng;
          5
          6????//?加密器
          7????RSAES_OAEP_SHA_Encryptor?e(m_rsaPublicKey);
          8
          9????StringSource?ss(plainData,?true,
          10????????new?PK_EncryptorFilter(rng,?e,?new?StringSink(cipherData)
          )
          11????)
          ;
          12}
          13
          14void?okcrypt::DecryptRSA(std::string?const&?cipherData,?std::string?&recoveredData)
          15{
          16????//?偽隨機(jī)數(shù)生成器
          17????AutoSeededRandomPool?rng;
          18
          19????//?解密器
          20????RSAES_OAEP_SHA_Decryptor?d(m_rsaPrivateKey);
          21
          22????StringSource?ss(cipherData,?true,
          23????????new?PK_DecryptorFilter(rng,?d,?new?StringSink(recoveredData)
          )
          24????)
          ;
          25}

          6

          okcrypt的使用

          克隆到本地:

          git clone https://github.com/gxkey/okcrypt.git

          其中包含已編譯好的cryptopp,目標(biāo)機(jī)器msvc2019,包含目錄okcrypt,lib目錄okcrypt/lib。其它編譯器可能要自己重新編譯cryptopp。
          只需包含okcrypt.h,就能使用,樣例代碼如下:

          1#include?
          2#include?"okcrypt.h"
          3
          4void?PrintEncrypt(const?char*?algo,?const?std::string&?hexCipherData)?{
          5????std::cout?<"加密結(jié)果:\n"?<std::endl;
          6????std::cout?<"----------------------------------\n";
          7}
          8
          9void?PrintDecrypt(const?char*?algo,?const?std::string&?hexCipherData)?{
          10????std::cout?<"解密結(jié)果:\n"?<std::endl;
          11????std::cout?<"----------------------------------\n";
          12}
          13
          14int?main()
          15
          {
          16????std::string?plain{?"plain?data"?};
          17
          18????std::cout?<"原始數(shù)據(jù):"?<"\n-----\n";
          19
          20????PrintEncrypt("MD5",?okcrypt::EncryptMD5(plain));
          21????PrintEncrypt("Base64",?okcrypt::EncryptBase64(plain));
          22????PrintEncrypt("SHA256",?okcrypt::EncryptSHA256(plain));
          23????PrintEncrypt("SHA512",?okcrypt::EncryptSHA512(plain));
          24????PrintEncrypt("SHA3-256",?okcrypt::EncryptSHA3_256(plain));
          25????PrintEncrypt("SHA3-512",?okcrypt::EncryptSHA3_512(plain));
          26
          27????try?{
          28????????//?DES
          29????????std::string?cipher;
          30????????std::string?recovered;
          31????????okcrypt::InitalizeDESKey();
          32????????std::cout?<"des?key:?"?<std::endl;
          33????????okcrypt::EncryptDES("text?will?be?encryped?with?des",?cipher);
          34????????PrintEncrypt("DES",?okcrypt::ToHex(cipher));
          35????????okcrypt::DecryptDES(cipher,?recovered);
          36????????PrintDecrypt("DES",?recovered);
          37
          38????????cipher.clear();
          39????????recovered.clear();
          40
          41????????//?3DES
          42????????okcrypt::Initalize3DESKey();
          43????????std::cout?<"3des?key:?"?<std::endl;
          44????????okcrypt::Encrypt3DES("text?will?be?encryped?with?3des",?cipher);
          45????????PrintEncrypt("3DES",?okcrypt::ToHex(cipher));
          46????????okcrypt::Decrypt3DES(cipher,?recovered);
          47????????PrintDecrypt("3DES",?recovered);
          48
          49????????cipher.clear();
          50????????recovered.clear();
          51
          52????????//?AES
          53????????okcrypt::InitalizeAESKey();
          54????????std::cout?<"aes?key:?"?<std::endl;
          55????????okcrypt::EncryptAES("text?will?be?encrypted?with?aes",?cipher);
          56????????PrintEncrypt("AES",?okcrypt::ToHex(cipher));
          57????????okcrypt::DecryptAES(cipher,?recovered);
          58????????PrintDecrypt("AES",?recovered);
          59
          60????????cipher.clear();
          61????????recovered.clear();
          62
          63????????//?RSA
          64????????okcrypt::InitalizeRSAKeys();
          65????????std::cout?<"rsa?public?key:?"?<std::endl;
          66????????okcrypt::EncryptRSA("text?will?be?encrypted?with?rsa",?cipher);
          67????????PrintEncrypt("RSA",?okcrypt::ToHex(cipher));
          68????????okcrypt::DecryptRSA(cipher,?recovered);
          69????????PrintDecrypt("RSA",?recovered);
          70????}
          71????catch?(const?CryptoPP::Exception&?e)
          72????{
          73????????std::cerr?<"Error:?"?<std::endl;
          74????}
          75
          76
          77????std::cin.get();
          78????return?0;
          79}

          輸出結(jié)果:
          其它沒(méi)加的算法,以后會(huì)抽時(shí)間再加到okcrypt,本篇就到這里吧。

          瀏覽 29
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人在线大香蕉免费 | 日韩精品人妻中文字幕蜜乳 | 国产理论在线观看 | 黄伊人大香蕉 | 狠狠撸日日撸 |