資深的 PHP 開發人員 Octavia Andreea Anghel 在 DevX.com 發表了一篇 PHP 加密技術的教學文件,討論如何取得和安裝各種 PHP 加密技術軟件包,以提高你的 PHP 應用程式的安全性。本文是系列的第一部分,第二部分在這裡。在理想世界,加密和保安技術根本無須存在,但現實世界遠非完美,所以軟件開發商要花費大量時間和金錢,為應用程式設立保安措施,加密只是整個保安拼圖中的一小塊,其他的尚有 SSL / TLS、數碼證書、數碼簽名等等。本文將會介紹如何用 PHP 來實作最常見的加密算法,除了描述 PHP 預設的加密功能,你也會看到各種各樣加密函式庫和軟件包。
本文所有範例均使用一個短小的純文本檔 textfile.txt,它就是密碼學所謂的「明文」(plaintext),明文加密後便變成「密文」(ciphertext)。本文使用的「明文」如下:
For every difficult and complicated question there is an answer
that is simple, easily understood, and wrong. HL Mencken
PHP 預設的加密函式
在預設的安裝模式下,PHP 包含了三個內建的加密函式:md5()、crypt()、和 sha1()。md5() 函式的原型是:
string md5(string $str [, bool $raw_output ])這個函式使用 MD5 訊息摘要算法 (MD5 Message-Digest algorithm) 計算輸入字串的 MD5 散列值,其中引數 $str 是需要加密的字串,若果引數 $raw_output 的值是FALSE (這是預設值),函式會以一個 32 字符的十六進制數字送回散列值,若果該引數的值是 TRUE,函式會送回一個 16 字節長度的原始二進制數字。
至於 crypt() 則是一個單向的加密函式,可讓你把一個輸入的密碼與一個預存的密碼比較,無須經過任何解密程序,crypt() 函式的原型是:
string crypt (string $str [, string $salt ])它使用以 Unix 的 DES 為基礎的加密算法(或者操作系統提供的替代算法)來加密輸入的字串,引數 $str 就是要加密的字串,可選引數 $salt 是一個提供給加密程序的字串,若果你不提供 $salt,PHP 將每次隨機產生一個。
sha1() 函式是用來計算一個字串的 SHA-1 散列值,該函式的原型是:
string sha1 (string $str [, bool $raw_output ]) 函式 sha1() 以字串的方式送回輸入字串的 SHA-1 散列值,同樣地,引數 $str 代表輸入字串,若果可選引數 $raw_output 的值是 TRUE,函式會送回一個長度 20 個字節的原始二進制數字;若果引數的值是 FALSE,函式會一個 40 字符的十六進制數字。
下面的範例顯示了如何使用 PHP 的預設加密函式把 textfile.txt 文件加密,並把結果存到 encrypted.txt 檔案中:
<?php
$file = 'textfile.txt';
$initial_contents = file_get_contents($file);
if($initial_contents) {
$password = 'OctaviaAnghel';
// 計算 MD5 散列值
$md5_data = md5($password);
// 加密數據
$crypt = crypt($password);
// 計算 SHA-1 散列值
$sha1 = sha1($password);
$encrypted_file = @fopen('encrypted.txt','w');
$ok_encrypt = @fwrite($encrypted_file,'md5: '. $md5_data.
"\r\n".'crypt: '.$crypt."\r\n".'sha1: '.$sha1);
if($ok_encrypt) {
echo '成功建立密文檔案 encrypted_file.txt!!!';
}
else {
echo ("檔案寫入失敗!");
}
@fclose($encrypted_file);
}
?>
除了內建的函式外,PHP 也支援外部的加密函式庫和軟件包,下表顯示了本文餘下部分將會提及的函式庫和軟件包:
| 軟件包/函式庫 | 描述 |
| MCrypt | MCrypt 提供範圍廣泛的加密功能,可用來加密大型檔案或數據流,你可以在 http://mcrypt.sourceforge.net/ 找到更多資料。 |
| MHash | 使用 MHash 來獲取散列值,MHash 支援最流行的散列算法和實作,包括 SHA、MD5、及 CRC,你可以用這些算法來計算校驗值 (checksum)、訊息摘要 (message digest)、和產生署碼簽署,MHash 經常用來計算輸入 HTML 密碼欄位中密碼的散列值。你可以在 http://mhash.sourceforge.net/ 找到更多 MHash 的資訊。 |
| Crypt_Blowfish | Crypt_Blowfish 可以進行快速雙向加密,可以選擇使用或不使用密鑰,它無需依靠 PHP 的 MCrypt 擴展模組,不過若果已經安裝 MCrypt,Crypt_Blowfish 可以使用它。你可以在 http://pear.php.net/package/Crypt_Blowfish 找到更多細節。 |
| Crypt_RSA | Crypt_RSA 提供 RSA 一樣的密鑰生成、加密/解密、數位簽署及簽署驗證功能,你可以在 http://pear.php.net/package/Crypt_RSA 找到更多資料。 |
| Crypt_HMAC | 這個類可用來計算兼容 RFC 2104 的散列值,你可以在 http://pear.php.net/package/Crypt_HMAC 找到完整的資料。 |
| Crypt_DiffieHellman | 這是一個在 PHP 5 上實作的 Diffie-Hellman 密鑰交換協議,你可以在 http://pear.php.net/package/Crypt_DiffieHellman 找到更多資料。 |
加密大量數據與 MCrypt
即使不是專業的密碼學家,PHP 開發人員也可以使用 MCrypt 中大量的加密函式來加密文件或數據流,MCrypt 支援多種區塊加密算法 (block encryption algorithm),包括 Blowfish、DES、TripleDES、SAFER-SK128、TWOFISH、TEA、RC2、3-WAY、SAFER-SK64,和幾種「運作模式」,MCrypt 一類的區塊加密軟件針對固定長度的數據塊,一般來說是 64 或 128 bits,由於明文的長度並不是固定的,加上使用相同的密鑰來加密相同的明文,會得到相同的結果,所以專家們發明了數個解決方案允許區塊加密軟件處理任意長度的明文,這些解決方案稱為「運作模式」,MCrypt 支援的運作模式包括 CBC、CFB、CTR、ECB、OFB、及 NCFB。
MCrypt 的配套函式庫是 Libmcrypt,它提供實際的加密功能,微軟視窗用家可以在這裡下載,Linux 用家則可在這裡下載。
| 原作者註解:若果你使用的是 PHP 5.0.0,你需要 libmcrypt 2.5.6 或更高版本。 |
安裝 libmcrypt:
- 下載 libmcrypt.dll。
- 複製 libcrypt.dll 到 {php_home}/ext 及 {Windows_home}/System32 資料夾。
- 在 php.ini 中把 extension=php_mcrypt.dll 前面的評論符號「;」刪除,啟動這個模組。
- 儲存更新後的 php.ini。
原作者註解:使用 Linux 的話,請下載 libmcrypt-x.z.tar.gz 檔案,並遵照附帶的安裝指示安裝。 |
MCrypt 有四種運作模式:CBC、OFB、CFB、及 ECB,若果你使用 libmcrypt-2.4.x 或更高版本,那麼 MCrypt 也可以使用 OFB 及 STREAM 運作模式,下表列出常用的運作模式,與及扼要介紹何時使用甚麼模式。
| 運作模式 | 描述 |
| MCRYPT_MODE_ECB | 適合隨機數據,你可以用這種模式來加密不同的密碼。 |
| MCRYPT_MODE_CBC | 用來加密文件。 |
| MCRYPT_MODE_CFB | 建議用來加密字節流。 |
| MCRYPT_MODE_OFB | 專門用在不容許出錯的應用系統。 |
| MCRYPT_MODE_NOFB | 兼容 OFB,但更加安全。 |
| MCRYPT_MODE_STREAM | 需要資料流算法時使用,例如 WAKE 或 RC4。 |
除了這些運作模式,MCrypt 也支援以下加密算法:
- MCRYPT_3DES
- MCRYPT_ARCFOUR
- MCRYPT_BLOWFISH
- MCRYPT_IDEA (非免費)
- MCRYPT_LOKI97
- MCRYPT_MARS
- MCRYPT_PANAMA
- MCRYPT_RIJNDAEL_128
| 原作者註解:由於 MCrypt 支援的加密算法可能隨時間而改變,請定期檢查這份名單。 |
MCrypt 範例
這裡是一個使用 MCrypt 加密和解密一個文件的範例,程式會把檔案 textfile.txt 加密成為 encrypted.txt,然後把這個檔案解密成為 newfile.txt。
// Listing file_encrypt.php
<?php
$file = 'textfile.txt';
$initial_contents = file_get_contents($file);
if($initial_contents) {
// 這個函式開啟 MCrypt 模組,並設定所使用的運作模式
$td = mcrypt_module_open('tripledes', '', 'ecb', '');
// 從一個隨機來源建立一個初始向量
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
// 這個函式初始化所有加密所需的緩衝器
mcrypt_generic_init($td, $initial_contents, $iv);
// 這個函式加密數據
$encrypted_data = mcrypt_generic($td, $initial_contents);
$encrypted_file = @fopen('encrypted.txt','w');
$ok_encrypt = @fwrite($encrypted_file,$encrypted_data);
if($ok_encrypt) {
echo '成功建立密文檔案 encrypted_file.txt!!!';
}
else {
echo ("檔案寫入失敗!");
}
@fclose($encrypted_file);
mcrypt_generic_init($td, $initial_contents, $iv);
// 這個函式解密數據
$p_t = mdecrypt_generic($td, $encrypted_data);
$newfile = @fopen('newfile.txt','w');
$ok_decrypt = @fwrite($newfile,$p_t);
if($ok_decrypt) {
echo '成功建立解密文件 newfile.txt!!!';
}
else{
echo ("檔案寫入失敗!");
}
@fclose($newfile);
// 這個函式為加密模組解除初始化
mcrypt_generic_deinit($td);
// 關閉加密模組
mcrypt_module_close($td);
}
?>
發表新回應