iOS逆向開發(fā):密碼學(xué) HASH

前言

最近看了一篇關(guān)于逆向?qū)崙?zhàn)的文章:來談?wù)刬OS逆向工程之App脫殼请琳,比起理論還是實(shí)戰(zhàn)更有趣,覺得還不錯(cuò)分享給大家看看阵翎,參考參考裆赵。
好 話不多說东囚,開始本篇文章的主題吧。

1. HASH算法簡(jiǎn)介

1.1 HASH是什么战授?

(多文字預(yù)警)

  • Hash算法(也叫散列算法)

Hash页藻,一般翻譯做“散列”,也有直接音譯為“哈现怖迹”的沪猴,就是把任意長(zhǎng)度的輸入通過散列算法變換成固定長(zhǎng)度的輸出,該輸出就是散列值饮怯。這種轉(zhuǎn)換是一種壓縮映射帘腹,也就是,散列值的空間通常遠(yuǎn)小于輸入的空間筒繁,不同的輸入可能會(huì)散列成相同的輸出噩凹,所以不可能從散列值來確定唯一的輸入值。簡(jiǎn)單的說就是一種將任意長(zhǎng)度的消息壓縮到某一固定長(zhǎng)度的消息摘要的函數(shù)

先舉個(gè)例子毡咏。我們每個(gè)活在世上的人驮宴,為了能夠參與各種社會(huì)活動(dòng),都需要一個(gè)用于識(shí)別自己的標(biāo)志呕缭。也許你覺得名字或是身份證就足以代表你這個(gè)人堵泽,但是這種代表性非常脆弱修己,因?yàn)橹孛娜撕芏啵矸葑C也可以偽造迎罗。最可靠的辦法是把一個(gè)人的所有基因序列記錄下來用來代表這個(gè)人睬愤,但顯然,這樣做并不實(shí)際纹安。而指紋看上去是一種不錯(cuò)的選擇尤辱,雖然一些專業(yè)組織仍然可以模擬某個(gè)人的指紋,但這種代價(jià)實(shí)在太高了钻蔑。
而對(duì)于在互聯(lián)網(wǎng)世界里傳送的文件來說啥刻,如何標(biāo)志一個(gè)文件的身份同樣重要。比如說我們下載一個(gè)文件咪笑,文件的下載過程中會(huì)經(jīng)過很多網(wǎng)絡(luò)服務(wù)器可帽、路由器的中轉(zhuǎn),如何保證這個(gè)文件就是我們所需要的呢窗怒?我們不可能去一一檢測(cè)這個(gè)文件的每個(gè)字節(jié)映跟,也不能簡(jiǎn)單地利用文件名、文件大小這些極容易偽裝的信息扬虚,這時(shí)候努隙,我們就需要一種指紋一樣的標(biāo)志來檢查文件的可靠性,這種指紋就是我們現(xiàn)在所用的Hash算法(也叫散列算法)辜昵。

  • 散列算法(Hash Algorithm)荸镊,又稱哈希算法,雜湊算法堪置,是一種從任意文件中創(chuàng)造小的數(shù)字「指紋」的方法躬存。與指紋一樣,散列算法就是一種以較短的信息來保證文件唯一性的標(biāo)志舀锨,這種標(biāo)志與文件的每一個(gè)字節(jié)都相關(guān)岭洲,而且難以找到逆向規(guī)律。因此坎匿,當(dāng)原有文件發(fā)生改變時(shí)盾剩,其標(biāo)志值也會(huì)發(fā)生改變,從而告訴文件使用者當(dāng)前的文件已經(jīng)不是你所需求的文件替蔬。
  1. 這種標(biāo)志有何意義呢告私?
    之前文件下載過程就是一個(gè)很好的例子,事實(shí)上承桥,現(xiàn)在大部分的網(wǎng)絡(luò)部署和版本控制工具都在使用散列算法來保證文件可靠性驻粟。而另一方面,我們?cè)谶M(jìn)行文件系統(tǒng)同步快毛、備份等工具時(shí)格嗅,使用散列算法來標(biāo)志文件唯一性能幫助我們減少系統(tǒng)開銷,這一點(diǎn)在很多云存儲(chǔ)服務(wù)器中都有應(yīng)用唠帝。
  2. 當(dāng)然屯掖,作為一種指紋,散列算法最重要的用途在于給證書襟衰、文檔贴铜、密碼等高安全系數(shù)的內(nèi)容添加加密保護(hù)。這一方面的用途主要是得益于散列算法的不可逆性瀑晒,這種不可逆性體現(xiàn)在绍坝,你不僅不可能根據(jù)一段通過散列算法得到的指紋來獲得原有的文件,也不可能簡(jiǎn)單地創(chuàng)造一個(gè)文件并讓它的指紋與一段目標(biāo)指紋相一致苔悦。散列算法的這種不可逆性維持著很多安全框架的運(yùn)營(yíng)轩褐,

1.2 Hash的特點(diǎn)

  1. 算法是公開的

  2. 對(duì)相同數(shù)據(jù)運(yùn)算,得到的結(jié)果是一樣的

  3. 對(duì)不同數(shù)據(jù)運(yùn)算,如MD5得到的結(jié)果默認(rèn)是128位,32個(gè)字符(16進(jìn)制標(biāo)識(shí))。

  4. 沒法逆運(yùn)算

  5. 一個(gè)優(yōu)秀的 hash 算法玖详,將能實(shí)現(xiàn):

  1. 正向快速:給定明文和 hash 算法把介,在有限時(shí)間和有限資源內(nèi)能計(jì)算出 hash 值。
  2. 逆向困難:給定(若干) hash 值蟋座,在有限時(shí)間內(nèi)很難(基本不可能)逆推出明文拗踢。
  3. 輸入敏感:原始輸入信息修改一點(diǎn)信息,產(chǎn)生的 hash 值看起來應(yīng)該都有很大不同向臀。
  4. 沖突避免:很難找到兩段內(nèi)容不同的明文巢墅,使得它們的 hash 值一致(發(fā)生沖突)。即對(duì)于任意兩個(gè)不同的數(shù)據(jù)塊券膀,其hash值相同的可能性極芯摇;對(duì)于一個(gè)給定的數(shù)據(jù)塊三娩,找到和它hash值相同的數(shù)據(jù)塊極為困難庵芭。

1.3 Hash的作用

  • 主要用途有:
  1. 用戶密碼的加密
  2. 搜索引擎
  3. 版權(quán)
  4. 數(shù)字簽名
  • Hash在在密碼學(xué)中的應(yīng)用

在密碼學(xué)中,hash算法的作用主要是用于消息摘要和簽名雀监,換句話說双吆,它主要用于對(duì)整個(gè)消息的完整性進(jìn)行校驗(yàn)。舉個(gè)例子会前,我們登陸知乎的時(shí)候都需要輸入密碼好乐,那么知乎如果明文保存這個(gè)密碼,那么黑客就很容易竊取大家的密碼來登陸瓦宜,特別不安全蔚万。那么知乎就想到了一個(gè)方法,使用hash算法生成一個(gè)密碼的簽名临庇,知乎后臺(tái)只保存這個(gè)簽名值反璃。由于hash算法是不可逆的昵慌,那么黑客即便得到這個(gè)簽名,也絲毫沒有用處淮蜈;而如果你在網(wǎng)站登陸界面上輸入你的密碼斋攀,那么知乎后臺(tái)就會(huì)重新計(jì)算一下這個(gè)hash值,與網(wǎng)站中儲(chǔ)存的原h(huán)ash值進(jìn)行比對(duì)梧田,如果相同淳蔼,證明你擁有這個(gè)賬戶的密碼,那么就會(huì)允許你登陸裁眯。銀行也是如此鹉梨,銀行是萬(wàn)萬(wàn)不敢保存用戶密碼的原文的,只會(huì)保存密碼的hash值而而已穿稳。在這些應(yīng)用場(chǎng)景里存皂,對(duì)于抗碰撞和抗篡改能力要求極高,對(duì)速度的要求在其次司草。一個(gè)設(shè)計(jì)良好的hash算法艰垂,其抗碰撞能力是很高的。以MD5為例埋虹,其輸出長(zhǎng)度為128位猜憎,設(shè)計(jì)預(yù)期碰撞概率為2^128,這是一個(gè)極小極小的數(shù)字——而即便是在MD5被王小云教授破解之后搔课,其碰撞概率上限也高達(dá)胰柑,也就是說,至少需要找次才能有1/2的概率來找到一個(gè)與目標(biāo)文件相同的hash值爬泥。

