使用PHP内置的DES算法函数实现数据加密解密

mcrypt本身就提供了强大的加密解密方法
服务器君一共花费了273.926 ms进行了5次数据库查询,努力地为您提供了这个页面。
试试阅读模式?希望听取您的建议

由于项目的需要,要写一个能生成“授权码”的类(授权码主要包含项目使用的到期时间),生成的授权码将会写入到一个文件当中,每当项目运行的时候,会自动读取出文件中的密文,然后使用唯一的“密钥”来调用某个函数,对密文进行解密,从中解读出项目的使用到期时间。

之前,自己有先试着写了下,主要是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),这是一个对称算法,速度较快,适用于加密大量数据的场合。

用到的几个加密函数介绍

接下来我简要的说明下加密类中会使用到的几个函数。

1. resource mcrypt_module_open ( string $algorithm , string $algorithm_directory , string $mode , string $mode_directory )

  • 参数$algorithm:要使用的算法,可以通过函数mcrypt_list_algorithms()来查看所有支持的算法名称
  • 参数$ mode:要使用哪种模式,同样,可以内置函数mcrypt_list_algorithms()来查看所有支持的模式

2. int mcrypt_enc_get_iv_size ( resource $td )

  • 该函数将返回使用的算法的初始化向量(IV)的大小(看着有点抽象),如果IV在算法中被忽略的话讲返回0。
  • 参数$td就是使用mcrypt_module_open函数的返回值。

3. string mcrypt_create_iv ( int $size [, int $source = MCRYPT_DEV_RANDOM ] )

该函数会创建一个初始化向量(IV)

参数:$source可以使MCRYPT_RAND,MCRYPT_DEV_RANDOMMCRYPT_DEV_URANDOM

注意:PHP5.3.0以上的版本,只支持MCRYPT_RAND

返回值:成功,则返回一个字符串型的初始向量,失败,则返回False

4. 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的值,越大越好吗?有同学会的,帮忙解答下。

5. string mcrypt_generic ( resource $td , string $data )

完成了前面的工作之后,就可以调用该函数用以加密数据了。

  • 参数$data:要加密的数据内容
  • 返回值:返回加密后的密文

6. bool mcrypt_generic_deinit ( resource $td )

该函数能够帮我们卸载当前使用的加密模块。

返回值:成功时返回 TRUE, 或者在失败时返回 FALSE.

7. string mdecrypt_generic ( resource $td , string $data )

该函数能够用来解密数据。

注意:解密后的数据可能比实际上的更长,可能会有后续的\0,需去掉

8. 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("~!@#$%^");
?>

本文地址:http://www.nowamagic.net/librarys/veda/detail/1953,欢迎访问原出处。

不打个分吗?

转载随意,但请带上本文地址:

http://www.nowamagic.net/librarys/veda/detail/1953

如果你认为这篇文章值得更多人阅读,欢迎使用下面的分享功能。
小提示:您可以按快捷键 Ctrl + D,或点此 加入收藏

大家都在看

阅读一百本计算机著作吧,少年

很多人觉得自己技术进步很慢,学习效率低,我觉得一个重要原因是看的书少了。多少是多呢?起码得看3、4、5、6米吧。给个具体的数量,那就100本书吧。很多人知识结构不好而且不系统,因为在特定领域有一个足够量的知识量+足够良好的知识结构,系统化以后就足以应对大量未曾遇到过的问题。

奉劝自学者:构建特定领域的知识结构体系的路径中再也没有比学习该专业的专业课程更好的了。如果我的知识结构体系足以囊括面试官的大部分甚至吞并他的知识结构体系的话,读到他言语中的一个词我们就已经知道他要表达什么,我们可以让他坐“上位”毕竟他是面试官,但是在知识结构体系以及心理上我们就居高临下。

所以,阅读一百本计算机著作吧,少年!

《设计模式:可复用面向对象软件的基础》 Erich Gamma (作者), Richard Helm (作者), Ralph Johnson (作者), John Vlissides (作者), 李英军 (译者), 等 (译者)

《设计模式:可复用面向对象软件的基础》是引导读者走出软件设计迷宫的指路明灯,凝聚了软件开发界几十年设计经验的结晶。四位顶尖的面向对象领域专家精心选取了最具价值的设计实践,加以分类整理和命名,并用简洁而易于重用的形式表达出来。本书已经成为面向对象技术人员的圣经和词典,书中定义的23个模式逐渐成为开发界技术交流所必备的基础知识和语汇。

更多计算机宝库...