PHP, Uncategorized, 什麼是?

[PHP] 實做 AES 資料加密(含範例)

在 PHP 中使用 AES 為 API 資料加密、解密。
為什麼要這麼做呢? 即便有 https(ssl) 與網站間做資料傳轉協定,也未怕是 100% 安全,最好還是能在資料傳遞間做好加密,確保只有你自己可以看到完整資料…
確保後端(PHP)與前端(iOS, ANdroid)資料傳遞是安全的

 

你也能選擇另一種加密方式 : [PHP] 範例實做 RSA, 公私鑰非對稱加解密 ( 個人比較推薦的方式 )

為什麼要做資料加密?

除了個資法之外,使用者的行為和信用卡資料也需要加密保護或是不實際儲存…
你也不希望,某天… 你的上網記錄被公佈或是購物記錄曝光吧。

裝置與裝置間或是使用者與伺服器之間的資料傳輸,很容易被監聽或是被側錄

前陣子很紅的文章
看完這駭客四部曲,保證你以後再也不敢連到公共 Wi-Fi 了
即便你的系統很安全,你也不能保證使用者的網路環境是安全的!

https 憑證也分很多種等級的…

https-ssl-twitter
https-ssl-cola

無論如何, https 傳輸己經是基本

 

 

如何做 AES 加密?

資料加密的方式很多,我認為使用 AES 或是公鑰、私鑰 public, private Key 的方式是比較有效又快效的解決方案!
今天就說明一下 AES 在 PHP 上的做法…
(我並不是資安專長,簡單說明方法與 Example Code)

首先,先瞭解一下 PHP mcrypt_encryptmcrypt_decrypt

ps: 記得為 php 安裝 php mcrypt extension

確保加密、解密兩方的編碼模式相同:CBC 與 EBC
最好能與 mobile APP 工程師一塊處理、決定

選擇 128 或 256 位元方式,愈複雜被破解的機率就愈低!但是相對解密時速度也就愈慢

 

 

PHP 實做 AES 資料加密

 

首先 定義 key 與 iv


$hash_string = 'test';

$hash = hash('SHA384', $hash_string, true);
$app_cc_aes_key = substr($hash, 0, 32);
$app_cc_aes_iv = substr($hash, 32, 16);

上述將 金鑰 設定為 test

利用 hash() 將 純文字 轉為 binary
使用 SHA384,hash 出來的 binary 長度為 48
若不帶入 true 參數,則會回傳純文字,長度為 96
這個部份注意一下即可

接著要實做 AES 256 所以將 key 與 iv 的長度設為 32 與 16

ps: binary 與 純文字要處理的 key, iv 長度也會不同,要注意一下哦!

 

 


$data = 'cola is bear';

$padding = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($padding), $padding);
$encrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $app_cc_aes_key, $data, MCRYPT_MODE_CBC, $app_cc_aes_iv);

$encrypt_text = base64_encode($encrypt);

設定要加密的內容為 cola is bear
最後使用 base64_encode() 將加密後內容轉為純文字方便傳遞

如果把 $encrypt 輸出畫面上會顯示…

��@���'�����'�)

這就是 binary 資料

經過 base64_encode() 之後的 $encrypt_text

gpFAqKLkJ9D2oKDQJ/EDKQ==

這串文字就能更方便的在後端與前端之間傳遞了

 

 

PHP 實做 AES 資料解密

接下來是解密的部份…


$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $app_cc_aes_key, $encrypt, MCRYPT_MODE_CBC, $app_cc_aes_iv);
$padding = ord($data[strlen($data) - 1]);
$decrypt_text = substr($data, 0, -$padding);

解密的部份就相對簡單了,最後的 $decrypt_text 就是解密後的結果了
ps:之後記得在解密前先把傳入值做 base64_decode() 哦

 

 

範例結果

這次測試的 example code 和結果

php aes example

測試用 example code

echo '<pre>';