1.4 Hash有哪些流行的算法

  • 目前流行的 Hash 算法包括 MD5柬讨、SHA-1 和 SHA-2。

  • MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年設(shè)計(jì)的袍啡,MD 是 Message Digest 的縮寫踩官。其輸出為 128 位。MD4 已證明不夠安全境输。

  • MD5(RFC 1321)是 Rivest 于1991年對(duì) MD4 的改進(jìn)版本蔗牡。它對(duì)輸入仍以 512 位分組,其輸出是 128 位嗅剖。MD5 比 MD4 復(fù)雜辩越,并且計(jì)算速度要慢一點(diǎn),更安全一些信粮。MD5 已被證明不具備"強(qiáng)抗碰撞性"黔攒。

  • SHA (Secure Hash Algorithm)是一個(gè) Hash 函數(shù)族,由 NIST(National Institute of Standards and Technology)于 1993 年發(fā)布第一個(gè)算法。目前知名的 SHA-1 在 1995 年面世督惰,它的輸出為長(zhǎng)度 160 位的 hash 值不傅,因此抗窮舉性更好。SHA-1 設(shè)計(jì)時(shí)基于和 MD4 相同原理赏胚,并且模仿了該算法蛤签。SHA-1 已被證明不具"強(qiáng)抗碰撞性"。

  • 為了提高安全性栅哀,NIST 還設(shè)計(jì)出了 SHA-224、SHA-256称龙、SHA-384留拾,和 SHA-512 算法(統(tǒng)稱為 SHA-2),跟 SHA-1 算法原理類似鲫尊。SHA-3 相關(guān)算法也已被提出痴柔。

1.5 Hash算法的碰撞

  • 如果我們隨便拿9個(gè)數(shù)去計(jì)算,肯定至少會(huì)得到兩個(gè)相同的值疫向,我們把這種情況就叫做散列算法的「碰撞」(Collision)

這很容易理解咳蔚,因?yàn)樽鳛橐环N可用的散列算法,其位數(shù)一定是有限的搔驼,也就是說它能記錄的文件是有限的——而文件數(shù)量是無(wú)限的谈火,兩個(gè)文件指紋發(fā)生碰撞的概率永遠(yuǎn)不會(huì)是零。
但這并不意味著散列算法就不能用了舌涨,因?yàn)榉彩露家紤]代價(jià)糯耍,買光所有彩票去中一次頭獎(jiǎng)是毫無(wú)意義的。現(xiàn)代散列算法所存在的理由就是囊嘉,它的不可逆性能在較大概率上得到實(shí)現(xiàn)温技,也就是說,發(fā)現(xiàn)碰撞的概率很小扭粱,這種碰撞能被利用的概率更小舵鳞。
隨意找到一組碰撞是有可能的,只要窮舉就可以琢蛤。散列算法得到的指紋位數(shù)是有限的蜓堕,比如MD5算法指紋字長(zhǎng)為128位,意味著只要我們窮舉2^128次虐块,就肯定能得到一組碰撞——當(dāng)然俩滥,這個(gè)時(shí)間代價(jià)是難以想象的,而更重要的是贺奠,僅僅找到一組碰撞并沒有什么實(shí)際意義霜旧。更有意義的是,如果我們已經(jīng)有了一組指紋,能否找到一個(gè)原始文件挂据,讓它的散列計(jì)算結(jié)果等于這組指紋以清。如果這一點(diǎn)被實(shí)現(xiàn),我們就可以很容易地篡改和偽造網(wǎng)絡(luò)證書崎逃、密碼等關(guān)鍵信息掷倔。
你也許已經(jīng)聽過MD5已經(jīng)被破解的新聞——但事實(shí)上,即便是MD5這種已經(jīng)過時(shí)的散列算法个绍,也很難實(shí)現(xiàn)逆向運(yùn)算勒葱。我們現(xiàn)在更多的還是依賴于海量字典來進(jìn)行嘗試,也就是通過已經(jīng)知道的大量的文件——指紋對(duì)應(yīng)關(guān)系巴柿,搜索某個(gè)指紋所對(duì)應(yīng)的文件是否在數(shù)據(jù)庫(kù)里存在凛虽。

1.6 MD5簡(jiǎn)介

  • MD5的應(yīng)用

MD5的典型應(yīng)用是對(duì)一段信息(Message)產(chǎn)生信息摘要(Message-Digest),以防止被篡改广恢。比如凯旋,在UNIX下有很多軟件在下載的時(shí)候都有一個(gè)文件名相同,文件擴(kuò)展名為.md5的文件钉迷,在這個(gè)文件中通常只有一行文本至非,大致結(jié)構(gòu)如:
MD5 (tanajiya.tar.gz) = 0ca175b9c0f726a831d895e269332461
這就是tanajiya.tar.gz文件的數(shù)字簽名。MD5將整個(gè)文件當(dāng)作一個(gè)大文本信息糠聪,通過其不可逆的字符串變換算法援岩,產(chǎn)生了這個(gè)唯一的MD5信息摘要葵蒂。
大家都知道,地球上任何人都有自己獨(dú)一無(wú)二的指紋,這常常成為公安機(jī)關(guān)鑒別罪犯身份最值得信賴的方法罚斗;與之類似窒升,MD5就可以為任何文件(不管其大小奈附、格式缚够、數(shù)量)產(chǎn)生一個(gè)同樣獨(dú)一無(wú)二的“數(shù)字指紋”,如果任何人對(duì)文件名做了任何改動(dòng)题造,其MD5值也就是對(duì)應(yīng)的“數(shù)字指紋”都會(huì)發(fā)生變化傍菇。
我們常常在某些軟件下載站點(diǎn)的某軟件信息中看到其MD5值,它的作用就在于我們可以在下載該軟件后界赔,對(duì)下載回來的文件用專門的軟件(如Windows MD5 Check等)做一次MD5校驗(yàn)丢习,以確保我們獲得的文件與該站點(diǎn)提供的文件為同一文件。利用MD5算法來進(jìn)行文件校驗(yàn)的方案被大量應(yīng)用到軟件下載站淮悼、論壇數(shù)據(jù)庫(kù)咐低、系統(tǒng)文件安全等方面。
MD5的典型應(yīng)用是對(duì)一段Message(字節(jié)串)產(chǎn)生fingerprint(指紋)袜腥,以防止被“篡改”见擦。舉個(gè)例子,你將一段話寫在一個(gè)叫 readme.txt文件中,并對(duì)這個(gè)readme.txt產(chǎn)生一個(gè)MD5的值并記錄在案鲤屡,然后你可以傳播這個(gè)文件給別人损痰,別人如果修改了文件中的任何內(nèi)容,你對(duì)這個(gè)文件重新計(jì)算MD5時(shí)就會(huì)發(fā)現(xiàn)(兩個(gè)MD5值不相同)酒来。如果再有一個(gè)第三方的認(rèn)證機(jī)構(gòu)卢未,用MD5還可以防止文件作者的“抵賴”,這就是所謂的數(shù)字簽名應(yīng)用堰汉。
MD5還廣泛用于操作系統(tǒng)的登陸認(rèn)證上辽社,如Unix、各類BSD系統(tǒng)登錄密碼翘鸭、數(shù)字簽名等諸多方爹袁。如在UNIX系統(tǒng)中用戶的密碼是以MD5(或其它類似的算法)經(jīng)Hash運(yùn)算后存儲(chǔ)在文件系統(tǒng)中。當(dāng)用戶登錄的時(shí)候矮固,系統(tǒng)把用戶輸入的密碼進(jìn)行MD5 Hash運(yùn)算,然后再去和保存在文件系統(tǒng)中的MD5值進(jìn)行比較譬淳,進(jìn)而確定輸入的密碼是否正確档址。通過這樣的步驟,系統(tǒng)在并不知道用戶密碼的明碼的情況下就可以確定用戶登錄系統(tǒng)的合法性邻梆。這可以避免用戶的密碼被具有系統(tǒng)管理員權(quán)限的用戶知道守伸。MD5將任意長(zhǎng)度的“字節(jié)串”映射為一個(gè)128bit的大整數(shù),并且是通過該128bit反推原始字符串是困難的浦妄,換句話說就是尼摹,即使你看到源程序和算法描述,也無(wú)法將一個(gè)MD5的值變換回原始的字符串剂娄,從數(shù)學(xué)原理上說蠢涝,是因?yàn)樵嫉淖址袩o(wú)窮多個(gè),這有點(diǎn)象不存在反函數(shù)的數(shù)學(xué)函數(shù)阅懦。所以和二,要遇到了md5密碼的問題,比較好的辦法是:你可以用這個(gè)系統(tǒng)中的md5()函數(shù)重新設(shè)一個(gè)密碼惯吕,如admin,把生成的一串密碼的Hash值覆蓋原來的Hash值就行了怕午。

1.6.1 MD5 加密

  • MD5在線加密網(wǎng)站
    image.png
  • 由于MD5加密是不可逆的废登,所以正常無(wú)法破解,
    但是由于有前面說到的散列碰撞存在郁惜,所以有了破解的方式堡距。

1.6.2 MD5 破解

  • 有一個(gè)很出名的網(wǎng)站https://cmd5.com/ 收錄了很多md5值,可以在線查看MD5的原始值。

    image.png

  • 剛剛md5加密123456得到了:32位大寫的MD5值:E10ADC3949BA59ABBE56E057F20F883E

  • 現(xiàn)在在解密網(wǎng)站上面驗(yàn)證


    image.png

2. 對(duì)稱加密, 非對(duì)稱加密, HMAC

