Uncategorized

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

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

 

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

為什麼要做資料加密?

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

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

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

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


無論如何, 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 和結果

測試用 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

可樂

View Comments

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

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

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

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

      是的!

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

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

Recent Posts

plain PHP 搭配 Slack 進行錯誤追蹤、回報(Error Tracking、Error Handling)

錯誤追蹤、回報非常重要,看到的錯誤才知道怎麼修。現今 PHP 流行的 Laravel 有很好的 Error Tracking, Error Handling。但 plain PHP 怎麼辦呢? 在 production 為了安全考量會設定…

4 years ago

Drone CI/CD 配合 Github 使用 Rsync 進行 Deploy

jenkins、circleci、travis 或 Gitlab CI 皆為目前暫知名的 CI/CD 服務,各自缺點也不言而喻...過於肥大、收費略高(?)、速度不夠快執問題...此時使用 go language 開發的 Drone 就出現啦,完全 docker 容器化的運行方式讓整個 CI…

4 years ago

Nginx brotli 設定

網頁壓縮技術中 gzip 很好用,deflate 己經過時,但你聽過 brotli 嗎? 有著比 gzip 更好、更快的壓縮效率。看起來利大於弊有什麼不用他的理由嗎?簡單從優、缺點來看 brotli!到底 brotli 布羅特利是什麼、如何設定呢。 目前大多的 web server…

4 years ago

本機使用 Docker 容器內 PHP (wrapper/expose PHP)

為什麼要讓本機使用 Docker 內 PHP? 情境... docker 容器內用的是 PHP 7.4 但你的開發本機還在跑 PHP 5.6 或是更舊,因為 dockerize 的關係會將所有相關環境都轉移到…

4 years ago

為什麼你需要密碼管理工具

為什麼你需要密碼管理工具現代人一天下來需要輸入多少組密碼,工作與生活己經和密碼密不可分! 除了足夠全安的密碼,密碼記錄、儲存的方式又足夠安全嗎?密碼管理工具可以帶來什麼幫助呢? 為什麼你需要密碼管理工具 資安問題!!大多人說著沒做壞事不怕被偷資料、監聽。嚴重曝露出現代人的基本科技素養的低落和無知 🤯 密碼的使用無所不在!! 行動裝置的普及,APP 、手機遊戲、銀行帳戶所有和生活相關的東西都需要密碼!!facebook, line 只要打開 APP 也會輸入密碼只是他是自動輸入、一般情況不可視 (auth token) 一般人最常發生的密碼資安問題…

4 years ago

簡單使用 Mysql Partition 優化查詢

mysql 資料表分區 mysql table partition 從架構上調整 mysql 的查詢效率。mysql DB 的優化可以簡單也能複雜,除了調整設定值。也可以透過水平分割(Horizontal Partitioning)、垂直分割(Vertical Partitioning) 分庫或分表將資料分散儲存減少資料搜尋、group by 時的效能消耗。拆開批次處理,理論上效率都會變好,本文就水平分割的…

4 years ago