PHP 加密技術指南(二之二)

本文轉載了 資深的 PHP 開發人員 Octavia Andreea Anghel 在 DevX.com 發表的 PHP 加密技術的教學文件第一部分介紹了 PHP 預設的加密功能,及擴充模組 MCrypt 的安裝及應用方法。本文將會繼續介紹其他擴充模組。

用 MHash 建立散列值

MHash 是一個免費的函式庫,提供大量散列值算法,這些算法可用來計算校驗值 (checksum)、訊息摘要 (message digests)、及建立數碼簽署。

安裝 libmhash

  1. 下載 libmhash.dll
  2. 複製 libmhash.dll 到 {php_home}/ext 及 {Windows_home}/System32 資料夾。
  3. 在 php.ini 中把 extension=php_mhash.dll 前面的評論符號「;」刪除,啟動這個模組。
  4. 儲存更新後的 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 |  copy code |? 
01
<?php
02
$file = 'textfile.txt';
03
$initial_contents = file_get_contents($file);
04
 
05
if ($initial_contents) {
06
    // mhash() 使用 MHASH_MD5 算法來處理 $initial_contents
07
    $encrypted = mhash(MHASH_MD5, $initial_contents);
08
 
09
    // 取得 Unix 現在的 timestamp
10
    $current = time();
11
    $salt = $current;
12
    $password = "Octavia";
13
 
14
    // mhash_keygen_s2k 函式根據指定的散列函數及用戶提供的密碼產生一個密鑰
15
    $hash = mhash_keygen_s2k(MHASH_GOST, $password, $salt, 20);
16
 
17
    // 串聯 $salt 和 $hash
18
    $key = $salt . "|" . bin2hex($hash);
19
 
20
    $encrypted_file = @fopen('encrypted.txt','w');
21
    $ok_encrypt = @fwrite($encrypted_file, 'mhash: '.bin2hex($encrypted).' mhash_keygen_s2k:'.$key);
22
 
23
    if ($ok_encrypt) {
24
        echo '成功建立密文檔案 encrypted_file.txt!!!';
25
    }
26
    else {
27
        echo ("檔案寫入失敗!");
28
    }
29
    @fclose($encrypted_file);
30
}
31
?> 

秘密鑰匙和 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 這個檔案:

 PHP |  copy code |? 
1
require_once 'Crypt/Blowfish.php'; 

以下熟悉的加密原碼示範 Crypt_Blowfish 的用法:

 PHP |  copy code |? 
01
<?php
02
 
03
require_once 'Crypt/Blowfish.php';
04
 
05
$file = 'textfile.txt';
06
$initial_contents = file_get_contents($file);
07
 
08
if ($initial_contents) {
09
    $bf = new Crypt_Blowfish('some secret key!');
10
 
11
    // 加密一個字串
12
    $encrypted = $bf->encrypt($initial_contents);
13
 
14
    $encrypted_file = @fopen('encrypted.txt','w');
15
    $ok_encrypt = @fwrite($encrypted_file,$encrypted);
16
    if ($ok_encrypt) {
17
        echo '成功建立密文檔案 encrypted_file.txt!!!';
18
    }
19
    else {
20
        echo ("檔案寫入失敗!");
21
    }
22
    @fclose($encrypted_file);
23
 
24
    // 把一個已加密的字串解密
25
    $plaintext = $bf->decrypt($encrypted);
26
    $newfile = @fopen('newfile.txt','w');
27
    $ok_decrypt = @fwrite($newfile,$plaintext);
28
    if ($ok_decrypt) {
29
        echo '成功建立解密文件 newfile.txt!!!';
30
    }
31
    else {
32
        echo ("檔案寫入失敗!");
33
    }
34
 
35
    @fclose($newfile);
36
}
37
?>

PEAR 的 Crypt_RSA PEAR 套件讓你用任意長度的密鑰來加密數據

