我發誓這真的是最後一篇關於ECDH的文兒!(API安全增強篇四)

首先是前段時間我在公衆號裏被人批(dui)評(gang)了,大概意思就是:你別老整那ECDH又是橢圓又是素數啥的,你就說這玩意實際項目中怎麼用就完了,咱們不想聽那些,那些咱們都懂都精通,並且你還太監了,你本身看看是否是太監了,ECDH寫到上一篇明顯還沒完,結果到如今了還沒下文,你本身說是否是太監了,你本身說。php

其次是實際上本篇內容實際上和ECDH沒有半毛錢關係,通篇都是DH(少了EC兩個字母),不過在項目中實際應用的業務邏輯寫法、道理都是同樣曬兒的。你如今能夠暫時認爲DH就是ECDH的「 少了兩個字母版本 」。用DH的最主要緣由是啥呢,由於時間有限,我優先寫了DH的經常使用語言庫文件,目前可用,ECDH的一根毛都沒有寫,因此只能用DH演示。node

最後是再次強調一遍,做爲一篇正經的文章,我須要再次科普一下DH是啥意思。git

不少都覺得DH是Daemon Hunter(惡魔獵手)的簡稱,然而並非。Daemon Hunter是真實名稱叫作伊利丹,是個瞎子同時又是法瑪麗奧(就是老鹿)的兄dei。他暗戀白虎(就是那種真的白虎)泰蘭德,然而泰蘭德卻嫁給了老鹿,事情大概就是這麼一回事。

在咱們這裏DH則是Diffie-Hellman的簡稱,二位大爺的照片我之前貼過,如今不得再也不貼一遍:程序員

上圖告訴咱們頭髮長短與職業無關,douyin上那些自覺得get到程序員梗的短視頻真的是LOWB到一塌糊塗。github

在正式開始前以前,我仍是要說明一下用DH的初衷是什麼或者說這個東西是來解決什麼問題的。接着上篇的故事(點擊這裏)說:redis

  • 你老闆說項目很是牛逼,數據要加密,用牛逼的加密算法
  • 你就用RSA非對稱加密開發測試操做猛如虎
  • 而後,一上線:CPU炸了,成績1-5
  • 而後你找老闆審批升級服務器費用,老闆給了你300塊並讓你放心花大膽花
  • 你首先把RSA下線了,而後偷偷換成了AES對稱加密,CPU不炸了
  • 而後三百塊偷偷放到了本身腰包裏
  • 可是AES的對稱密鑰你寫死到客戶端,被逆向就完了;若是經過服務器下發,聽起來更加扯淡
  • 想了想,你拿着三百塊錢組了個局兒,你帶着錢,我帶着陳旭,老趙帶着柱子,再加上大彪,正好六人局
  • 局上我向你透露出一種方案:將AES對稱密鑰經過非對稱方式協商出來。DH這種神奇的算法可讓你服務器和客戶端在不傳輸該對稱密鑰的狀況下就能夠經過心有靈犀地方式各自計算出一個對稱密鑰,並且能夠同樣,避免了該密鑰在網絡上流通,並且你能夠隨意更換,過時時間定爲1分鐘,可謂是狠毒至極!

咱們引入DH就是爲了解決上面的問題。然而,DH或ECDH並不能解決中間人攻擊問題,這個要搞明白了。算法

因此,在正式開始以前,我必須先安利我和東北大嫖客還有巨蛀以及阿尼特寫的DH庫,github連接是這個,下面我將利用這些DH庫們進行demo演示。json

https://github.com/ti-dh
(明眼人已經看出來我是來騙star的)

目前這個庫提供了純PHP、C實現的PHP擴展、Java版,列個表格吧:api

圖片描述

先說下服務端和客戶端進行協商地總體流程,很是很是簡單:服務器

整個協商流程中,只有第二步和第三步會發生數據交互。第二步是API下發p、g、server-num給客戶端;第三步是客戶端向API提交client-num數據;最後一步,對稱加解密用的key就已經計算出來用於生產環境了。

