本文轉載了資深的 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| <?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 套件沒有分別:
1
| > pear install pear_package_name
|
這個套件採用了兩個在 blowfish.php 中定義的類,所有使用 Crypt_Blowfish 套件的程式均需 include 這個檔案:
1
| require_once 'Crypt/Blowfish.php';
|
以下熟悉的加密原碼示範 Crypt_Blowfish 的用法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| <?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 套件一樣安裝它。
1
| > pear install pear_package_name
|
Crypt_RSA 需要執行密集的數學計算,並需要以下其中一個擴充模組:
以下是使用這個套件的範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
| <?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 套件的安裝方法沒有分別:
1
| > pear install pear_package_name
|
以下是使用 Crypt_HMAC 產生散列值的範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <?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 套件的安裝方法沒有分別:
1
| > pear install pear_package_name
|
以下兩個程式示範怎樣為兩伙人 (subject_1 和 subject_2) 產生密鑰,第一個程式示範用 Diffie Hellman 算法產生密鑰的最簡單方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| <?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 模式產生密鑰:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| <?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);
?>
|
使用以上提及的各式各樣加密方案,你應該可以做到任何想做的事,加密是一個敏感的安全問題,正如你見到的,解決方案和實作都很多,本文的資訊可以幫助你認識這個課題,但要更進一步,只有在系統安全上的經驗和努力工作,才能幫助你選擇合適的加密方案,使你在安全性、速度、和實作時間上取得平衡。