2.1 HMAC

  • 上面講解了hash算法和用途吏颖,hash算法在密碼學(xué)上面可以用來加密搔体,如服務(wù)器認(rèn)證賬號(hào)信息時(shí),根本不需要知道密碼是什么半醉,只需要驗(yàn)證密碼的md5值就可以了疚俱。
  • 一般使用hash加密的方式主要有:
  1. 直接使用MD5
  2. MD5加鹽
  3. HMAC加密方案
  • HMAC: HMAC不是一種加密算法,而是一種加密方案缩多。使用一個(gè)密鑰加密呆奕,并且做了兩次散列。在實(shí)際開發(fā)中衬吆,密鑰來自于服務(wù)器梁钾。每個(gè)賬號(hào)匹配一個(gè)密鑰。

  • HMAC 加密方案的過程:

1逊抡、客戶端填寫一個(gè)賬號(hào)姆泻,發(fā)給服務(wù)端驗(yàn)證。服務(wù)端返回一個(gè)隨機(jī)數(shù)給客戶端冒嫡。
2拇勃、此隨機(jī)數(shù)就是HMAC的key⌒⒘瑁客戶端的密碼使用這個(gè)key加密方咆,然后把這個(gè)加密之后的hash值發(fā)個(gè)客戶端◇凹埽客戶端保存這個(gè)key瓣赂。
3、服務(wù)端保存客服端發(fā)送過來的hash值片拍。這個(gè)hash值只會(huì)傳輸一次煌集。在注冊(cè)或換手機(jī)登錄的情況下傳輸。
4捌省、以后的每次登錄驗(yàn)證都是用這個(gè)hash值加上服務(wù)端時(shí)間戳(精確到分)牙勘,然后再hash一次,得到新的hash發(fā)送給服務(wù)端所禀。服務(wù)端用它保存的hash值也加上服務(wù)端時(shí)間方面,然后再hash一次,用得到的hash和客戶端發(fā)送過來的hash比對(duì)色徘。比對(duì)這一分鐘和上一分鐘恭金,只要有一個(gè)比對(duì)成功,就算成功褂策。
5横腿、有一種情況颓屑,客戶端換了手機(jī)且開啟了設(shè)備驗(yàn)證,向服務(wù)端要key耿焊。服務(wù)器會(huì)先向授權(quán)設(shè)備發(fā)起是否授權(quán)揪惦,授權(quán)通過發(fā)送key,授權(quán)不通過不發(fā)送key罗侯。

2.2 對(duì)稱加密

  • 什么是對(duì)稱加密器腋?

對(duì)稱加密(也叫私鑰加密)指加密和解密使用相同密鑰的加密算法。有時(shí)又叫傳統(tǒng)密碼算法钩杰,就是加密密鑰能夠從解密密鑰中推算出來纫塌,同時(shí)解密密鑰也可以從加密密鑰中推算出來。而在大多數(shù)的對(duì)稱算法中讲弄,加密密鑰和解密密鑰是相同的措左,所以也稱這種加密算法為秘密密鑰算法或單密鑰算法。它要求發(fā)送方和接收方在安全通信之前避除,商定一個(gè)密鑰怎披。對(duì)稱算法的安全性依賴于密鑰,泄漏密鑰就意味著任何人都可以對(duì)他們發(fā)送或接收的消息解密瓶摆,所以密鑰的保密性對(duì)通信性至關(guān)重要凉逛。

  • 對(duì)稱加密的優(yōu)點(diǎn)

對(duì)稱加密算法的特點(diǎn)是算法公開、計(jì)算量小赏壹、加密速度快、加密效率高

  • 對(duì)稱加密算法的缺點(diǎn)衔沼?
  1. 要求提供一條安全的渠道使通訊雙方在首次通訊時(shí)協(xié)商一個(gè)共同的密鑰蝌借。直接的面對(duì)面協(xié)商可能是不現(xiàn)實(shí)而且難于實(shí)施的,所以雙方可能需要借助于郵件和電話等其它相對(duì)不夠安全的手段來進(jìn)行協(xié)商指蚁;
  2. 密鑰的數(shù)目難于管理菩佑。因?yàn)閷?duì)于每一個(gè)合作者都需要使用不同的密鑰,很難適應(yīng)開放社會(huì)中大量的信息交流凝化;
  3. 對(duì)稱加密算法一般不能提供信息完整性的鑒別稍坯。它無(wú)法驗(yàn)證發(fā)送者和接受者的身份;
  4. 對(duì)稱密鑰的管理和分發(fā)工作是一件具有潛在危險(xiǎn)的和煩瑣的過程搓劫。對(duì)稱加密是基于共同保守秘密來實(shí)現(xiàn)的瞧哟,采用對(duì)稱加密技術(shù)的貿(mào)易雙方必須保證采用的是相同的密鑰,保證彼此密鑰的交換是安全可靠的枪向,同時(shí)還要設(shè)定防止密鑰泄密和更改密鑰的程序勤揩。

2.2.1 常用的對(duì)稱加密算法

  • 常用對(duì)稱加密算法主要有:DES算法,3DES算法秘蛔,TDEA算法陨亡,Blowfish算法傍衡,RC5算法,IDEA算法负蠕。

DES: 數(shù)據(jù)加密標(biāo)準(zhǔn)蛙埂,但是用的少,因?yàn)閺?qiáng)調(diào)低
3DES: 使用3個(gè)蜜鑰遮糖,對(duì)相同的數(shù)據(jù)執(zhí)行3次加密绣的。
AES: 高級(jí)加密標(biāo)準(zhǔn),如我們蘋果系統(tǒng)里鑰匙串訪問用的就是AES加密止吁。美國(guó)安全局也是用的AES 加密被辑。

  • 對(duì)稱加密算法原理