下面我用世界上最好的語言演示一下如何使用這個鬼東西,客戶端咱們用什麼演示呢?客戶端也依然使用世界上最好的語言來演示。首先,大家把上面github裏的庫文件集成到大家API裏,我這裏集成完畢後代碼以下:

API demo code:

<?php
class DhController extends BaseController{

  private $dh = null;

  // 將DH庫初始化進來呀...
  public function init() {
    $this->dh = new Dh();
  }

  // 這就是上圖中的第二步:客戶端訪問這個API獲取g p 和 server-num
  public function getdhbasedataAction() {
    $ret = $this->dh->getdhbasedata();
    echo json_encode( $ret );
  }

  // 這就是上圖中的第三步:客戶端經過這個api提交client-num參數
  public function postdhclientdataAction() {
    if ( $this->getRequest()->isPost() ) {
      if ( empty( $_POST['client_number'] ) || !is_numeric( $_POST['client_number'] ) ) {
        exit( json_encode( array(
          'code'    => -1,
          'message' => 'wrong parameters',
        ) ) );
      }
      $ret = $this->dh->postdhclientdata( $_POST );
      echo json_encode( array(
        'key' => $ret,
      ) );
    }
  }

}

Client demo code:

<?php
require __DIR__ . '/vendor/autoload.php';
use \Curl\Curl;
$curl = new Curl();
// 初始化客戶端數據,隨機一個便可~
$client_number = mt_rand( 100000, 999999 );
// 一、第一步,獲取服務器的p、g和server_number
$ret = $curl->get( 'https://xxxx.ooo/dh/getdhbasedata' );
$ret = json_decode( $ret, true );
$p = $ret['p'];
$g = $ret['g'];
$server_number = $ret['server_number'];
// 二、第二步,根據服務器獲取到的數據計算出client-number
$process_client_number = gmp_powm( $g, $client_number, $p );
// 三、第三步,將計算事後的client-number發送給服務器
// 那個demo裏已經有完美的演示了,多看代碼
$ret = $curl->post( 'https://xxxx.ooo/dh/postdhclientdata', array(
  'client_number' => gmp_strval( $process_client_number ),
) );
$ret = json_decode( $ret, true );
// 四、第四步,根據server-number,client-number和p 計算出公共密鑰K
$key = gmp_powm( $server_number, $client_number, $p );
echo PHP_EOL."DH非對稱密鑰產生交換:".PHP_EOL;
echo 'client計算出的public key : '.$key.PHP_EOL;
echo 'server計算出的public key : '.$ret['key'].PHP_EOL.PHP_EOL;

客戶端文件保存client.php,而後php client.php執行一下,結果大家感覺一下:

同樣有沒有?!計算出來的都同樣,有沒有?!!

上圖中那麼一坨長的不能整的讓人看了就以爲噁心嘔吐的數字就是API和客戶端分別計算出來的對稱加解密的密鑰了,請注意實際使用過程當中,服務器千萬不要把這個數據返回給客戶端,demo裏這麼作就是爲了演示而已,用的時候本身也須要動動腦子的。

然而,事情每每不會說就是這麼簡單就能夠了,若是在生產環境使用,仍是須要繼續完善一些細節的。

  • 第一個問題就是有些想的比較多的寶貝兒們會不一樣的兩個客戶端計算出來的key會不會同樣?可能性很是很是很是小
  • 第二個問題就是通常客戶端登錄的用戶都有本身的token或uid之類的,API這裏在與一個客戶端協商出一個key後能夠以 「 token:key 」 格式把key存儲到redis中,而後給一個有效時間好比30分鐘;客戶端也將key保存到手機內存中設置一個30分鐘有效期。每次使用key進行加解密前都驗證一下是否過時,若是過時了就從新走一遍前面的協商流程

我發誓,這是關於DH或ECDH的最後一篇文章了,之後我不再會寫任何與這兩個英文縮寫相關的東西了,我說都是真的,我保證說到作到。

歡迎來公衆號懟我、槓我:

圖片描述

相關文章
相關標籤/搜索