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      
$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 需要執行密集的數學計算,並需要以下其中一個擴充模組:

以下是使用這個套件的範例:
<?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);

?>

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


發表新回應

  • Images can be added to this post.

更多關於格式化選項的資訊

Captcha
以下問題用來確認閣下是一個真人,防止機器人濫發垃圾文章。