對(duì)稱加密算法的優(yōu)點(diǎn)在于加解密的高速度和使用長(zhǎng)密鑰時(shí)的難破解性。假設(shè)兩個(gè)用戶需要使用對(duì)稱加密方法加密然后交換數(shù)據(jù)敬惦,則用戶最少需要2個(gè)密鑰并交換使用盼理,如果企業(yè)內(nèi)用戶有n個(gè),則整個(gè)企業(yè)共需要n×(n-1) 個(gè)密鑰俄删,密鑰的生成和分發(fā)將成為企業(yè)信息部門的惡夢(mèng)宏怔。對(duì)稱加密算法的安全性取決于加密密鑰的保存情況,但要求企業(yè)中每一個(gè)持有密鑰的人都保守秘密是不可能的畴椰,他們通常會(huì)有意無(wú)意的把密鑰泄漏出去–如果一個(gè)用戶使用的密鑰被入侵者所獲得臊诊,入侵者便可以讀取該用戶密鑰加密的所有文檔,如果整個(gè)企業(yè)共用一個(gè)加密密鑰斜脂,那整個(gè)企業(yè)文檔的保密性便無(wú)從談起抓艳。

  • DES加密算法: 對(duì)稱加密算法中最經(jīng)典的算法莫過于DES加密算法。DES加密采用的是分組加密的方法帚戳,使用56位密鑰加密64位明文玷或,最后產(chǎn)生64位密文。DES算法的基本流程如下:
    image.png
  1. DES對(duì)64位的明文分組M進(jìn)行操作片任,M經(jīng)過一個(gè)初始置換IP置換成m0偏友,將m0明文分成左半部分和右半部分m0=(L0,R0),各32位長(zhǎng)对供。然后進(jìn)行16輪完全相同的運(yùn)算位他,這些運(yùn)算稱為函數(shù)f,在運(yùn)算過程中产场,數(shù)據(jù)與密匙結(jié)合鹅髓。經(jīng)過16輪運(yùn)算之后,可以看到第16輪運(yùn)算京景,將右側(cè)第15輪運(yùn)算的結(jié)果(R15)作為左側(cè)運(yùn)算的最終結(jié)果(L16)迈勋,而右側(cè)最后的結(jié)果(R16)為左側(cè)第15輪運(yùn)算結(jié)果(L15)和函數(shù)f運(yùn)算結(jié)果的異或運(yùn)算所得。此后醋粟,再將左靡菇、右部分合在一起經(jīng)過一個(gè)逆置換重归,輸出密文。
  2. 實(shí)際加密過程要分成兩個(gè)同時(shí)進(jìn)行的過程厦凤,即加密過程和密鑰生成過程:


    image.png
  3. 在16輪循環(huán)的每一輪中鼻吮,密匙位移位,然后再?gòu)拿艹椎?4位中選出48位较鼓。通過一個(gè)擴(kuò)展置換將數(shù)據(jù)的右半部分?jǐn)U展成48位椎木,并通過一個(gè)異或操作替代成新的32位數(shù)據(jù),在將其置換一次博烂。這四步運(yùn)算構(gòu)成了圖6-2中的函數(shù)f香椎。然后,通過另一個(gè)異或運(yùn)算禽篱,函數(shù)f的輸出與左半部分結(jié)合畜伐,其結(jié)果成為新的右半部分,原來的右半部分成為新的左半部分躺率。該操作重復(fù)16次玛界。
  4. DES算法的解密過程和加密過程幾乎完全相同,只是使用密鑰的順序相反悼吱。
  5. NIST(National Institute of Standards and Technology慎框,美國(guó)國(guó)家標(biāo)準(zhǔn)技術(shù)研究院)在1999年發(fā)布了新的DES加密標(biāo)準(zhǔn),3DES取代DES成為新的加密標(biāo)準(zhǔn)后添。3DES采用168位的密鑰笨枯,三重加密节榜,但速度較慢价说。之后,又出現(xiàn)了AES(Advanced Encryption Standard谬墙,先進(jìn)加密標(biāo)準(zhǔn))等高級(jí)對(duì)稱機(jī)密算法努溃。
  • TripleDES加密算法
  1. 由于DES算法安全性方面的原因硫嘶,為了提高DES算法的抗攻擊性阻问,因此提出了Triple-DES算法梧税。
  2. Triple-DES算法的基本原理是:用兩個(gè)密鑰對(duì)數(shù)據(jù)進(jìn)行3次加密/解密運(yùn)算。即首先使用第一個(gè)密鑰對(duì)數(shù)據(jù)進(jìn)行加密称近,然后用第二個(gè)密鑰對(duì)其進(jìn)行解密第队,最后用第一個(gè)密鑰再加密。這兩個(gè)密鑰可以是同一個(gè)刨秆,也可以不同凳谦,它們也可以來源于一個(gè)128位密鑰,只是在加密/解密時(shí)將其分割成兩個(gè)64位的密鑰衡未,分別輪換使用這兩個(gè)64位密鑰去完成加密/解密運(yùn)算尸执。Triple-DES算法保留了DES算法運(yùn)算速度快的特點(diǎn)家凯,通過增加運(yùn)算次數(shù)和密鑰長(zhǎng)度(兩個(gè)64位密鑰相當(dāng)于128位密鑰)來增加破解者的破解時(shí)間,但是從密碼學(xué)本身來說如失,其安全強(qiáng)度并沒有增加绊诲。
  • RC系列算法:
  1. 現(xiàn)在我們用到的RC系列算法包括RC2、RC4褪贵、RC5掂之、RC6算法,其中RC4是序列密碼算法脆丁,其他三種是分組密碼算法世舰。
  2. RC2算法: 該算法設(shè)計(jì)的目的是用來取代DES算法,它采用密鑰長(zhǎng)度可變的對(duì)明文采取64位分組的分組加密算法槽卫,屬于Festel網(wǎng)絡(luò)結(jié)構(gòu)跟压。
  3. RC4算法: 該算法是一個(gè)密鑰長(zhǎng)度可變的面向字節(jié)流的加密算法,以隨機(jī)置換為基礎(chǔ)晒夹。該算法執(zhí)行速度快裆馒,每輸出1字節(jié)的結(jié)果僅需要816字節(jié)的機(jī)器指令。RC4算法比較容易描述丐怯,它首先用82048位可變長(zhǎng)度的密鑰初始化一個(gè)256字節(jié)的狀態(tài)矢量S喷好。S的成員標(biāo)記為S[0],S[1],…读跷,S[255]梗搅,整個(gè)置換過程都包含0~255的8比特?cái)?shù)。對(duì)于加密和解密效览,設(shè)字節(jié)數(shù)據(jù)為K无切,由S中256個(gè)元素按一定方式選出一個(gè)元素生成,每生成一個(gè)K值丐枉,元素中的數(shù)據(jù)就要被重新置換一次哆键。
  • Rijndael算法:
  1. Rijndael是一個(gè)反復(fù)運(yùn)算的加密算法,它允許可變動(dòng)的數(shù)據(jù)區(qū)塊及密鑰的長(zhǎng)度瘦锹。數(shù)據(jù)區(qū)塊與密鑰長(zhǎng)度的變動(dòng)是各自獨(dú)立的籍嘹。
  2. 在Rijndael算法中定義了兩個(gè)名詞:
    State:在運(yùn)算過程中所產(chǎn)生的中間值,是一個(gè)4×Nb的矩陣弯院,Nb可由數(shù)據(jù)長(zhǎng)度除以32位求得辱士,也就是把數(shù)據(jù)分割成Nb個(gè)區(qū)塊。
    Cipher Key:用來做加密運(yùn)算的密鑰听绳,形式是一個(gè)4×Nk的矩陣颂碘,Nk可由金鑰長(zhǎng)度除以32位求得,也就是把密鑰分割成Nk個(gè)32位的子密鑰椅挣。
  3. 在Rijndael算法中头岔,運(yùn)算的回合數(shù)(Nr)是由Nb及Nk決定的

2.3 非對(duì)稱加密

  • 什么是非對(duì)稱加密塔拳?

非對(duì)稱加密:指加密和解密使用不同密鑰的加密算法。非對(duì)稱加密算法需要兩個(gè)密鑰:公鑰(publickey)和私鑰(privatekey)峡竣。
公鑰與私鑰是一對(duì)存在蝙斜,如果用公鑰對(duì)數(shù)據(jù)進(jìn)行加密,只有用對(duì)應(yīng)的私鑰才能解密澎胡;如果用密鑰對(duì)數(shù)據(jù)進(jìn)行加密孕荠,那么只有用對(duì)應(yīng)的公鑰才能解密。因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同的密鑰攻谁,所以這種算法叫作非對(duì)稱加密算法稚伍。
非對(duì)稱加密又稱為現(xiàn)代加密,而對(duì)稱加密又稱為傳統(tǒng)加密戚宦,因?yàn)橐郧岸际鞘褂脤?duì)稱加密的

  • 非對(duì)稱加密的特點(diǎn):

非對(duì)稱密碼體制的特點(diǎn):算法強(qiáng)度復(fù)雜个曙、安全性依賴于算法與密鑰但是由于其算法復(fù)雜,而使得加密解密速度沒有對(duì)稱加密解密的速度快受楼。對(duì)稱密碼體制中只有一種密鑰垦搬,并且是非公開的,如果要解密就得讓對(duì)方知道密鑰艳汽。所以保證其安全性就是保證密鑰的安全猴贰,而非對(duì)稱密鑰體制有兩種密鑰,其中一個(gè)是公開的河狐,這樣就可以不需要像對(duì)稱密碼那樣傳輸對(duì)方的密鑰了米绕。這樣安全性就大了很多。

  • 非對(duì)稱加密算法是一種密鑰的保密方法馋艺。

  • 非對(duì)稱加密的典型算法是RSA加密方式栅干,目前大部分銀行都是使用這種加密方式。更多RSA加密的詳情可以參考我前面的一篇博客:IOS 逆向開發(fā)(一)密碼學(xué) 非對(duì)稱加密RSA

  • 對(duì)稱加密和非對(duì)稱加密的對(duì)比

  1. 非對(duì)稱密碼體制的特點(diǎn):算法強(qiáng)度復(fù)雜捐祠、安全性依賴于算法與密鑰但是由于其算法復(fù)雜碱鳞,而使得加密解密速度沒有對(duì)稱加密解密的速度快。
  2. 對(duì)稱密碼體制中只有一種密鑰踱蛀,并且是非公開的窿给,如果要解密就得讓對(duì)方知道密鑰,所以保證其安全性就是保證密鑰的安全星岗。而非對(duì)稱密鑰體制有兩種密鑰填大,其中一個(gè)是公開的戒洼,這樣就可以不需要像對(duì)稱密碼那樣傳輸對(duì)方的密鑰了俏橘。這樣安全性就大了很多。
  3. 假設(shè)兩個(gè)用戶要加密交換數(shù)據(jù)圈浇,雙方交換公鑰寥掐,使用時(shí)一方用對(duì)方的公鑰加密靴寂,另一方即可用自己的私鑰解密。
  4. 如果企業(yè)中有n個(gè)用戶召耘,企業(yè)需要生成n對(duì)密鑰百炬,并分發(fā)n個(gè)公鑰。由于公鑰是可以公開的污它,用戶只要保管好自己的私鑰即可剖踊,因此加密密鑰的分發(fā)將變得 十分簡(jiǎn)單。同時(shí)衫贬,由于每個(gè)用戶的私鑰是唯一的德澈,其他用戶除了可以通過"信息發(fā)送者的公鑰"來驗(yàn)證信息的來源是否真實(shí),還可以確保發(fā)送者無(wú)法否認(rèn)曾發(fā)送過該信息固惯。非對(duì)稱加密的缺點(diǎn)是加解密速度要遠(yuǎn)遠(yuǎn)慢于對(duì)稱加密梆造,在某些極端情況下,甚至能比對(duì)稱加密慢上1000倍葬毫。
  5. 非對(duì)稱的好處顯而易見镇辉,非對(duì)稱加密體系不要求通信雙方事先傳遞密鑰或有任何約定就能完成保密通信,并且密鑰管理方便贴捡,可實(shí)現(xiàn)防止假冒和抵賴忽肛,因此,更適合網(wǎng)絡(luò)通信中的保密通信要求烂斋。
  • 總的說來麻裁,有以下幾點(diǎn):
  1. 對(duì)稱加密加密與解密使用的是同樣的密鑰,所以速度快源祈,但由于需要將密鑰在網(wǎng)絡(luò)傳輸煎源,所以安全性不高。
  2. 非對(duì)稱加密使用了一對(duì)密鑰香缺,公鑰與私鑰手销,所以安全性高,但加密與解密速度慢图张。
  3. 常用解決的辦法是將對(duì)稱加密的密鑰使用非對(duì)稱加密的公鑰進(jìn)行加密锋拖,然后發(fā)送出去,接收方使用私鑰進(jìn)行解密得到對(duì)稱加密的密鑰祸轮,然后雙方可以使用對(duì)稱加密來進(jìn)行溝通兽埃。這就是在HTTPS中使用的方式。

