由於項目的需要,要寫一個能生成“授權碼”的類(授權碼主要包含項目使用的到期時間),生成的授權碼將會寫入到一個文件當中,每當項目運行的時候,會自動讀取出文件中的密文,然後使用唯一的“密鑰”來調用某個函數,對密文進行解密,從中解讀出項目的使用到期時間。
之前,自己有先試著寫了下,主要是base64+md5+反轉字符串。算法太過簡單,很容易被破解,而且也沒有能過做到“密鑰”在加解密中的重要性,故而捨之。
後來,查找了相關資料,發現,原來PHP中內置了一個功能強大的函數庫,即Mcrypt。
其實,mcrypt本身就提供了強大的加密解密方法,並且支持很多流行的公開的加密算法,如DES, TripleDES, Blowfish (默認), 3-WAY, SAFER-SK64, SAFER-SK128, TWOFISH, TEA, RC2 and GOST in CBC, OFB, CFB and ECB。
這裡簡單的引用下百度百科關於“加密算法”的解釋:
數據加密的基本過程就是對原來為明文的文件或數據按某種算法進行處理,使其成為不可讀的一段代碼,通常稱為“密文”,使其只能在輸入相應的密鑰之後才能顯示出本來內容,通過這樣的途徑來達到保護數據不被非法人竊取、閱讀的目的。 該過程的逆過程為解密,即將該編碼信息轉化為其原來數據的過程。
加密技術通常分為兩大類:“對稱式”和“非對稱式”。
對稱式加密就是加密和解密使用同一個密鑰,通常稱之為“Session Key ”這種加密技術目前被廣泛采用,如美國政府所采用的DES加密標准就是一種典型的“對稱式”加密法,它的Session Key長度為56Bits。
非對稱式加密就是加密和解密所使用的不是同一個密鑰,通常有兩個密鑰,稱為“公鑰”和“私鑰”,它們兩個必需配對使用,否則不能打開加密文件。這裡的“公鑰”是指可以對外公布的,“私鑰”則不能,只能由持有人一個人知道。它的優越性就在這裡,因為對稱式的加密方法如果是在網絡上傳輸加密文件就很難把密鑰告訴對方,不管用什麼方法都有可能被別竊聽到。而非對稱式的加密方法有兩個密鑰,且其中的“公鑰”是可以公開的,也就不怕別人知道,收件人解密時只要用自己的私鑰即可以,這樣就很好地避免了密鑰的傳輸安全性問題。
前面提到過,mcrypt支持多種國際公開的算法,我在這次的項目中使用的是DES算法,DES(Data Encryption Standard),這是一個對稱算法,速度較快,適用於加密大量數據的場合。
接下來我簡要的說明下加密類中會使用到的幾個函數。
--------------------------------------------------------------------------------
resource mcrypt_module_open ( string $algorithm , string $algorithm_directory , string $mode , string $mode_directory )
參數$algorithm:要使用的算法,可以通過函數mcrypt_list_algorithms()來查看所有支持的算法名稱
參數$ mode:要使用哪種模式,同樣,可以內置函數mcrypt_list_algorithms()來查看所有支持的模式
--------------------------------------------------------------------------------
int mcrypt_enc_get_iv_size ( resource $td )
該函數將返回使用的算法的初始化向量(IV)的大小(看著有點抽象),如果IV在算法中被忽略的話講返回0。
參數$td就是使用mcrypt_module_open函數的返回值。
--------------------------------------------------------------------------------
string mcrypt_create_iv ( int $size [, int $source = MCRYPT_DEV_RANDOM ] )
該函數會創建一個初始化向量(IV)
參數:
$source可以使MCRYPT_RAND,MCRYPT_DEV_RANDOM,
MCRYPT_DEV_URANDOM
注意:PHP5.3.0以上的版本,只支持MCRYPT_RAND
返回值:
成功,則返回一個字符串型的初始向量,失敗,則返回False
--------------------------------------------------------------------------------
int mcrypt_enc_get_key_size ( resource $td )
該函數能夠取得當前算法所支持的最大的密鑰長度(以字節計算)
int mcrypt_generic_init ( resource $td , string $key , string $iv )
調用mcrypt_generic() or mdecrypt_generic()之前,首先需要調用該函數,該函數能夠幫我們初始化緩沖區,用以存放加密數據。
參數$key:密鑰長度,記住,當前$key的值,要比函數mcrypt_enc_get_key_size()返回的值小
問題:$key的值,越大越好嗎?有同學會的,幫忙解答下。
--------------------------------------------------------------------------------
string mcrypt_generic ( resource $td , string $data )
完成了前面的工作之後,就可以調用該函數用以加密數據了。
參數$data:要加密的數據內容
返回值:返回加密後的密文
--------------------------------------------------------------------------------
bool mcrypt_generic_deinit ( resource $td )
該函數能夠幫我們卸載當前使用的加密模塊。
返回值
成功時返回 TRUE, 或者在失敗時返回 FALSE.
--------------------------------------------------------------------------------
string mdecrypt_generic ( resource $td , string $data )
該函數能夠用來解密數據。
注意:解密後的數據可能比實際上的更長,可能會有後續的\0,需去掉
--------------------------------------------------------------------------------
bool mcrypt_module_close ( resource $td )
關閉指定的加密模塊資源句柄
返回值
成功時返回 TRUE, 或者在失敗時返回 FALSE.
--------------------------------------------------------------------------------
貼上代碼:
復制代碼 代碼如下:
<?php
class authCode {
public $ttl;//到期時間 時間格式:20120101(年月日)
public $key_1;//密鑰1
public $key_2;//密鑰2
public $td;
public $ks;//密鑰的長度
public $iv;//初始向量
public $salt;//鹽值(某個特定的字符串)
public $encode;//加密後的信息
public $return_array = array(); // 返回帶有MAC地址的字串數組
public $mac_addr;//mac地址
public $filepath;//保存密文的文件路徑
public function __construct(){
//獲取物理地址
$this->mac_addr=$this->getmac(PHP_OS);
$this->filepath="./licence.txt";
$this->ttl="20120619";//到期時間
$this->salt="~!@#$";//鹽值,用以提高密文的安全性
// echo "<pre>".print_r(mcrypt_list_algorithms ())."</pre>";
// echo "<pre>".print_r(mcrypt_list_modes())."</pre>";
}
/**
* 對明文信息進行加密
* @param $key 密鑰
*/
public function encode($key) {
$this->td = mcrypt_module_open(MCRYPT_DES,'','ecb',''); //使用MCRYPT_DES算法,ecb模式
$size=mcrypt_enc_get_iv_size($this->td);//設置初始向量的大小
$this->iv = mcrypt_create_iv($size, MCRYPT_RAND);//創建初始向量
$this->ks = mcrypt_enc_get_key_size($this->td);//返回所支持的最大的密鑰長度(以字節計算)
$this->key_1 = substr(md5(md5($key).$this->salt),0,$this->ks);
mcrypt_generic_init($this->td, $this->key_1, $this->iv); //初始處理
//要保存到明文
$con=$this->mac_addr.$this->ttl;
//加密
$this->encode = mcrypt_generic($this->td, $con);
//結束處理
mcrypt_generic_deinit($this->td);
//將密文保存到文件中
$this->savetofile();
}
/**
* 對密文進行解密
* @param $key 密鑰
*/
public function decode($key) {
try {
if (!file_exists($this->filepath)){
throw new Exception("授權文件不存在");
}else{//如果授權文件存在的話,則讀取授權文件中的密文
$fp=fopen($this->filepath,'r');
$secret=fread($fp,filesize($this->filepath));
$this->key_2 = substr(md5(md5($key).$this->salt),0,$this->ks);
//初始解密處理
mcrypt_generic_init($this->td, $this->key_2, $this->iv);
//解密
$decrypted = mdecrypt_generic($this->td, $secret);
//解密後,可能會有後續的\0,需去掉
$decrypted=trim($decrypted) . "\n";
//結束
mcrypt_generic_deinit($this->td);
mcrypt_module_close($this->td);
return $decrypted;
}
}catch (Exception $e){
echo $e->getMessage();
}
}
/**
* 將密文保存到文件中
*/
public function savetofile(){
try {
$fp=fopen($this->filepath,'w+');
if (!$fp){
throw new Exception("文件操作失敗");
}
fwrite($fp,$this->encode);
fclose($fp);
}catch (Exception $e){
echo $e->getMessage();
}
}
/**
* 取得服務器的MAC地址
*/
public function getmac($os_type){
switch ( strtolower($os_type) ){
case "linux":
$this->forLinux();
break;
case "solaris":
break;
case "unix":
break;
case "aix":
break;
default:
$this->forWindows();
break;
}
$temp_array = array();
foreach( $this->return_array as $value ){
if (preg_match("/[0-9a-f][0-9a-f][:-]"."[0-9a-f][0-9a-f][:-]"."[0-9a-f][0-9a-f][:-]"."[0-9a-f][0-9a-f][:-]"."[0-9a-f][0-9a-f][:-]"."[0-9a-f][0-9a-f]/i",$value,$temp_array )){
$mac_addr = $temp_array[0];
break;
}
}
unset($temp_array);
return $mac_addr;
}
/**
* windows服務器下執行ipconfig命令
*/
public function forWindows(){
@exec("ipconfig /all", $this->return_array);
if ( $this->return_array )
return $this->return_array;
else{
$ipconfig = $_SERVER["WINDIR"]."\system32\ipconfig.exe";
if ( is_file($ipconfig) )
@exec($ipconfig." /all", $this->return_array);
else
@exec($_SERVER["WINDIR"]."\system\ipconfig.exe /all", $this->return_array);
return $this->return_array;
}
}
/**
* Linux服務器下執行ifconfig命令
*/
public function forLinux(){
@exec("ifconfig -a", $this->return_array);
return $this->return_array;
}
}
$code=new authCode();
//加密
$code->encode("~!@#$%^");
//解密
echo $code->decode("~!@#$%^");
?>
原創文章:WEB開發_小飛