Wiki 上定義的 RSA加密演算法是一種非對稱加密演算法 (Wiki 真是偷懶好東西)
簡單來說,加密時需要透過 公鑰 進行,而解密時需要利用 私鑰 進行解密!
也就是說,就算 Client 端遭到破解,造成 公鑰 流出,也不會有任何危害。
‼️ 注意:透過 RSA 加密後的內容(密文),每次都會不同!
因為 演算法 (PKCS PADDING) 的關係,每次加密後的結果都不同,但透過同組公、私鑰都能正常解密.
(PKCS PADDING 會在加密前對明文內容加入亂數填充 Padding – wiki)
在這裡,需要利用 openssl 產出一 私鑰(private key)
你需要在 CLI (command-line interface) 裡使用 opensll 輸入下面指令,windows 的使用者請先安裝 openssl (這次先不另外講解這部份…)
可以透過兩種方式建立 公鑰與私鑰,則一即可..
方法一:
>openssl genrsa -out private_1024.key 1024
使用 RSA 1024 位元加密,產出 Private Key
接著再使用剛剛產出的 private key 建立 public key
>openssl rsa -in private.key -out public_1024.pem -outform PEM -pubout
方法二: (產出的副檔名,不是那麼重要)
>sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout ~/php/private_2048.key -out ~/php/public_2048.crt
上述方式較為嚴僅,可以設定更多細節,可以參考(https://blog.gtwang.org/linux/nginx-create-and-install-ssl-certificate-on-ubuntu-linux/)
一些參數說明….(也可以選擇要不要再加入密碼保護 )
- req:使用 X.509 Certificate Signing Request(CSR) Management 產生憑證。
- x509:建立自行簽署的憑證。
- nodes:不要使用密碼保護,因為這個憑證是 NGINX 伺服器要使用的,如果設定密碼的話,會讓伺服器每次在啟動時書需要輸入密碼
- days 3650:設定憑證的使用期限,單位是天,如果不想時常重新產生憑證,可以設長一點。
- newkey rsa:2048:同時產生新的 RSA 2048 位元的金鑰。
- keyout:設定金鑰儲存的位置。
- out:設定憑證儲存的位置。
分別產出 私鑰 (Private Key) 和公鑰 (Public Key) ,也確認兩者都放到正確位置就可以開始實做&測試加解密了!
若要將公鑰交給 iOS 或 Android 端,他們會需要 .pem 或 .der 檔,可以參考下面的文章進行轉換
OpenSSL 操作筆記 – 檔案格式轉換
用簡單的 Plain PHP 做範例…
// 加密前原始資料-信用卡資料
$fullText = '{"card_number":"1234567812345678","expiry_date":"202012","cvc2":"000"}';
// 設定公、私鑰檔名
const PRIVATE_KEY = 'private_1024.key';
const PUBLIC_KEY = 'public_1024.pem';
// 如果你是用第二種方法產生
// const PRIVATE_KEY = 'private_2048.key';
// const PUBLIC_KEY = 'public_2048.crt';
// 如果設定密碼
// const PASSPHRASE = 'my_pasword';
function public_encrypt($plain_text)
{
$fp = fopen(PUBLIC_KEY, "r");
$pub_key = fread($fp, 8192);
fclose($fp);
$pub_key_res = openssl_get_publickey($pub_key);
if(!$pub_key_res) {
throw new Exception('Public Key invalid');
}
openssl_public_encrypt($plain_text, $crypt_text, $pub_key_res, OPENSSL_PKCS1_OAEP_PADDING);
openssl_free_key($pub_key_res);
return base64_encode($crypt_text); // 加密後的內容為 binary 透過 base64_encode() 轉換為 string 方便傳輸
}
function private_decrypt($encrypted_text)
{
$fp = fopen(PRIVATE_KEY, "r");
$priv_key = fread($fp, 8192);
fclose($fp);
$private_key_res = openssl_get_privatekey($priv_key);
// $private_key_res = openssl_get_privatekey($priv_key, PASSPHRASE); // 如果使用密碼
if(!$private_key_res) {
throw new Exception('Private Key invalid');
}
// 先將密文做 base64_decode() 解釋
openssl_private_decrypt(base64_decode($encrypted_text), $decrypted, $private_key_res, OPENSSL_PKCS1_OAEP_PADDING);
openssl_free_key($private_key_res);
return $decrypted;
}
// 將資料進行加密
$r = public_encrypt($fullText);
var_dump($r);
// 將資料進行解密
$r = private_decrypt($r);
var_dump($r);
非常簡單吧~
另外… 使用 1024, 2048 更甚至是 3072 加密時所需的加、解密耗時
1024
加解密約 0.0001~0.0006 秒
失敗時約 0.005~0.007 秒
3072
加解密約 0.0003~0.0007 秒
失敗時約 0.006~0.009 秒
做個參考~
官方手冊:openssl_public_encrypt
官方手冊:openssl_private_decrypt
上述兩個函式第四個參數 padding 模式可以指定加、解密使用的演算法
(OPENSSL_PKCS1_PADDING, OPENSSL_SSLV23_PADDING, OPENSSL_PKCS1_OAEP_PADDING, OPENSSL_NO_PADDING)
預設為:OPENSSL_PKCS1_PADDING
目前比較推薦 OPENSSL_PKCS1_OAEP_PADDING
密文
與 明文
‼️ 注意: 產生金鑰時的長度, RSA 1024 或 RSA 2048 會影響可被加密的明文長度
e.g 1024 bit 的金鑰能加密的明文只有約 128 bytes (實際上再少一些,詳情請看 參考文章 – 密文與明文長度)
因此如果預期明文的長度比較長,建議最初生成 RSA 金鑰的時候設定大一點 2048, 4096…
錯誤追蹤、回報非常重要,看到的錯誤才知道怎麼修。現今 PHP 流行的 Laravel 有很好的 Error Tracking, Error Handling。但 plain PHP 怎麼辦呢? 在 production 為了安全考量會設定…
jenkins、circleci、travis 或 Gitlab CI 皆為目前暫知名的 CI/CD 服務,各自缺點也不言而喻...過於肥大、收費略高(?)、速度不夠快執問題...此時使用 go language 開發的 Drone 就出現啦,完全 docker 容器化的運行方式讓整個 CI…
網頁壓縮技術中 gzip 很好用,deflate 己經過時,但你聽過 brotli 嗎? 有著比 gzip 更好、更快的壓縮效率。看起來利大於弊有什麼不用他的理由嗎?簡單從優、缺點來看 brotli!到底 brotli 布羅特利是什麼、如何設定呢。 目前大多的 web server…
為什麼要讓本機使用 Docker 內 PHP? 情境... docker 容器內用的是 PHP 7.4 但你的開發本機還在跑 PHP 5.6 或是更舊,因為 dockerize 的關係會將所有相關環境都轉移到…
為什麼你需要密碼管理工具現代人一天下來需要輸入多少組密碼,工作與生活己經和密碼密不可分! 除了足夠全安的密碼,密碼記錄、儲存的方式又足夠安全嗎?密碼管理工具可以帶來什麼幫助呢? 為什麼你需要密碼管理工具 資安問題!!大多人說著沒做壞事不怕被偷資料、監聽。嚴重曝露出現代人的基本科技素養的低落和無知 🤯 密碼的使用無所不在!! 行動裝置的普及,APP 、手機遊戲、銀行帳戶所有和生活相關的東西都需要密碼!!facebook, line 只要打開 APP 也會輸入密碼只是他是自動輸入、一般情況不可視 (auth token) 一般人最常發生的密碼資安問題…
mysql 資料表分區 mysql table partition 從架構上調整 mysql 的查詢效率。mysql DB 的優化可以簡單也能複雜,除了調整設定值。也可以透過水平分割(Horizontal Partitioning)、垂直分割(Vertical Partitioning) 分庫或分表將資料分散儲存減少資料搜尋、group by 時的效能消耗。拆開批次處理,理論上效率都會變好,本文就水平分割的…
View Comments
不好意思 我想請問 我產生的 private_1024.key 要放在電腦的哪個地方??
放在任何位置都可以哦,只是你 PHP 能讀取的地方就可以了。
通常和專案放在一塊,比較方便測試和讀取。
安全一點的話,可以放到 .ssh 這類,安全性比較高的目錄。