2.3.1 非對(duì)稱加密算法

  • RSA适袜、Elgamal柄错、背包算法、Rabin、HD,ECC(橢圓曲線加密算法)售貌。
  • 使用最廣泛的是RSA算法给猾,Elgamal是另一種常用的非對(duì)稱加密算法。
  • Elgamal由Taher Elgamal于1985年發(fā)明颂跨,其基礎(chǔ)是DiffieˉHellman密鑰交換算法敢伸,后者使通信雙方能通過公開通信來推導(dǎo)出只有他們知道的秘密密鑰值[DiffieˉHellman]。DiffieˉHellman是Whitfield Diffie和Martin Hellman于1976年發(fā)明的恒削,被視為第一種 非對(duì)稱加密算法池颈,DiffieˉHellman 與RSA的不同之處在于,DiffieˉHellman不是加密算法钓丰,它只是生成可用作對(duì)稱密鑰的秘密數(shù)值饶辙。在DiffieˉHellman密鑰交換過程中,發(fā)送方和接收方分別生成一個(gè)秘密的隨機(jī)數(shù)斑粱,并根據(jù)隨機(jī)數(shù)推導(dǎo)出公開值弃揽,然后,雙方再交換公開值则北。DiffieˉHellman算法的基礎(chǔ)是具備生成共享密鑰的能力矿微。只要交換了公開值,雙方就能使用自己的私有數(shù)和對(duì)方的公開值來生成對(duì)稱密鑰尚揣,稱為共享密鑰涌矢,對(duì)雙方來說,該對(duì)稱密鑰是相同的快骗,可以用于使用對(duì)稱加密算法加密數(shù)據(jù)娜庇。
  • 與RSA相比,DiffieˉHellman的優(yōu)勢(shì)之一是每次交換密鑰時(shí)都使用一組新值方篮,而使用RSA算法時(shí)名秀,如果攻擊者獲得了私鑰,那么他不僅能解密之前截獲的消息藕溅,還能解密之后的所有消息匕得。然而,RSA可以通過認(rèn)證(如使用X.509數(shù)字證書)來防止中間人攻擊巾表,但Diff ieˉHellman在應(yīng)對(duì)中間人攻擊時(shí)非常脆弱汁掠。

2.3.2 完整的非對(duì)稱加密過程

  • 假如現(xiàn)在 你向支付寶 轉(zhuǎn)賬(術(shù)語(yǔ)數(shù)據(jù)信息),為了保證信息傳送的保密性集币、真實(shí)性考阱、完整性和不可否認(rèn)性,需要對(duì)傳送的信息進(jìn)行數(shù)字加密和簽名鞠苟,其傳送過程為:
  1. 首先你要確認(rèn)是否是支付寶的數(shù)字證書乞榨,如果確認(rèn)為支付寶身份后秽之,則對(duì)方真實(shí)可信〗啵可以向?qū)Ψ絺魉托畔ⅲ?/li>
  2. 你準(zhǔn)備好要傳送的數(shù)字信息(明文)計(jì)算要轉(zhuǎn)的多少錢,對(duì)方支付寶賬號(hào)等趾访;
  3. 你 對(duì)數(shù)字信息進(jìn)行哈希運(yùn)算态秧,得到一個(gè)信息摘要(客戶端主要職責(zé));
  4. 你用自己的私鑰對(duì)信息摘要進(jìn)行加密得到 你 的數(shù)字簽名扼鞋,并將其附在數(shù)字信息上申鱼;
  5. 你隨機(jī)產(chǎn)生一個(gè)加密密鑰,并用此密碼對(duì)要發(fā)送的信息進(jìn)行加密(密文)云头;
  6. 你用 支付寶的公鑰對(duì)剛才隨機(jī)產(chǎn)生的加密密鑰進(jìn)行加密捐友,將加密后的 DES 密鑰連同密文一起傳送給支付寶;
  7. 支付寶收到 你 傳送來的密文和加密過的 DES 密鑰溃槐,先用自己的私鑰對(duì)加密的 DES 密鑰進(jìn)行解密匣砖,得到 你隨機(jī)產(chǎn)生的加密密鑰;
  8. 支付寶 然后用隨機(jī)密鑰對(duì)收到的密文進(jìn)行解密昏滴,得到明文的數(shù)字信息猴鲫,然后將隨機(jī)密鑰拋棄;
  9. 支付寶 用你 的公鑰對(duì) 你的的數(shù)字簽名進(jìn)行解密谣殊,得到信息摘要拂共;
  10. 支付寶用相同的哈希算法對(duì)收到的明文再進(jìn)行一次哈希運(yùn)算,得到一個(gè)新的信息摘要姻几;
  11. 支付寶將收到的信息摘要和新產(chǎn)生的信息摘要進(jìn)行比較宜狐,如果一致,說明收到的信息沒有被修改過蛇捌;
  12. 確定收到信息抚恒,然后進(jìn)行向?qū)Ψ竭M(jìn)行付款交易,一次非對(duì)稱密過程結(jié)束络拌。

2.3.3 對(duì)稱加密的應(yīng)用模式

  • ECB(Electronic Code Book):電子密碼本模式柑爸。每一塊數(shù)據(jù),獨(dú)立加密盒音。

最基本的加密模式表鳍,也就是通常理解的加密,相同的明文將永遠(yuǎn)加密成相同的密文祥诽,無(wú)初始向量譬圣,容易受到密碼本重放攻擊勇凭,一般情況下很少用责语。

  • CBC(Cipher Block Chaining):密碼分組鏈接模式繁堡。使用一個(gè)密鑰和一個(gè)初始化向量[IV]對(duì)數(shù)據(jù)執(zhí)行加密。

明文被加密前要與前面的密文進(jìn)行異或運(yùn)算后再加密殊校,因此只要選擇不同的初始向量,相同的密文加密后會(huì)形成不同的密文佃牛,這是目前應(yīng)用最廣泛的模式她按。CBC加密后的密文是上下文相關(guān)的,但明文的錯(cuò)誤不會(huì)傳遞到后續(xù)分組飘庄,但如果一個(gè)分組丟失脑蠕,后面的分組將全部作廢(同步錯(cuò)誤)。

2.3.3.1 終端驗(yàn)證

  • 終端輸入:vi message.txt
  • 通過vi編輯文字信息如下:


    image.png
  • 按“esc”鍵跪削,然后輸入:wq保存
  • 然后終端輸入:openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out msg1.bin 將message.txt 通過ECB(Electronic Code Book):電子密碼本模式谴仙。每一塊數(shù)據(jù),獨(dú)立加密碾盐。輸出的結(jié)果保存到msg1.bin文件里面晃跺。
    image.png

注意:上述加密命令中616263是加密的key,-nosalt是表示不加鹽。

  • 輸出后毫玖,我們可以看到生成了msg1.bin文件:


    image.png
  • 然后我們稍微修改一下message.txt文件:


    image.png
  • 然后重新輸入:openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out msg2.bin進(jìn)行加密掀虎,生成msg2.bin文件。

  • 接下來我們查看一下msg1.bin和msg2.bin有什么區(qū)別

  • 我們使用命令xxd msg1.bin查看:

    image.png

  • 只修改了一個(gè)數(shù)字付枫,但是整個(gè)塊8個(gè)字節(jié)都不一樣了涩盾,說明是一塊塊進(jìn)行加密的。

  • 接下來励背,我們輸入:openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in message.txt -out msg3.bin 得到加密文件msg3.bin

    image.png

  • 然后我們?cè)傩薷囊幌略嘉募essage.txt,將2改回1


    image.png

    image.png
  • 接下來春霍,我們輸入:openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in message.txt -out msg4.bin 得到加密文件msg4.bin

    image.png

  • 然后我們通過xxd msg3.bin,xxd msg4.bin來查看對(duì)比msg3.bin和msg4.bin文件。

    image.png

  • 由此可以看出叶眉,CBC(Cipher Block Chaining):密碼分組鏈接模式址儒。使用一個(gè)密鑰和一個(gè)初始化向量[IV]對(duì)數(shù)據(jù)執(zhí)行加密。加密時(shí)是密碼鏈條衅疙。