這個套件是以 RSA 區塊加密技術為基礎,支持雙向加密,它支援任意長度的密鑰來加密和解密,最新的 1.0.0 穩定版本可在這裡下載,並像安裝其他 PEAR 套件一樣安裝它。

> pear install pear_package_name

Crypt_RSA 需要執行密集的數學計算,並需要以下其中一個擴充模組:

以下是使用這個套件的範例:

 PHP |  copy code |? 
01
<?php
02
require_once 'Crypt/RSA.php';
03
 
04
// 產生一雙對稱密鑰
05
function generate_key_pair() {
06
    global $public_key,$private_key;
07
    $key_pair = new Crypt_RSA_KeyPair(32);
08
 
09
    // 從這雙密鑰中提取公鑰
10
    $public_key = $key_pair->getPublicKey();
11
 
12
    // 從這雙密鑰中提取密鑰
13
    $private_key = $key_pair->getPrivateKey();
14
}
15
 
16
// 監察執行時錯誤
17
function check_error(&$obj) {
18
    if ($obj->isError()) {
19
        $error = $obj->getLastError();
20
        switch ($error->getCode()) {
21
            case CRYPT_RSA_ERROR_WRONG_TAIL :
22
                // 無須做任何事
23
                break;
24
            default:
25
                // 顯示錯誤訊息然後退出
26
                echo 'error: ', $error->getMessage();
27
                exit;
28
        }
29
    }
30
}
31
 
32
$file = 'textfile.txt';
33
 
34
generate_key_pair();
35
$plain_text = file_get_contents($file);
36
 
37
// 把公鑰表達為一個字符串
38
$key = Crypt_RSA_Key::fromString($public_key->toString());
39
 
40
$rsa_obj = new Crypt_RSA;
41
check_error($rsa_obj);
42
 
43
// 用密鑰 $key 加密 $plain_text
44
$encrypted = $rsa_obj->encrypt($plain_text, $key);
45
 
46
$encrypted_file = @fopen('encrypted.txt','w');
47
$ok_encrypt = fwrite($encrypted_file,$encrypted);
48
if ($ok_encrypt) {
49
    echo '成功建立密文檔案 encrypted_file.txt!!!';
50
}
51
else{
52
    echo ("檔案寫入失敗!");
53
}
54
@fclose($encrypted_file);
55
 
56
$enc_text = $encrypted;
57
 
58
// 把密鑰表達為一個字符串
59
$key2 = Crypt_RSA_Key::fromString($private_key->toString());
60
check_error($key2);
61
 
62
// 檢查加密/解密函式的行為
63
$rsa_obj->setParams(array('dec_key' => $key2));
64
check_error($rsa_obj);
65
 
66
// 解密 $enc_text
67
$decrypted = $rsa_obj->decrypt($enc_text);
68
 
69
$newfile = @fopen('newfile.txt','w');
70
$ok_decrypt = @fwrite($newfile,$decrypted);
71
if ($ok_decrypt) {
72
    echo '成功建立解密文件 newfile.txt!!!';
73
}
74
else {
75
    echo ("檔案寫入失敗!");
76
}
77
@fclose($newfile);
78
 
79
?> 

用 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 |  copy code |? 
01
<?php
02
require_once 'Crypt/HMAC.php';
03
 
04
// 把字符 "0x0b" 重複二十次來產生一個密鑰
05
$key = str_repeat(chr(0x0b), 20);
06
 
07
// 產生一個 Crypt_HMAC 類的實體
08
$crypt = new Crypt_HMAC($key, 'md5');
09
 
10
// 散列函式
11
echo $crypt->hash('Hello');
12
 
13
$key = str_repeat(chr(0xaa), 10);
14
$data = str_repeat(chr(0xdd), 50);
15
 
16
// 把散列函式的密鑰設定為 $key
17
$crypt->setKey($key);
18
echo $crypt->hash($data)."\n";
19
?> 