$hash_string = 'test';
$hash = hash('SHA384', $hash_string, true);
echo "hash : ";
var_dump($hash);
echo '<hr>';
$app_cc_aes_key = substr($hash, 0, 32);
$app_cc_aes_iv = substr($hash, 32, 16);
echo "app_cc_aes_key : ";
var_dump($app_cc_aes_key);
echo '<br>';
echo "app_cc_aes_iv :";
var_dump($app_cc_aes_iv);
echo '<hr>';

$data = 'cola is bear';
echo "data : {$data}";
echo '<hr>';

$padding = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($padding), $padding);
$encrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $app_cc_aes_key, $data, MCRYPT_MODE_CBC, $app_cc_aes_iv);

$encrypt_text = base64_encode($encrypt);
echo "encrypt :";
var_dump($encrypt);
echo '<br>';
echo "encrypt_text :";
var_dump($encrypt_text);
echo '<hr>';

$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $app_cc_aes_key, $encrypt, MCRYPT_MODE_CBC, $app_cc_aes_iv);
$padding = ord($data[strlen($data) - 1]);
$decrypt_text = substr($data, 0, -$padding);
echo "decrypt_text : {$decrypt_text}";
echo '<hr>';

exit('--done--');

 

 

精美版 example code

<?php namespace App\Library;

Class MyAES
{
 private $app_cc_aes_key;
 private $app_cc_aes_iv;

 function __construct()
 {
   $hash_string = 'cola-secret-key'; // 可以由外部帶入
   if(is_null($hash_string)) {
     return false;
   }
   $hash = hash('SHA384', $hash_string, true);
   $this->app_cc_aes_key = substr($hash, 0, 32);
   $this->app_cc_aes_iv = substr($hash, 32, 16);
 }

 public function encrypt($data)
 {
   return base64_encode(self::aes256_cbc_encrypt($data, $this->app_cc_aes_key, $this->app_cc_aes_iv));
 }

 // return false for failure
 public function decrypt($data)
 {
   return self::aes256_cbc_decrypt(base64_decode($data), $this->app_cc_aes_key, $this->app_cc_aes_iv);
 }

 // this for AES-256
 private function check_key_and_iv_len($key, $iv)
 {
   if(32 !== strlen($key)) {
     return false;
   }
   if(16 !== strlen($iv)) {
     return false;
   }

   return true;
 }

 private function aes256_cbc_encrypt($data, $key, $iv)
 {
   if(!self::check_key_and_iv_len($key, $iv)) {
     return false;
   }

   $padding = 16 - (strlen($data) % 16);
   $data .= str_repeat(chr($padding), $padding);
   return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
 }

 private function aes256_cbc_decrypt($data, $key, $iv)
 {
   if(!self::check_key_and_iv_len($key, $iv)) {
     return false;
   }

   $data = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
   $padding = ord($data[strlen($data) - 1]);
   return substr($data, 0, -$padding);
 }
}

其中也有 PKCS7、PKCS5 等補零的問題
記得和前端工程師說定就好了!
iOS、android 的部份很容易就能在 Google 上找到範到了
https://www.google.com.tw/search?newwindow=1&safe=off&q=php+aes+ios+android&oq=php+aes+ios+android

5 Comments

  1. 用POST的話,HTTPS會連同內容一起加密吧,對於不同SSL憑證,安全性是相同的;PKI體系的用意在於驗證身分,所以公用WIFI下面也是可以確保安全性的(雖然我都連VPN回家裡)。
    不過這實作非常好,多一分保障就少一分危險

  2. 請教各位大大,我用esp8266做了一個wifi家電控制,但它是純html,沒PHP,要如何做AES-128的加解密,然後我是用android手機的wifi來發出命令,要如何做加密嗎?是在手機app端做加密,然後esp8266做解密嗎?具體作法,是還需要買什麼硬體嗎,還是純軟體就可以做, .NET新手, 還請各位大神 賜教! 感謝觀看.

    1. 不一定使用 PHP 才能做 AES, .NET 也可以哦!

      > 是在手機app端做加密,然後esp8266做解密嗎?

      是的!

      > 是還需要買什麼硬體嗎,還是純軟體就可以做

      不需要另外添購硬體哦,純軟體程式就可以完成了!

Leave a Reply