3. 數(shù)字簽名

  • 什么是數(shù)字簽名莲趣?
  1. 數(shù)字簽名:是將摘要信息用發(fā)送者的私鑰加密,與原文一起傳送給接收者饱溢。接收者只有用發(fā)送者的公鑰才能解密被加密的摘要信息喧伞,然后用HASH函數(shù)對(duì)收到的原文產(chǎn)生一個(gè)摘要信息,與解密的摘要信息對(duì)比绩郎。
  2. 如果相同潘鲫,則說明收到的信息是完整的,在傳輸過程中沒有被修改肋杖;
    否則說明信息被修改過溉仑,因此數(shù)字簽名能夠驗(yàn)證信息的完整性。
    如果中途數(shù)據(jù)被纂改或者丟失状植。那么對(duì)方就可以根據(jù)數(shù)字簽名來辨別是否是來自對(duì)方的第一手信息數(shù)據(jù)浊竟。
  3. 數(shù)字簽名是個(gè)加密的過程怨喘,數(shù)字簽名驗(yàn)證是個(gè)解密的過程
  4. 數(shù)字簽名用來,保證信息傳輸?shù)耐暾哉穸āl(fā)送者的身份認(rèn)證必怜、防止交易中的抵賴發(fā)生。
  5. 非對(duì)稱加密算法實(shí)現(xiàn)機(jī)密信息交換的基本過程是:甲方生成一對(duì)密鑰并將其中的一把作為公用密鑰向其它方公開后频;得到該公用密鑰的乙方使用該密鑰對(duì)機(jī)密信息進(jìn)行加密后再發(fā)送給甲方梳庆;甲方再用自己保存的另一把專用密鑰對(duì)加密后的信息進(jìn)行解密。
  • 什么是數(shù)字證書
  1. 數(shù)字證書:就是互聯(lián)網(wǎng)通訊中標(biāo)志通訊各方身份信息的一串?dāng)?shù)字徘郭,提供了一種在Internet上驗(yàn)證通信實(shí)體身份的方式靠益,數(shù)字證書不是數(shù)字身份證丧肴,而是身份認(rèn)證機(jī)構(gòu)蓋在數(shù)字身份證上的一個(gè)章或硬腥唷(或者說加在數(shù)字身份證上的一個(gè)簽名)。
  2. 它是由權(quán)威機(jī)構(gòu)——CA機(jī)構(gòu)芋浮,又稱為證書授權(quán)(Certificate Authority)中心發(fā)行的抱环,人們可以在網(wǎng)上用它來識(shí)別對(duì)方的身份。
  3. 數(shù)字證書綁定了公鑰及其持有者的真實(shí)身份纸巷,它類似于現(xiàn)實(shí)生活中的居民身份證镇草,所不同的是數(shù)字證書不再是紙質(zhì)的證照,而是一段含有證書持有者身份信息并經(jīng)過認(rèn)證中心審核簽發(fā)的電子數(shù)據(jù)瘤旨,廣泛用在電子商務(wù)和移動(dòng)互聯(lián)網(wǎng)中梯啤。

3.1 數(shù)字前面在HTTPS協(xié)議中的應(yīng)用

  • 瀏覽器中簽名證書認(rèn)證中的對(duì)稱加密和非對(duì)稱加密混合應(yīng)用
  1. 瀏覽器向服務(wù)器發(fā)出請(qǐng)求,詢問對(duì)方支持的對(duì)稱加密算法和非對(duì)稱加密算法存哲;服務(wù)器回應(yīng)自己支持的算法因宇。
  2. 瀏覽器選擇雙方都支持的加密算法,并請(qǐng)求服務(wù)器出示自己的證書祟偷;服務(wù)器回應(yīng)自己的證書察滑。
  3. 瀏覽器隨機(jī)產(chǎn)生一個(gè)用于本次會(huì)話的對(duì)稱加密的鑰匙,并使用服務(wù)器證書中附帶的公鑰對(duì)該鑰匙進(jìn)行加密后傳遞給服務(wù)器修肠;服務(wù)器為本次會(huì)話保持該對(duì)稱加密的鑰匙贺辰。第三方不知道服務(wù)器的私鑰,即使截獲了數(shù)據(jù)也無(wú)法解密嵌施。非對(duì)稱加密讓任何瀏覽器都可以與服務(wù)器進(jìn)行加密會(huì)話饲化。
  4. 瀏覽器使用對(duì)稱加密的鑰匙對(duì)請(qǐng)求消息加密后傳送給服務(wù)器,服務(wù)器使用該對(duì)稱加密的鑰匙進(jìn)行解密吗伤;服務(wù)器使用對(duì)稱加密的鑰匙對(duì)響應(yīng)消息加密后傳送給瀏覽器滓侍,瀏覽器使用該對(duì)稱加密的鑰匙進(jìn)行解密。第三方不知道對(duì)稱加密的鑰匙牲芋,即使截獲了數(shù)據(jù)也無(wú)法解密撩笆。對(duì)稱加密提高了加密速度 捺球。

3.1.1 HTTPS中的SSL流程:

  1. 為了提高安全性,我們常用的做法是使用對(duì)稱加密的手段加密數(shù)據(jù)夕冲〉可是只使用對(duì)稱加密的話,雙方通信的開始總會(huì)以明文的方式傳輸密鑰歹鱼。那么從一開始這個(gè)密鑰就泄露了泣栈,談不上什么安全。所以 TLS/SSL 在握手的階段弥姻,結(jié)合非對(duì)稱加密的手段南片,保證只有通信雙方才知道對(duì)稱加密的密鑰。大概的流程如下:


    image.png

    CA證書驗(yàn)證過程:


    image.png

    image.png
  • SSL/TLS 握手過程


    image.png
  • Client Hello: 握手第一步是客戶端向服務(wù)端發(fā)送 Client Hello 消息庭敦,這個(gè)消息里包含了一個(gè)客戶端生成的隨機(jī)數(shù) Random1疼进、客戶端支持的加密套件(Support Ciphers)和 SSL Version 等信息。通過 Wireshark 抓包秧廉,我們可以看到如下信息:


    image.png
  • Server Hello: 第二步是服務(wù)端向客戶端發(fā)送 Server Hello 消息伞广,這個(gè)消息會(huì)從 Client Hello 傳過來的 Support Ciphers 里確定一份加密套件,這個(gè)套件決定了后續(xù)加密和生成摘要時(shí)具體使用哪些算法疼电,另外還會(huì)生成一份隨機(jī)數(shù) Random2嚼锄。注意,至此客戶端和服務(wù)端都擁有了兩個(gè)隨機(jī)數(shù)(Random1+ Random2)蔽豺,這兩個(gè)隨機(jī)數(shù)會(huì)在后續(xù)生成對(duì)稱秘鑰時(shí)用到区丑。


    image.png
  • Certificate: 這一步是服務(wù)端將自己的證書下發(fā)給客戶端,讓客戶端驗(yàn)證自己的身份修陡,客戶端驗(yàn)證通過后取出證書中的公鑰沧侥。


    image.png
  • Server Key Exchange: 如果是DH算法,這里發(fā)送服務(wù)器使用的DH參數(shù)濒析。RSA算法不需要這一步正什。


    image.png
  • Certificate Request: Certificate Request 是服務(wù)端要求客戶端上報(bào)證書,這一步是可選的号杏,對(duì)于安全性要求高的場(chǎng)景會(huì)用到婴氮。

  • Server Hello Done: Server Hello Done 通知客戶端 Server Hello 過程結(jié)束。


    image.png
  • Certificate Verify:客戶端收到服務(wù)端傳來的證書后盾致,先從 CA 驗(yàn)證該證書的合法性主经,驗(yàn)證通過后取出證書中的服務(wù)端公鑰,再生成一個(gè)隨機(jī)數(shù) Random3庭惜,再用服務(wù)端公鑰非對(duì)稱加密 Random3 生成 PreMaster Key罩驻。

  • Client Key Exchange: 上面客戶端根據(jù)服務(wù)器傳來的公鑰生成了 PreMaster Key,Client Key Exchange 就是將這個(gè) key 傳給服務(wù)端护赊,服務(wù)端再用自己的私鑰解出這個(gè) PreMaster Key 得到客戶端生成的 Random3惠遏。至此砾跃,客戶端和服務(wù)端都擁有 Random1 + Random2 + Random3,兩邊再根據(jù)同樣的算法就可以生成一份秘鑰节吮,握手結(jié)束后的應(yīng)用層數(shù)據(jù)都是使用這個(gè)秘鑰進(jìn)行對(duì)稱加密抽高。為什么要使用三個(gè)隨機(jī)數(shù)呢?這是因?yàn)?SSL/TLS 握手過程的數(shù)據(jù)都是明文傳輸?shù)耐讣ǎ⑶叶鄠€(gè)隨機(jī)數(shù)種子來生成秘鑰不容易被暴力破解出來翘骂。客戶端將 PreMaster Key 傳給服務(wù)端的過程如下圖所示:


    image.png
  • Change Cipher Spec(Client):這一步是客戶端通知服務(wù)端后面再發(fā)送的消息都會(huì)使用前面協(xié)商出來的秘鑰加密了帚豪,是一條事件消息:


    image.png
  • Encrypted Handshake Message(Client): 這一步對(duì)應(yīng)的是 Client Finish 消息碳竟,客戶端將前面的握手消息生成摘要再用協(xié)商好的秘鑰加密,這是客戶端發(fā)出的第一條加密消息狸臣。服務(wù)端接收后會(huì)用秘鑰解密莹桅,能解出來說明前面協(xié)商出來的秘鑰是一致的。


    image.png
  • Change Cipher Spec(Server):這一步是服務(wù)端通知客戶端后面再發(fā)送的消息都會(huì)使用加密固棚,也是一條事件消息统翩。

  • Encrypted Handshake Message(Server):這一步對(duì)應(yīng)的是 Server Finish 消息仙蚜,服務(wù)端也會(huì)將握手過程的消息生成摘要再用秘鑰加密此洲,這是服務(wù)端發(fā)出的第一條加密消息∥郏客戶端接收后會(huì)用秘鑰解密呜师,能解出來說明協(xié)商的秘鑰是一致的。


    image.png
  • Application Data: 到這里贾节,雙方已安全地協(xié)商出了同一份秘鑰汁汗,所有的應(yīng)用層數(shù)據(jù)都會(huì)用這個(gè)秘鑰加密后再通過 TCP 進(jìn)行可靠傳輸。

