摘要:很明顯,非對(duì)稱加密的極大的消耗成了一種瓶頸。其中,利用非對(duì)稱加密的方案大概就是我前面說的那樣,偽代碼已經(jīng)展示過了。
其實(shí),前面兩篇翻來覆去只為叨逼叨叨逼叨兩件事情:
對(duì)稱加解密,典型算法有AES、DES、3DES等等
非對(duì)稱加解密,典型的算法有RSA、DSA、ECDH等等
但是,我知道大家最討厭在看這種文章的時(shí)候冒出來的一坨“橢圓曲線”、“素?cái)?shù)”、“質(zhì)數(shù)”等等這樣的玩意,反正看也看不懂,理解也理解不了,背也背不過,所以我索性就不寫這些玩意,一點(diǎn)兒都不寫,不裝任何逼(然而實(shí)際上我背過了,我最近一直在搞線性代數(shù),所以對(duì)數(shù)學(xué)比原來稍微敏感了一些)。
寫到這里后,就有刁民、php泥腿子自以為已經(jīng)掌握了高科技,隨便從github上扒兩個(gè)庫(kù)下來跑了跑test就開始四處裝逼,聲稱自己精通對(duì)稱加密算法和非對(duì)稱加密算法,尤其是在面試的時(shí)候,上去就是跟面試官一頓糊弄,糊弄住了就要5萬(wàn),糊弄不了要5千。然而我要告訴你的是,你應(yīng)該接繼續(xù)往下看,這樣的話你在面試的時(shí)候,糊弄住了就可以張口要8萬(wàn),糊弄不了也能最低要8千!比原來要5000整整多了3000!而且我提供的這份裝逼指南還是免費(fèi)的!
今天我們從一個(gè)實(shí)際需求作為出發(fā)點(diǎn),比如你是API開發(fā)人員(當(dāng)然了,作為只有十來個(gè)人的小公司,你還得兼職運(yùn)維,不過工資只按開發(fā)算,運(yùn)維的活兒算是你友情贊助給老板的),然后老板兼PM向你提出了一個(gè)比較嚴(yán)峻的問題,大概意思就是“公司的項(xiàng)目是個(gè)非常牛逼的項(xiàng)目,一年后公司是要上市的,你必須要加密了數(shù)據(jù),讓BAT和TMD都無法抄襲我們!然后你就能買車買房!”,你表示十分認(rèn)可。由于你已經(jīng)看過了我前面兩篇文章,再加上老板一再?gòu)?qiáng)調(diào)“我們這個(gè)是牛逼的項(xiàng)目,遲早要上市”,所以你就準(zhǔn)備用高安全性的非對(duì)稱加密來解決這個(gè)問題。
具體做法就是服務(wù)器生成一對(duì)公私鑰,然后再生成一對(duì)公私鑰給所有客戶端公用。比如用戶登陸API,接口文檔大概如下:
API : https://www.so.com/api/user/login METHOD : POST PROTOCOL : 將數(shù)據(jù)以JSON形式,全部放入到http body體中,key叫做mzip DATA : { "username" => "xitele", "password" => "qiangdadaoniyongyuancaibuchulaishiduoshao" }
然后客戶端執(zhí)行登陸的偽代碼如下:
var username string = "xitele" var password string = md5("123456") // 將數(shù)據(jù)生成json var data = jsonize( hashMap( "username" : username, "password" : password ) ) // 用服務(wù)器公鑰,將數(shù)據(jù)加密 var encryptData = RSA.encrypt( "服務(wù)端的公鑰", data ) // 再次封裝數(shù)據(jù)為json var lastJson = jsonize( hashMap( "mzip" => encryptData ) ) // 提交數(shù)據(jù) http.post( "https://www.so.com/api/user/login", lastJson, function() { // ... ... do something ... } )
服務(wù)器端使用世界上最好的語(yǔ)言來實(shí)現(xiàn)的,所以代碼你會(huì)覺得十分眼熟:
prepare( "select * from user where username=:username" ); $sth->bindParam( ":username", $aDecryptData["username"], PARAM_STR ); $pdo->execute(); $aUser = $pdo->fetch(); if ( $aUser["password"] != $aDecryptData["password"] ) { echo json_encode( array( "code" => 0, "msg" => "登陸成功" ) ); } else { echo json_encode( array( "code" => 10002, "msg" => "登陸失敗" ) ); }
上線后,發(fā)現(xiàn)倒也沒啥大問題了,就是明顯服務(wù)器CPU負(fù)載特別高,客戶端也感覺有點(diǎn)兒卡。很明顯,非對(duì)稱加密的CPU極大的消耗成了一種瓶頸。于是你找老板申請(qǐng)服務(wù)區(qū)費(fèi)用,老板當(dāng)場(chǎng)表示非常理解,大手一揮就給你批了300塊錢并表示隨意揮霍,把服務(wù)器升級(jí)成最牛逼的服務(wù)器。
當(dāng)然了,都跟我學(xué)習(xí)了這么久了你應(yīng)該馬上就意味到300塊代表著什么,300塊頂多代表能組兩個(gè)局兒... ...
當(dāng)然了,API那里也好交代,全線降級(jí)為AES對(duì)稱,CPU瞬間就下來了,又不是不能用.. ...
當(dāng)然了,300塊組個(gè)五人局兒應(yīng)該還是可以的,除了你和我,再拉上柱子跟老趙,最后再帶上陳旭,局兒上除了吃飯,就額外討論一下關(guān)于這個(gè)問題的解決方案。
局兒后,我神神秘秘地告訴你說“這特么簡(jiǎn)單,我給你講,你服務(wù)器先隨機(jī)生成一個(gè)AES對(duì)稱加密用的密鑰,然后利用客戶端的RSA公鑰加密后傳給客戶端,客戶端再通過自己的RSA私鑰解密得到這個(gè)AES對(duì)稱密鑰,然后再用這個(gè)AES對(duì)稱密鑰進(jìn)行后續(xù)的加解密即可,然后你可以給這個(gè)AES密鑰設(shè)定一個(gè)有效期,比如五分鐘,當(dāng)過期后,就再次利用上面的流程申請(qǐng)新的AES密鑰即可!這樣,不僅保證了AES密鑰的安全,還能解決了性能問題!”
鋪墊這么長(zhǎng),終于能扯出來今天的討論關(guān)鍵點(diǎn)了:密鑰協(xié)商/交換!這就是我們今天的核心話題了。
先說下為什么會(huì)出現(xiàn)密鑰協(xié)商和交換這種玩意,其實(shí)就是為了避免密鑰在網(wǎng)絡(luò)上的傳輸被劫持導(dǎo)致的安全問題,前兩句話的潛臺(tái)詞就是“這個(gè)世界上存在著一種即便我不告訴你,你也能知道我想告訴你什么的心有靈犀解決方案”。
密鑰協(xié)商交換一般常用的有如下幾種方案:
利用RSA等非對(duì)稱加密技術(shù)進(jìn)行交換,也就是300塊的局兒上那個(gè)方案
利用專門伺候密鑰交換需求的交換算法,比如DH算法,全稱叫做Diffie-Hellman密鑰交換。Diffie和Hellman分別是兩個(gè)大叔的名字(注意,此二位是數(shù)學(xué)家),是他們合伙搞出來的這個(gè)算法,DH算法先于RSA出現(xiàn)。
其中,利用非對(duì)稱加密的方案大概就是我前面說的那樣,偽代碼已經(jīng)展示過了。那么DH到底是個(gè)什么玩意呢?
下面我們玩一個(gè)比較簡(jiǎn)單的數(shù)字游戲:
1、元首和古德里安都同時(shí)選擇100這個(gè)數(shù)字,其他人知不知道無所謂 2、元首隨機(jī)出了一個(gè)數(shù)字9,然后將9乘以數(shù)字100,得到900,其他人能不能知道無所謂 3、古德里安隨機(jī)出了一個(gè)數(shù)3,然后將3乘以數(shù)字100,得到300,其他人能不能知道無所謂 4、元首將900扔給古德里安 5、古德里安將300扔給元首 到這里后,元首手里有的數(shù)據(jù)有100、9、300,古德里安手里的數(shù)據(jù)有100、3、900,然后兩個(gè)人此時(shí)只需要默默地做下面這一步: 元首:9 * 300 = 2700 古德里安:3 * 900 = 2700 OK了,就2700了
雙方都在僅僅是遠(yuǎn)遠(yuǎn)地確認(rèn)了一下眼神,說了一句話(彼此交換300和900),就已經(jīng)同時(shí)得到2700這個(gè)相同的數(shù)字。辣么,2700就是雙方后面進(jìn)行通信時(shí)候?qū)?shù)據(jù)進(jìn)行加密的密鑰了。同樣,雙方可以為這個(gè)密鑰算一個(gè)過期時(shí)間,比如五分鐘后,然后過期后重新協(xié)商出一個(gè)新的即可!而且,即便有其他人知道了雙方選擇的是100,也知道了元首給古德里安傳了900,也知道了古德里安給元首穿了300,然而并沒有什么卵用,因?yàn)樗€是不知道對(duì)方最終使用的密鑰(也就是2700)是多少。
當(dāng)然了,現(xiàn)實(shí)中真正的DH算法選擇公共數(shù)字、隨機(jī)數(shù)字可不是這么簡(jiǎn)單的,而且雙方最終計(jì)算這個(gè)密鑰的時(shí)候也不會(huì)像上面那個(gè)例子中那么輕松簡(jiǎn)單做一下乘法而已。
具體人家怎么算得,我就不寫了,反正網(wǎng)上到處都有,而且無論我寫出來還是不寫出來,反正你們都不看,畢竟,這玩意是數(shù)學(xué)家要搞的玩意。
RSA的庫(kù)前面我從github上扒過,也test過了,所以RSA就不演示了。然而,DH的咱們一起從github上扒一個(gè)下來玩玩來驗(yàn)證一下我們剛才講的簡(jiǎn)單理論。
PHP的一個(gè)DH庫(kù),GITHUB鏈接:https://github.com/jcink/diff...
將上述代碼保存為index.php,然后php index.php 32執(zhí)行一下,結(jié)果如下,你們感受一下:
我們看到這個(gè)庫(kù)順帶打印了一坨log,作為從來不研究底層的廣大泥腿子來說,我們只需要關(guān)注最后一行“Shared Key : 101451040”,這個(gè)就是服務(wù)端和客戶端協(xié)商出來的密鑰了,也就是意味著后面API的通信過程中使用101451040對(duì)數(shù)據(jù)加解密即可。
好了,以上是DH算法。其實(shí),圈里那些仁兄在看到今天標(biāo)題中含有DH的時(shí)候心里就應(yīng)該有數(shù)了,這傻逼天天在微信群里安利ECDH,今兒特么終于看到DH兩個(gè)字母了,總算有點(diǎn)兒眉毛了。辣么,我天天在群里安利的ECDH到底是什么玩意。
具體原理怎么回事,反正我這次是真是連背都背不過了,不過,你可以簡(jiǎn)單認(rèn)為ECDH是DH的升級(jí)版本,畢竟多了兩個(gè)字母。其實(shí)ECDH是ECC算法和DH算法二合一體,媽蛋,又特么冒出來一個(gè)ECC,好了好了,就當(dāng)我沒說。
然后還是老套路,我們從github上扒一個(gè)庫(kù)下來簡(jiǎn)單跑一下test,這樣以后就可以出去裝逼要8萬(wàn)工資了,傳送門:https://github.com/Querdos/EC...
computeSecret( $gudelian->getPublic() ); $gudelian->computeSecret( $xitele->getPublic() ); // shareKey1 和 shareKey2 就是協(xié)商出來的密鑰 $shareKey1 = $xitele->getSecret(); echo $shareKey1.PHP_EOL; $shareKey2 = $gudelian->getSecret(); echo $shareKey2.PHP_EOL; // 我們用gmp cmp來對(duì)比是否為同一個(gè)密鑰 if ( 0 == gmp_cmp( $shareKey1, $shareKey2 ) ) { echo "一樣".PHP_EOL; } else { echo "不一樣".PHP_EOL; } // 除此之外,這個(gè)ecdh庫(kù)比dh那個(gè)庫(kù)多了一個(gè)驗(yàn)證數(shù)據(jù)簽名驗(yàn)證,可以檢驗(yàn)數(shù)據(jù)是否被篡改! $msg = "hello world"; $signature = $xitele->signMessage( $msg ); if ( $gudelian->verifySignature( $signature, $xitele->getPublic(), $msg ) ) { echo "驗(yàn)證數(shù)據(jù)簽名成功".PHP_EOL; } else { echo "驗(yàn)證數(shù)據(jù)簽名失敗".PHP_EOL; } exit;將代碼保存為index.php,然后php index.php執(zhí)行結(jié)果如下圖所示:
通過上面代碼我們可以看出來,可以直接背誦一個(gè)結(jié)論,就是DH和ECDH都可以實(shí)現(xiàn)密鑰協(xié)商交換,但是ECDH還可以對(duì)數(shù)據(jù)進(jìn)行簽名,另一方可以對(duì)數(shù)據(jù)進(jìn)行驗(yàn)簽,從而可以判斷出數(shù)據(jù)在傳輸過程中是否被篡改!
好了,念念已久的ECDH終于入講了!以后我不會(huì)再在群里再叨叨這個(gè)了,祝你們幸福。
最近開了一個(gè)微信公眾號(hào):高性能API社區(qū),所有文章都先發(fā)這里
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/31422.html
摘要:這種神奇的算法可以讓你服務(wù)器和客戶端在不傳輸該對(duì)稱密鑰的情況下就可以通過心有靈犀地方式各自計(jì)算出一個(gè)對(duì)稱密鑰,而且可以一樣,避免了該密鑰在網(wǎng)絡(luò)上流通,而且你可以隨意更換,過期時(shí)間定為分鐘,可謂是狠毒至極我們引入就是為了解決上面的問題。 首先是前段時(shí)間我在公眾號(hào)里被人批(dui)評(píng)(gang)了,大概意思就是:你別老整那ECDH又是橢圓又是素?cái)?shù)啥的,你就說這玩意實(shí)際項(xiàng)目中怎么用就完了,我...
摘要:這種神奇的算法可以讓你服務(wù)器和客戶端在不傳輸該對(duì)稱密鑰的情況下就可以通過心有靈犀地方式各自計(jì)算出一個(gè)對(duì)稱密鑰,而且可以一樣,避免了該密鑰在網(wǎng)絡(luò)上流通,而且你可以隨意更換,過期時(shí)間定為分鐘,可謂是狠毒至極我們引入就是為了解決上面的問題。 首先是前段時(shí)間我在公眾號(hào)里被人批(dui)評(píng)(gang)了,大概意思就是:你別老整那ECDH又是橢圓又是素?cái)?shù)啥的,你就說這玩意實(shí)際項(xiàng)目中怎么用就完了,我...
摘要:由于密鑰被暴露了,所以必須換新的密鑰,元首這會(huì)兒只能走途徑告訴古德里安新的密鑰,這會(huì)兒逗逼的事情來了,如何對(duì)密鑰進(jìn)行加密。但是,有一點(diǎn)是值得說明,那就是無論是對(duì)稱加密還是非對(duì)稱加密,都頂不住用機(jī)器是強(qiáng)行暴力猜解私鑰。 懶漢 入門 這兩點(diǎn)就足以說明這篇文章不想要著有什么高端大氣的技術(shù)內(nèi)容,我跟你講,全是水。不可能有什么質(zhì)數(shù)素?cái)?shù)、橢圓曲線加密、迪菲-赫爾曼什么的,不可能有的。 首先我不...
摘要:實(shí)際上這一篇和上一篇均可以看作是關(guān)于加解密的懶漢入門篇安全加強(qiáng)篇一的后續(xù),只不過側(cè)重點(diǎn)在于安全上?;氐缴掀Y(jié)果提到的問題,就是對(duì)稱加密的安全性要人命,非對(duì)稱加密的性能非常要人命。元首作為高智商罪犯,這種低級(jí)錯(cuò)誤是不可能犯的。 為什么標(biāo)題總是要帶上API安全關(guān)鍵字呢?因?yàn)槲蚁胛覙芬狻?實(shí)際上這一篇和上一篇均可以看作是《關(guān)于PHP加解密的懶漢入門篇(API安全加強(qiáng)篇一)》》)的后續(xù),只不過...
摘要:實(shí)際上這一篇和上一篇均可以看作是關(guān)于加解密的懶漢入門篇安全加強(qiáng)篇一的后續(xù),只不過側(cè)重點(diǎn)在于安全上。回到上篇結(jié)果提到的問題,就是對(duì)稱加密的安全性要人命,非對(duì)稱加密的性能非常要人命。元首作為高智商罪犯,這種低級(jí)錯(cuò)誤是不可能犯的。 為什么標(biāo)題總是要帶上API安全關(guān)鍵字呢?因?yàn)槲蚁胛覙芬狻?實(shí)際上這一篇和上一篇均可以看作是《關(guān)于PHP加解密的懶漢入門篇(API安全加強(qiáng)篇一)》》)的后續(xù),只不過...
閱讀 489·2019-08-30 15:44
閱讀 903·2019-08-30 10:55
閱讀 2737·2019-08-29 15:16
閱讀 942·2019-08-29 13:17
閱讀 2810·2019-08-26 13:27
閱讀 578·2019-08-26 11:53
閱讀 2125·2019-08-23 18:31
閱讀 1893·2019-08-23 18:23