本文轉載了 資深的 PHP 開發人員 Octavia Andreea Anghel 在 DevX.com 發表的 PHP 加密技術的教學文件,第一部分介紹了 PHP 預設的加密功能,及擴充模組 MCrypt 的安裝及應用方法。本文將會繼續介紹其他擴充模組。
用 MHash 建立散列值
MHash 是一個免費的函式庫,提供大量散列值算法,這些算法可用來計算校驗值 (checksum)、訊息摘要 (message digests)、及建立數碼簽署。
安裝 libmhash
- 下載 libmhash.dll。
- 複製 libmhash.dll 到 {php_home}/ext 及 {Windows_home}/System32 資料夾。
- 在 php.ini 中把 extension=php_mhash.dll 前面的評論符號「;」刪除,啟動這個模組。
- 儲存更新後的 php.ini。
支援的散列算法
MHash 目前支援的散列算法包括:
- MHASH_ADLER32
- MHASH_CRC32
- MHASH_CRC32B
- MHASH_GOST
- MHASH_HAVAL128
- MHASH_HAVAL160
- MHASH_HAVAL192
- MHASH_HAVAL256
- MHASH_MD4
- MHASH_MD5
- MHASH_RIPEMD160
- MHASH_SHA1
- MHASH_SHA256
- MHASH_TIGER
- MHASH_TIGER128
- MHASH_TIGER160
以下範例把明文 textfile.txt 加密並把結果寫到 encrypted.txt:
<?php
$file = 'textfile.txt';
$initial_contents = file_get_contents($file);
if ($initial_contents) {
// mhash() 使用 MHASH_MD5 算法來處理 $initial_contents
$encrypted = mhash(MHASH_MD5, $initial_contents);
// 取得 Unix 現在的 timestamp
$current = time();
$salt = $current;
$password = "Octavia";
// mhash_keygen_s2k 函式根據指定的散列函數及用戶提供的密碼產生一個密鑰
$hash = mhash_keygen_s2k(MHASH_GOST, $password, $salt, 20);
// 串聯 $salt 和 $hash
$key = $salt . "|" . bin2hex($hash);
$encrypted_file = @fopen('encrypted.txt','w');
$ok_encrypt = @fwrite($encrypted_file,
'mhash: '.bin2hex($encrypted).' mhash_keygen_s2k:
'.$key);
if ($ok_encrypt) {
echo '成功建立密文檔案 encrypted_file.txt!!!';
}
else {
echo ("檔案寫入失敗!");
}
@fclose($encrypted_file);
}
?>
秘密鑰匙和 Crypt_Blowfish
秘密密鑰加密法利用一個單一的密鑰來加密和解密,所以也稱為「對稱密鑰」(symmetric key),舉例來說,常見的 DES 算法就是一個祕密密鑰算法。PEAR 的 Crypt_Blowfish 套件基於 Blowfish 區塊加密算法,提供雙向加密功能,無論是有或沒有祕密密鑰。這個套件無需依賴 MCrypt,但若果有的話 Crypt_Blowfish 可以使用它,這個套件最新的穩定版本是 1.0.1,安裝程序跟其他 PEAR 套件沒有分別:
> pear install pear_package_name
這個套件採用了兩個在 blowfish.php 中定義的類,所有使用 Crypt_Blowfish 套件的程式均需 include 這個檔案:
require_once 'Crypt/Blowfish.php';
以下熟悉的加密原碼示範 Crypt_Blowfish 的用法:
<?php
require_once 'Crypt/Blowfish.php';
$file = 'textfile.txt';
$initial_contents = file_get_contents($file);
if ($initial_contents) {
$bf = new Crypt_Blowfish('some secret key!');
// 加密一個字串
$encrypted = $bf->encrypt($initial_contents);
$encrypted_file = @fopen('encrypted.txt','w');
$ok_encrypt = @fwrite($encrypted_file,$encrypted);
if ($ok_encrypt) {
echo '成功建立密文檔案 encrypted_file.txt!!!';
}
else {
echo ("檔案寫入失敗!");
}
@fclose($encrypted_file);
// 把一個已加密的字串解密
$plaintext = $bf->decrypt($encrypted);
$newfile = @fopen('newfile.txt','w');
$ok_decrypt = @fwrite($newfile,$plaintext);
if ($ok_decrypt) {
echo '成功建立解密文件 newfile.txt!!!';
}
else {
echo ("檔案寫入失敗!");
}
@fclose($newfile);
}
?>
PEAR 的 Crypt_RSA PEAR 套件讓你用任意長度的密鑰來加密數據
這個套件是以 RSA 區塊加密技術為基礎,支持雙向加密,它支援任意長度的密鑰來加密和解密,最新的 1.0.0 穩定版本可在這裡下載,並像安裝其他 PEAR 套件一樣安裝它。
> pear install pear_package_name
Crypt_RSA 需要執行密集的數學計算,並需要以下其中一個擴充模組:
- PECL big_int extension (需要版本 1.0.3 或以上)
- PHP GMP extension
- PHP BCMath extension for PHP4/PHP5,由於只有 PHP 4.0.4 綑綁了 libbcmath,所以需要這個模組
<?php
require_once 'Crypt/RSA.php';
// 產生一雙對稱密鑰
function generate_key_pair()
{
global $public_key,$private_key;
$key_pair = new Crypt_RSA_KeyPair(32);
// 從這雙密鑰中提取公鑰
$public_key = $key_pair->getPublicKey();
// 從這雙密鑰中提取密鑰
$private_key = $key_pair->getPrivateKey();
}
// 監察執行時錯誤
function check_error(&$obj)
{
if ($obj->isError()){
$error = $obj->getLastError();
switch ($error->getCode()) {
case CRYPT_RSA_ERROR_WRONG_TAIL :
// 無須做任何事
break;
default:
// 顯示錯誤訊息然後退出
echo 'error: ', $error->getMessage();
exit;
}
}
}
$file = 'textfile.txt';
generate_key_pair();
$plain_text = file_get_contents($file);
// 把公鑰表達為一個字符串
$key = Crypt_RSA_Key::fromString($public_key->toString());
$rsa_obj = new Crypt_RSA;
check_error($rsa_obj);
// 用密鑰 $key 加密 $plain_text
$encrypted = $rsa_obj->encrypt($plain_text, $key);
$encrypted_file = @fopen('encrypted.txt','w');
$ok_encrypt = fwrite($encrypted_file,$encrypted);
if ($ok_encrypt) {
echo '成功建立密文檔案 encrypted_file.txt!!!';
}
else{
echo ("檔案寫入失敗!");
}
@fclose($encrypted_file);
$enc_text = $encrypted;
// 把密鑰表達為一個字符串
$key2 = Crypt_RSA_Key::fromString($private_key->toString());
check_error($key2);
// 檢查加密/解密函式的行為
$rsa_obj->setParams(array('dec_key' => $key2));
check_error($rsa_obj);
// 解密 $enc_text
$decrypted = $rsa_obj->decrypt($enc_text);
$newfile = @fopen('newfile.txt','w');
$ok_decrypt = @fwrite($newfile,$decrypted);
if ($ok_decrypt) {
echo '成功建立解密文件 newfile.txt!!!';
}
else {
echo ("檔案寫入失敗!");
}
@fclose($newfile);
?>
用 Crypt_HMAC 來產生散列值
PEAR 的 Crypt_HMAC 套件有一個類可以用來計算 RFC 2104 兼容的散列值,Crypt_HMAC 很容易使用,你只需告訴它你的密鑰、散列計算方法、和明文。Crypt_HMAC 支援 MD5 和 SHA-1 算法,最新的穩定版本是 1.0.0,它跟其他 PEAR 套件的安裝方法沒有分別:
> pear install pear_package_name
以下是使用 Crypt_HMAC 產生散列值的範例:
<?php
require_once 'Crypt/HMAC.php';
// 把字符 "0x0b" 重複二十次來產生一個密鑰
$key = str_repeat(chr(0x0b), 20);
// 產生一個 Crypt_HMAC 類的實體
$crypt = new Crypt_HMAC($key, 'md5');
// 散列函式
echo $crypt->hash('Hello');
$key = str_repeat(chr(0xaa), 10);
$data = str_repeat(chr(0xdd), 50);
// 把散列函式的密鑰設定為 $key
$crypt->setKey($key);
echo $crypt->hash($data)."\n";
?>
使用 PEAR 的 Crypt_DiffieHellman 套件來產生密鑰
這個 PEAR 套件在 PHP 5 環境下實作 Diffie-Hellman 密鑰交換協議,你可以使用這個協議來產生一個密鑰,並把密鑰交給兩伙人,讓他們在一個非安全通道上通訊,你可以在這裡下載最新的 0.2.1 (beta) 版本,它跟其他 PEAR 套件的安裝方法沒有分別:
> pear install pear_package_name
以下兩個程式示範怎樣為兩夥人 (subject_1 和 subject_2) 產生密鑰,第一個程式示範用 Diffie Hellman 算法產生密鑰的最簡單方法:
<?php
// 引入 Diffie Hellman 函式
require_once 'Crypt/DiffieHellman.php';
// 為兩夥人設定所需的引數
$subject_1 = array('prime'=>'123', 'generator'=>'7', 'private'=>'3');
$subject_2 = array('prime'=>'123', 'generator'=>'7', 'private'=>'34');
// 運用 Diffie Hellman 算法
$subject_1_GK = new Crypt_DiffieHellman(
$subject_1['prime'], $subject_1['generator'],
$subject_1['private']);
$subject_2_GK = new Crypt_DiffieHellman(
$subject_2['prime'], $subject_2['generator'],
$subject_2['private']);
// 產生密鑰
$subject_1_GK->generateKeys();
$subject_2_GK->generateKeys();
// 計算密鑰
$subject_1_SK = $subject_1_GK->computeSecretKey(
$subject_2_GK->getPublicKey())->getSharedSecretKey();
$subject_2_SK = $subject_2_GK->computeSecretKey(
$subject_1_GK->getPublicKey())->getSharedSecretKey();
// 顯示密鑰
echo('Subject_1_SK:'.$subject_1_SK);
echo('Subject_2_SK:'.$subject_2_SK);
?>
第二個程式示範用 Diffie Hellman 的 BINARY 模式產生密鑰:
<?php
// 引入 Diffie Hellman 函式
require_once 'Crypt/DiffieHellman.php';
// 為兩夥人設定所需的引數
$subject_1 = array('prime' =>
'9568094558049898340935098349053',
'generator'=>'2',
'private' => '2232370277237628823279273723742872289398723');
$subject_2 = array('prime' =>
'9568094558049898340935098349053',
'generator'=>'2',
'private' => '0389237288721323987429834389298232433363463');
// 運用 Diffie Hellman 算法
$subject_1_GK = new Crypt_DiffieHellman(
$subject_1['prime'], $subject_1['generator'],
$subject_1['private']);
$subject_2_GK = new Crypt_DiffieHellman(
$subject_2['prime'], $subject_2['generator'],
$subject_2['private']);
// 產生密鑰
$subject_1_GK->generateKeys();
$subject_2_GK->generateKeys();
// 用 BINARY 模式計算密鑰
$subject_1_SK = $subject_1_GK->computeSecretKey(
$subject_2_GK->getPublicKey(Crypt_DiffieHellman::BINARY),
Crypt_DiffieHellman::BINARY)->
getSharedSecretKey(Crypt_DiffieHellman::BINARY);
$subject_2_SK = $subject_2_GK->computeSecretKey(
$subject_1_GK->getPublicKey(Crypt_DiffieHellman::BINARY),
Crypt_DiffieHellman::BINARY)->
getSharedSecretKey(Crypt_DiffieHellman::BINARY);
// 顯示密鑰
echo('subject_1_SK:'.$subject_1_SK);
echo('subject_2_SK:'.$subject_2_SK);
?>
使用以上提及的各式各樣加密方案,你應該可以做到任何想做的事,加密是一個敏感的安全問題,正如你見到的,解決方案和實作都很多,本文的資訊可以幫助你認識這個課題,但要更進一步,只有在系統安全上的經驗和努力工作,才能幫助你選擇合適的加密方案,使你在安全性、速度、和實作時間上取得平衡。
發表新回應