3.1.2 HTTPS中的雙向驗(yàn)證

  • 雙向驗(yàn)證流程圖:


    image.png

4. 對(duì)稱加密終端演練

  • 終端測(cè)試指令
  1. 加密:
    AES(ECB)加密“hello”字符串:
    echo -n hello | openssl enc-aes-128-ecb -K 616263 -nosalt | base64 AES(CBC)加密“hello”字符串: * echo -n hello | openssl enc-aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
  2. 解密:
    AES(ECB)解密:
    echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc-aes-128-ecb -K 616263 -nosalt –d AES(CBC)解密: echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc-aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt –d
  • DES(ECB)加密
    終端輸入命令
 echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64

加密后結(jié)果輸出為:HQr0Oij2kbo=


image.png
  • DES(CBC)加密

終端輸入命令

echo -n hello | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64

加密后結(jié)果:alvrvb3Gz88=


image.png
  • AES(ECB)加密

終端輸入命令

  echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64

加密后結(jié)果:d1QG4T2tivoi0Kiu3NEmZQ==


image.png
  • AES(CBC)加密

終端輸入命令

  echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64

加密后結(jié)果:u3W/N816uzFpcg6pZ+kbdg==


image.png
  • DES(ECB)解密

終端輸入命令

  echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d

解密后結(jié)果:


image.png
  • DES(CBC)解密

終端輸入命令

  echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d

加密后結(jié)果:


image.png
  • AES(ECB)解密

終端輸入命令

  echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d

加密后結(jié)果:


image.png
  • AES(CBC)解密

終端輸入命令

 echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d

加密后結(jié)果:


image.png

5. 對(duì)稱加密實(shí)戰(zhàn)

5.1 Hash加密代碼

  • 本篇博客涉及Demo代碼地址:Hash加密算法demo

  • 新建一個(gè)NSString擴(kuò)展類:NSString+Hash

NSString+Hash.h文件

//
//  NSString+Hash.h
//  001-KEncryDemo
//
//  Created by 孔雨露 on 2019/12/14.
//  Copyright ? 2019 Apple. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSString (Hash) 
#pragma mark - 散列函數(shù)
    /**
     *  計(jì)算MD5散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  md5 -s "string"
     *  @endcode
     *
     *  <p>提示:隨著 MD5 碰撞生成器的出現(xiàn)栗涂,MD5 算法不應(yīng)被用于任何軟件完整性檢查或代碼簽名的用途知牌。<p>
     *
     *  @return 32個(gè)字符的MD5散列字符串
     */
- (NSString *)md5String;
    
    /**
     *  計(jì)算SHA1散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  echo -n "string" | openssl sha -sha1
     *  @endcode
     *
     *  @return 40個(gè)字符的SHA1散列字符串
     */
- (NSString *)sha1String;
    
    /**
     *  計(jì)算SHA256散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  echo -n "string" | openssl sha -sha256
     *  @endcode
     *
     *  @return 64個(gè)字符的SHA256散列字符串
     */
- (NSString *)sha256String;
    
    /**
     *  計(jì)算SHA 512散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  echo -n "string" | openssl sha -sha512
     *  @endcode
     *
     *  @return 128個(gè)字符的SHA 512散列字符串
     */
- (NSString *)sha512String;
    
#pragma mark - HMAC 散列函數(shù)
    /**
     *  計(jì)算HMAC MD5散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  echo -n "string" | openssl dgst -md5 -hmac "key"
     *  @endcode
     *
     *  @return 32個(gè)字符的HMAC MD5散列字符串
     */
- (NSString *)hmacMD5StringWithKey:(NSString *)key;
    
    /**
     *  計(jì)算HMAC SHA1散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  echo -n "string" | openssl sha -sha1 -hmac "key"
     *  @endcode
     *
     *  @return 40個(gè)字符的HMAC SHA1散列字符串
     */
- (NSString *)hmacSHA1StringWithKey:(NSString *)key;
    
    /**
     *  計(jì)算HMAC SHA256散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  echo -n "string" | openssl sha -sha256 -hmac "key"
     *  @endcode
     *
     *  @return 64個(gè)字符的HMAC SHA256散列字符串
     */
- (NSString *)hmacSHA256StringWithKey:(NSString *)key;
    
    /**
     *  計(jì)算HMAC SHA512散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  echo -n "string" | openssl sha -sha512 -hmac "key"
     *  @endcode
     *
     *  @return 128個(gè)字符的HMAC SHA512散列字符串
     */
- (NSString *)hmacSHA512StringWithKey:(NSString *)key;
    
#pragma mark - 文件散列函數(shù)
    
    /**
     *  計(jì)算文件的MD5散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  md5 file.dat
     *  @endcode
     *
     *  @return 32個(gè)字符的MD5散列字符串
     */
- (NSString *)fileMD5Hash;
    
    /**
     *  計(jì)算文件的SHA1散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  openssl sha -sha1 file.dat
     *  @endcode
     *
     *  @return 40個(gè)字符的SHA1散列字符串
     */
- (NSString *)fileSHA1Hash;
    
    /**
     *  計(jì)算文件的SHA256散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  openssl sha -sha256 file.dat
     *  @endcode
     *
     *  @return 64個(gè)字符的SHA256散列字符串
     */
- (NSString *)fileSHA256Hash;
    
    /**
     *  計(jì)算文件的SHA512散列結(jié)果
     *
     *  終端測(cè)試命令:
     *  @code
     *  openssl sha -sha512 file.dat
     *  @endcode
     *
     *  @return 128個(gè)字符的SHA512散列字符串
     */
- (NSString *)fileSHA512Hash;
@end

NS_ASSUME_NONNULL_END

NSString+Hash.m文件

//
//  NSString+Hash.m
//  001-KEncryDemo
//
//  Created by 孔雨露 on 2019/12/14.
//  Copyright ? 2019 Apple. All rights reserved.
//

#import "NSString+Hash.h"
#import <CommonCrypto/CommonCrypto.h>