使用 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 |  copy code |? 
01
<?php
02
// 引入 Diffie Hellman 函式
03
require_once 'Crypt/DiffieHellman.php';
04
 
05
// 為兩夥人設定所需的引數
06
$subject_1 = array('prime'=>'123', 'generator'=>'7', 'private'=>'3');
07
$subject_2 = array('prime'=>'123', 'generator'=>'7', 'private'=>'34');
08
 
09
// 運用 Diffie Hellman 算法
10
$subject_1_GK = new Crypt_DiffieHellman(
11
    $subject_1['prime'], $subject_1['generator'],
12
    $subject_1['private']);
13
$subject_2_GK = new Crypt_DiffieHellman(
14
    $subject_2['prime'], $subject_2['generator'],
15
    $subject_2['private']);
16
 
17
// 產生密鑰
18
$subject_1_GK->generateKeys();
19
$subject_2_GK->generateKeys();
20
 
21
// 計算密鑰
22
$subject_1_SK = $subject_1_GK->computeSecretKey(
23
    $subject_2_GK->getPublicKey())->getSharedSecretKey();
24
$subject_2_SK = $subject_2_GK->computeSecretKey(
25
    $subject_1_GK->getPublicKey())->getSharedSecretKey();
26
 
27
// 顯示密鑰
28
echo('Subject_1_SK:'.$subject_1_SK);
29
echo('Subject_2_SK:'.$subject_2_SK);
30
?> 

第二個程式示範用 Diffie Hellman 的 BINARY 模式產生密鑰:

 PHP |  copy code |? 
01
<?php
02
// 引入 Diffie Hellman 函式
03
require_once 'Crypt/DiffieHellman.php';
04
 
05
// 為兩夥人設定所需的引數
06
$subject_1 = array(
07
    'prime' => '9568094558049898340935098349053',
08
    'generator'=>'2',
09
    'private' => '2232370277237628823279273723742872289398723');
10
$subject_2 = array(
11
    'prime' => '9568094558049898340935098349053',
12
    'generator'=>'2',
13
    'private' => '0389237288721323987429834389298232433363463');
14
 
15
// 運用 Diffie Hellman 算法
16
$subject_1_GK = new Crypt_DiffieHellman(
17
    $subject_1['prime'], $subject_1['generator'],
18
    $subject_1['private']);
19
$subject_2_GK = new Crypt_DiffieHellman(
20
    $subject_2['prime'], $subject_2['generator'],
21
    $subject_2['private']);
22
 
23
// 產生密鑰
24
$subject_1_GK->generateKeys();
25
$subject_2_GK->generateKeys();
26
 
27
// 用 BINARY 模式計算密鑰
28
$subject_1_SK = $subject_1_GK->computeSecretKey(
29
    $subject_2_GK->getPublicKey(Crypt_DiffieHellman::BINARY),
30
    Crypt_DiffieHellman::BINARY)->
31
    getSharedSecretKey(Crypt_DiffieHellman::BINARY);
32
$subject_2_SK = $subject_2_GK->computeSecretKey(
33
    $subject_1_GK->getPublicKey(Crypt_DiffieHellman::BINARY),
34
    Crypt_DiffieHellman::BINARY)->
35
    getSharedSecretKey(Crypt_DiffieHellman::BINARY);
36
 
37
// 顯示密鑰
38
echo('subject_1_SK:'.$subject_1_SK);
39
echo('subject_2_SK:'.$subject_2_SK);
40
?> 

使用以上提及的各式各樣加密方案,你應該可以做到任何想做的事,加密是一個敏感的安全問題,正如你見到的,解決方案和實作都很多,本文的資訊可以幫助你認識這個課題,但要更進一步,只有在系統安全上的經驗和努力工作,才能幫助你選擇合適的加密方案,使你在安全性、速度、和實作時間上取得平衡。

發表回覆

  

  

  

您可使用下列 these HTML標籤

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>