由於專案的需要,要寫一個能產生「授權碼」的類別(授權碼主要包含專案使用的到期時間),產生的授權碼將會寫入一個檔案當中,每當專案運作的時候,會自動讀取出檔案中的密文,然後使用唯一的「金鑰」來呼叫某個函數,對密文進行解密,從中解讀出專案的使用到期時間。
之前,自己有先試著寫了下,主要是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()之前,首先需要呼叫mcrypt_generic() 或 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 class="brush:php;toolbar:false">".print_r(mcrypt_list_algorithms ()).""; // echo "
".print_r(mcrypt_list_modes()).""; } /** * 对明文信息进行加密 * @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("~!@#$%^"); ?>
更多通过PHP的内置函数,通过DES算法对数据加密和解密相关文章请关注PHP中文网!