@implementation NSString (Hash)
#pragma mark - 散列函數(shù)
- (NSString *)md5String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    
    CC_MD5(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
    
- (NSString *)sha1String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
    
    CC_SHA1(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
    
- (NSString *)sha256String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
    
    CC_SHA256(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
    
- (NSString *)sha512String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
    
    CC_SHA512(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
    
#pragma mark - HMAC 散列函數(shù)
- (NSString *)hmacMD5StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
    
- (NSString *)hmacSHA1StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgSHA1, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
    
- (NSString *)hmacSHA256StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgSHA256, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
    
- (NSString *)hmacSHA512StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgSHA512, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
    
#pragma mark - 文件散列函數(shù)
    
#define FileHashDefaultChunkSizeForReadingData 4096
    
- (NSString *)fileMD5Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_MD5_CTX hashCtx;
    CC_MD5_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_MD5_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
    
- (NSString *)fileSHA1Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_SHA1_CTX hashCtx;
    CC_SHA1_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_SHA1_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
    
- (NSString *)fileSHA256Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_SHA256_CTX hashCtx;
    CC_SHA256_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_SHA256_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
    CC_SHA256_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
    
- (NSString *)fileSHA512Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_SHA512_CTX hashCtx;
    CC_SHA512_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_SHA512_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
    CC_SHA512_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
    
#pragma mark - 助手方法
    /**
     *  返回二進(jìn)制 Bytes 流的字符串表示形式
     *
     *  @param bytes  二進(jìn)制 Bytes 數(shù)組
     *  @param length 數(shù)組長(zhǎng)度
     *
     *  @return 字符串表示形式
     */
- (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length {
    NSMutableString *strM = [NSMutableString string];
    
    for (int i = 0; i < length; i++) {
        [strM appendFormat:@"%02x", bytes[i]];
    }
    
    return [strM copy];
}

@end

  • 新建一個(gè)加密工具類:


    image.png

KEncryptionTool.h文件:

//
//  KEncryptionTool.h
//  001-KylAppEncrypt
//
//  Created by 孔雨露 on 2019/12/14.
//  Copyright ? 2019 Apple. All rights reserved.
//
/**
*  終端測(cè)試指令
*
*  DES(ECB)加密
*  $ echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64
*
* DES(CBC)加密
*  $ echo -n hello | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
*
*  AES(ECB)加密
*  $ echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
*
*  AES(CBC)加密
*  $ echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
*
*  DES(ECB)解密
*  $ echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d
*
*  DES(CBC)解密
*  $ echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d
*
*  AES(ECB)解密
*  $ echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
*
*  AES(CBC)解密
*  $ echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d
*
*  提示:
*      1> 加密過程是先加密,再base64編碼
*      2> 解密過程是先base64解碼斤程,再解密
*/


#import <Foundation/Foundation.h>


NS_ASSUME_NONNULL_BEGIN

@interface KEncryptionTool : NSObject

    + (instancetype)shared;
    
    /**
     @constant   kCCAlgorithmAES     高級(jí)加密標(biāo)準(zhǔn)角寸,128位(默認(rèn))
     @constant   kCCAlgorithmDES     數(shù)據(jù)加密標(biāo)準(zhǔn)
     */
    @property (nonatomic, assign) uint32_t algorithm;
    
    /**
     *  加密字符串并返回base64編碼字符串
     *
     *  @param string    要加密的字符串
     *  @param keyString 加密密鑰
     *  @param iv        初始化向量(8個(gè)字節(jié))
     *
     *  @return 返回加密后的base64編碼字符串
     */

- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
    
    /**
     *  解密字符串
     *
     *  @param string    加密并base64編碼后的字符串
     *  @param keyString 解密密鑰
     *  @param iv        初始化向量(8個(gè)字節(jié))
     *
     *  @return 返回解密后的字符串
     */
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
@end

NS_ASSUME_NONNULL_END

KEncryptionTool.m文件:

//
//  KEncryptionTool.m
//  001-KylAppEncrypt
//
//  Created by 孔雨露 on 2019/12/14.
//  Copyright ? 2019 Apple. All rights reserved.
//



#import "KEncryptionTool.h"
#import <CommonCrypto/CommonCrypto.h>
@interface KEncryptionTool()
@property (nonatomic, assign) int keySize;
@property (nonatomic, assign) int blockSize;

@end


@implementation KEncryptionTool
+ (instancetype)shared {
    static KEncryptionTool *instance;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
        instance.algorithm = kCCAlgorithmAES;
    });
    
    return instance;
}
    
- (void)setAlgorithm:(uint32_t)algorithm {
    _algorithm = algorithm;
    switch (algorithm) {
        case kCCAlgorithmAES:
        self.keySize = kCCKeySizeAES128;
        self.blockSize = kCCBlockSizeAES128;
        break;
        case kCCAlgorithmDES:
        self.keySize = kCCKeySizeDES;
        self.blockSize = kCCBlockSizeDES;
        break;
        default:
        break;
    }
}
    
- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
    
    // 設(shè)置秘鑰
    NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t cKey[self.keySize];
    bzero(cKey, sizeof(cKey));
    [keyData getBytes:cKey length:self.keySize];
    
    // 設(shè)置iv
    uint8_t cIv[self.blockSize];
    bzero(cIv, self.blockSize);
    int option = 0;
    if (iv) {
        [iv getBytes:cIv length:self.blockSize];
        option = kCCOptionPKCS7Padding;
    } else {
        option = kCCOptionPKCS7Padding | kCCOptionECBMode;
    }
    
    // 設(shè)置輸出緩沖區(qū)
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    size_t bufferSize = [data length] + self.blockSize;
    void *buffer = malloc(bufferSize);
    
    // 開始加密
    size_t encryptedSize = 0;
    //加密解密都是它 -- CCCrypt
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          self.algorithm,
                                          option,
                                          cKey,
                                          self.keySize,
                                          cIv,
                                          [data bytes],
                                          [data length],
                                          buffer,
                                          bufferSize,
                                          &encryptedSize);
    
    NSData *result = nil;
    if (cryptStatus == kCCSuccess) {
        result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
    } else {
        free(buffer);
        NSLog(@"[錯(cuò)誤] 加密失敗|狀態(tài)編碼: %d", cryptStatus);
    }
    
    return [result base64EncodedStringWithOptions:0];
}
    
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
    
    // 設(shè)置秘鑰
    NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t cKey[self.keySize];
    bzero(cKey, sizeof(cKey));
    [keyData getBytes:cKey length:self.keySize];
    
    // 設(shè)置iv
    uint8_t cIv[self.blockSize];
    bzero(cIv, self.blockSize);
    int option = 0;
    if (iv) {
        [iv getBytes:cIv length:self.blockSize];
        option = kCCOptionPKCS7Padding;//CBC 加密!
    } else {
        option = kCCOptionPKCS7Padding | kCCOptionECBMode;//ECB加密忿墅!
    }
    
    // 設(shè)置輸出緩沖區(qū)
    NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
    size_t bufferSize = [data length] + self.blockSize;
    void *buffer = malloc(bufferSize);
    
    // 開始解密
    size_t decryptedSize = 0;
    /**CCCrypt 對(duì)稱加密算法的核心函數(shù)(加密/解密)
     參數(shù):
     1扁藕、kCCEncrypt 加密/kCCDecrypt 解密
     2、加密算法疚脐、默認(rèn)的 AES/DES
     3亿柑、加密方式的選項(xiàng)
        kCCOptionPKCS7Padding | kCCOptionECBMode;//ECB加密!
        kCCOptionPKCS7Padding;//CBC 加密棍弄!
     4望薄、加密密鑰
     5疟游、密鑰長(zhǎng)度
     6、iv 初始化向量痕支,ECB 不需要指定
     7乡摹、加密的數(shù)據(jù)
     8、加密的數(shù)據(jù)長(zhǎng)度
     9采转、緩沖區(qū)(地址)聪廉,存放密文的
     10、緩沖區(qū)的大小
     11故慈、加密結(jié)果大小
     */
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          self.algorithm,
                                          option,
                                          cKey,
                                          self.keySize,
                                          cIv,
                                          [data bytes],
                                          [data length],
                                          buffer,
                                          bufferSize,
                                          &decryptedSize);
    
    NSData *result = nil;
    if (cryptStatus == kCCSuccess) {
        result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
    } else {
        free(buffer);
        NSLog(@"[錯(cuò)誤] 解密失敗|狀態(tài)編碼: %d", cryptStatus);
    }
    
    return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
    
@end

  • 測(cè)試代碼:
- (void) testEncrpytion {
    /** AES - ECB */
    NSString * key = @"abc";
    NSString * encStr = [[KEncryptionTool shared] encryptString:@"hello" keyString:key iv:nil];
    
    NSLog(@"加密的結(jié)果是:%@",encStr);
    
    NSLog(@"解密的結(jié)果是:%@",[[KEncryptionTool shared] decryptString:encStr keyString:key iv:nil]);
    
    /** AES - CBC 加密 */
    uint8_t iv[8] = {1,2,3,4,5,6,7,8};
    NSData * ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
    
    
    
    NSLog(@"CBC加密:%@",[[KEncryptionTool shared] encryptString:@"hello" keyString:@"abc" iv:ivData]);
    
    NSLog(@"解密:%@",[[KEncryptionTool shared] decryptString:@"u3W/N816uzFpcg6pZ+kbdg==" keyString:key iv:ivData]);
}
  • 測(cè)試結(jié)果:


    image.png

收錄自|原文地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末板熊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子察绷,更是在濱河造成了極大的恐慌干签,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拆撼,死亡現(xiàn)場(chǎng)離奇詭異容劳,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)闸度,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門竭贩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人莺禁,你說我怎么就攤上這事留量。” “怎么了哟冬?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵楼熄,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我浩峡,道長(zhǎng)可岂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任翰灾,我火速辦了婚禮缕粹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘预侯。我一直安慰自己致开,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布萎馅。 她就那樣靜靜地躺著双戳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪糜芳。 梳的紋絲不亂的頭發(fā)上飒货,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天魄衅,我揣著相機(jī)與錄音,去河邊找鬼塘辅。 笑死晃虫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扣墩。 我是一名探鬼主播哲银,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼呻惕!你這毒婦竟也來了荆责?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤亚脆,失蹤者是張志新(化名)和其女友劉穎做院,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體濒持,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡键耕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了柑营。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屈雄。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖由境,靈堂內(nèi)的尸體忽然破棺而出棚亩,到底是詐尸還是另有隱情蓖议,我是刑警寧澤虏杰,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站勒虾,受9級(jí)特大地震影響纺阔,放射性物質(zhì)發(fā)生泄漏瓤湘。R本人自食惡果不足惜撞蚕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望聪富。 院中可真熱鬧愕宋,春花似錦玻靡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至邻寿,卻和暖如春蝎土,著一層夾襖步出監(jiān)牢的瞬間视哑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工誊涯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挡毅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓暴构,卻偏偏與公主長(zhǎng)得像跪呈,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子取逾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容