php实现的rc4加密解密类定义与用法示例


Posted in PHP onAugust 16, 2018

本文实例讲述了php实现的rc4加密解密类。分享给大家供大家参考,具体如下:

class.rc4crypt.php文件:

<?php
/* 
 * By julying.com
 */
define('CRYPT_RC4_MODE_INTERNAL', 1);
define('CRYPT_RC4_MODE_MCRYPT', 2);
define('CRYPT_RC4_ENCRYPT', 0);
define('CRYPT_RC4_DECRYPT', 1);
class Crypt_RC4 {
 /**
  * The Key
  *
  * @see Crypt_RC4::setKey()
  * @var String
  * @access private
  */
 var $key = "\0";
 /**
  * The Key Stream for encryption
  *
  * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
  *
  * @see Crypt_RC4::setKey()
  * @var Array
  * @access private
  */
 var $encryptStream = false;
 /**
  * The Key Stream for decryption
  *
  * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
  *
  * @see Crypt_RC4::setKey()
  * @var Array
  * @access private
  */
 var $decryptStream = false;
 /**
  * The $i and $j indexes for encryption
  *
  * @see Crypt_RC4::_crypt()
  * @var Integer
  * @access private
  */
 var $encryptIndex = 0;
 /**
  * The $i and $j indexes for decryption
  *
  * @see Crypt_RC4::_crypt()
  * @var Integer
  * @access private
  */
 var $decryptIndex = 0;
 /**
  * MCrypt parameters
  *
  * @see Crypt_RC4::setMCrypt()
  * @var Array
  * @access private
  */
 var $mcrypt = array('', '');
 /**
  * The Encryption Algorithm
  *
  * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
  *
  * @see Crypt_RC4::Crypt_RC4()
  * @var Integer
  * @access private
  */
 var $mode;
 /**
  * Default Constructor.
  *
  * Determines whether or not the mcrypt extension should be used.
  *
  * @param optional Integer $mode
  * @return Crypt_RC4
  * @access public
  */
 var $continuousBuffer ;
 function Crypt_RC4()
 {
  if ( !defined('CRYPT_RC4_MODE') ) {
   switch (true) {
    case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')):
     // i'd check to see if rc4 was supported, by doing in_array('arcfour', mcrypt_list_algorithms('')),
     // but since that can be changed after the object has been created, there doesn't seem to be
     // a lot of point...
     define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
     break;
    default:
     define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
   }
  }
  switch ( CRYPT_RC4_MODE ) {
   case CRYPT_RC4_MODE_MCRYPT:
    switch (true) {
     case defined('MCRYPT_ARCFOUR'):
      $this->mode = MCRYPT_ARCFOUR;
      break;
     case defined('MCRYPT_RC4');
      $this->mode = MCRYPT_RC4;
    }
  }
 }
 /**
  * Sets the key.
  *
  * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
  * be used. If no key is explicitly set, it'll be assumed to be a single null byte.
  *
  * @access public
  * @param String $key
  */
 function setKey($key)
 {
  $this->key = $key;
  if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
   return;
  }
  $keyLength = strlen($key);
  $keyStream = array();
  for ($i = 0; $i < 256; $i++) {
   $keyStream[$i] = $i;
  }
  $j = 0;
  for ($i = 0; $i < 256; $i++) {
   $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
   $temp = $keyStream[$i];
   $keyStream[$i] = $keyStream[$j];
   $keyStream[$j] = $temp;
  }
  $this->encryptIndex = $this->decryptIndex = array(0, 0);
  $this->encryptStream = $this->decryptStream = $keyStream;
 }
 /**
  * Dummy function.
  *
  * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
  * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
  * calling setKey().
  *
  * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
  * the IV's are relatively easy to predict, an attack described by
  * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
  * can be used to quickly guess at the rest of the key. The following links elaborate:
  *
  * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
  * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
  *
  * @param String $iv
  * @see Crypt_RC4::setKey()
  * @access public
  */
 function setIV($iv)
 {
 }
 /**
  * Sets MCrypt parameters. (optional)
  *
  * If MCrypt is being used, empty strings will be used, unless otherwise specified.
  *
  * @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open
  * @access public
  * @param optional Integer $algorithm_directory
  * @param optional Integer $mode_directory
  */
 function setMCrypt($algorithm_directory = '', $mode_directory = '')
 {
  if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
   $this->mcrypt = array($algorithm_directory, $mode_directory);
   $this->_closeMCrypt();
  }
 }
 /**
  * Encrypts a message.
  *
  * @see Crypt_RC4::_crypt()
  * @access public
  * @param String $plaintext
  */
 function encrypt($plaintext)
 {
  return self::toHex($this->_crypt($plaintext, CRYPT_RC4_ENCRYPT));
 }
 /**
  * Decrypts a message.
  *
  * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
  * Atleast if the continuous buffer is disabled.
  *
  * @see Crypt_RC4::_crypt()
  * @access public
  * @param String $ciphertext
  */
 function decrypt($ciphertext)
 {
  $ciphertext = self::fromHex($ciphertext);
  return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
 }
 /**
  * Encrypts or decrypts a message.
  *
  * @see Crypt_RC4::encrypt()
  * @see Crypt_RC4::decrypt()
  * @access private
  * @param String $text
  * @param Integer $mode
  */
 function _crypt($text, $mode)
 {
  if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
   $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
   if ($this->$keyStream === false) {
    $this->$keyStream = mcrypt_module_open($this->mode, $this->mcrypt[0], MCRYPT_MODE_STREAM, $this->mcrypt[1]);
    mcrypt_generic_init($this->$keyStream, $this->key, '');
   } else if (!$this->continuousBuffer) {
    mcrypt_generic_init($this->$keyStream, $this->key, '');
   }
   $newText = mcrypt_generic($this->$keyStream, $text);
   if (!$this->continuousBuffer) {
    mcrypt_generic_deinit($this->$keyStream);
   }
   return $newText;
  }
  if ($this->encryptStream === false) {
   $this->setKey($this->key);
  }
  switch ($mode) {
   case CRYPT_RC4_ENCRYPT:
    $keyStream = $this->encryptStream;
    list($i, $j) = $this->encryptIndex;
    break;
   case CRYPT_RC4_DECRYPT:
    $keyStream = $this->decryptStream;
    list($i, $j) = $this->decryptIndex;
  }
  $newText = '';
  for ($k = 0; $k < strlen($text); $k++) {
   $i = ($i + 1) & 255;
   $j = ($j + $keyStream[$i]) & 255;
   $temp = $keyStream[$i];
   $keyStream[$i] = $keyStream[$j];
   $keyStream[$j] = $temp;
   $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
   $newText.= chr(ord($text[$k]) ^ $temp);
  }
  if ($this->continuousBuffer) {
   switch ($mode) {
    case CRYPT_RC4_ENCRYPT:
     $this->encryptStream = $keyStream;
     $this->encryptIndex = array($i, $j);
     break;
    case CRYPT_RC4_DECRYPT:
     $this->decryptStream = $keyStream;
     $this->decryptIndex = array($i, $j);
   }
  }
  return $newText;
 }
 /**
  * Treat consecutive "packets" as if they are a continuous buffer.
  *
  * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
  * will yield different outputs:
  *
  * <code>
  * echo $rc4->encrypt(substr($plaintext, 0, 8));
  * echo $rc4->encrypt(substr($plaintext, 8, 8));
  * </code>
  * <code>
  * echo $rc4->encrypt($plaintext);
  * </code>
  *
  * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
  * another, as demonstrated with the following:
  *
  * <code>
  * $rc4->encrypt(substr($plaintext, 0, 8));
  * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
  * </code>
  * <code>
  * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
  * </code>
  *
  * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
  * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
  * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
  *
  * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
  * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
  * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
  * however, they are also less intuitive and more likely to cause you problems.
  *
  * @see Crypt_RC4::disableContinuousBuffer()
  * @access public
  */
 function enableContinuousBuffer()
 {
  $this->continuousBuffer = true;
 }
 /**
  * Treat consecutive packets as if they are a discontinuous buffer.
  *
  * The default behavior.
  *
  * @see Crypt_RC4::enableContinuousBuffer()
  * @access public
  */
 function disableContinuousBuffer()
 {
  if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
   $this->encryptIndex = $this->decryptIndex = array(0, 0);
   $this->setKey($this->key);
  }
  $this->continuousBuffer = false;
 }
 /**
  * Dummy function.
  *
  * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
  * included is so that you can switch between a block cipher and a stream cipher transparently.
  *
  * @see Crypt_RC4::disablePadding()
  * @access public
  */
 function enablePadding()
 {
 }
 /**
  * Dummy function.
  *
  * @see Crypt_RC4::enablePadding()
  * @access public
  */
 function disablePadding()
 {
 }
 /**
  * Class destructor.
  *
  * Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really
  * needs to be called if mcrypt is being used.
  *
  * @access public
  */
 function __destruct()
 {
  if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
   $this->_closeMCrypt();
  }
 }
 /**
  * Properly close the MCrypt objects.
  *
  * @access prviate
  */
 function _closeMCrypt()
 {
  if ( $this->encryptStream !== false ) {
   if ( $this->continuousBuffer ) {
    mcrypt_generic_deinit($this->encryptStream);
   }
   mcrypt_module_close($this->encryptStream);
   $this->encryptStream = false;
  }
  if ( $this->decryptStream !== false ) {
   if ( $this->continuousBuffer ) {
    mcrypt_generic_deinit($this->decryptStream);
   }
   mcrypt_module_close($this->decryptStream);
   $this->decryptStream = false;
  }
 }
 // @function fromHex 把十六进制数转换成字符串
 function toHex($sa , $len = 0){
  $buf = "";
  if( $len == 0 )
   $len = strlen($sa) ;
  for ($i = 0; $i < $len; $i++)
  {
   $val = dechex(ord($sa{$i}));  
   if(strlen($val)< 2) 
    $val = "0".$val;
   $buf .= $val;
  }
  return $buf;
 }
 // @function fromHex 把十六进制数转换成字符串 
 function fromHex($sa){
  $buf = "";
  $len = strlen($sa) ;
  for($i = 0; $i < $len; $i += 2){
   $val = chr(hexdec(substr($sa, $i, 2)));
   $buf .= $val;
  }
  return $buf;
 }
}

使用方法:

include('class.rc4crypt.php');
$rc4 = new Crypt_RC4();
$rc4 -> setKey('21sd54a1w5q');
$text = '3water.com';
echo $x = $rc4->encrypt($text);//加密
echo '<br />';
echo $rc4->decrypt( $x) ;//解密

运行结果:

7907bb7c6694f179e9642ebd
3water.com

PHP 相关文章推荐
php Sql Server连接失败问题及解决办法
Aug 07 PHP
php 删除记录同时删除图片文件的实现代码
May 12 PHP
解析PayPal支付接口的PHP开发方式
Nov 28 PHP
yii实现图片上传及缩略图生成的方法
Dec 04 PHP
php上传文件问题汇总
Jan 30 PHP
Laravel 5框架学习之数据库迁移(Migrations)
Apr 08 PHP
php关联数组快速排序的方法
Apr 17 PHP
PHP图像处理类库MagickWand用法实例分析
May 21 PHP
ThinkPHP表单令牌错误的相关解决方法分析
May 20 PHP
PHP 自动加载的简单实现(推荐)
Aug 12 PHP
PHP去除字符串最后一个字符的三种方法实例
Mar 01 PHP
PHP 扩展Memcached命令用法实例总结
Jun 04 PHP
Laravel框架实现定时发布任务的方法
Aug 16 #PHP
Laravel框架使用monolog_mysql实现将系统日志信息保存到mysql数据库的方法
Aug 16 #PHP
Laravel中的chunk组块结果集处理与注意问题
Aug 15 #PHP
PHP curl批处理及多请求并发实现方法分析
Aug 15 #PHP
php使用curl_init()和curl_multi_init()多线程的速度比较详解
Aug 15 #PHP
php使用curl获取header检测开启GZip压缩的方法
Aug 15 #PHP
深入研究PHP中的preg_replace和代码执行
Aug 15 #PHP
You might like
深入PHP获取随机数字和字母的方法详解
2013/06/06 PHP
PHP反射机制用法实例
2014/08/28 PHP
PHP针对多用户实现更换头像功能
2016/09/04 PHP
浅谈PHP各环境下的伪静态配置
2019/03/13 PHP
JavaScript的Cookies
2008/01/16 Javascript
加载jQuery后$冲突的解决办法
2010/07/09 Javascript
将文本输入框内容加入表中的js代码
2013/08/18 Javascript
Flex通过JS获取客户端IP和计算机名的实例代码
2013/11/21 Javascript
js中for in的用法示例解析
2013/12/25 Javascript
改变隐藏的input中value的值代码
2013/12/30 Javascript
javascript获取dom的下一个节点方法
2014/09/05 Javascript
javascript实现很浪漫的气泡冒出特效
2020/09/05 Javascript
用原生JS实现简单的多选框功能
2017/06/12 Javascript
react 组件传值的三种方法
2019/06/03 Javascript
vue中get请求如何传递数组参数的方法示例
2019/11/08 Javascript
ES6如何用一句代码实现函数的柯里化
2020/01/18 Javascript
vue和H5 draggable实现拖拽并替换效果
2020/07/29 Javascript
[02:41]辉夜杯现场一家三口 “我爸玩风行 我玩血魔”
2015/12/27 DOTA
[00:34]拔城逐梦,热血永恒!2020(秋)完美世界城市挑战赛报名开启
2020/10/09 DOTA
python基础教程之Hello World!
2014/08/29 Python
python用10行代码实现对黄色图片的检测功能
2015/08/10 Python
日常整理python执行系统命令的常见方法(全)
2015/10/22 Python
python 获取微信好友列表的方法(微信web)
2019/02/21 Python
用Python批量把文件复制到另一个文件夹的实现方法
2019/08/16 Python
Python使用itchat模块实现群聊转发,自动回复功能示例
2019/08/26 Python
python语言中有算法吗
2020/06/16 Python
详解webapp页面滚动卡顿的解决办法
2018/12/26 HTML / CSS
Tripadvisor新西兰:阅读评论,比较价格和酒店预订
2018/02/10 全球购物
哈利波特商店:Harry Potter Shop
2018/11/30 全球购物
公务员的自我鉴定
2013/10/26 职场文书
高一历史教学反思
2014/01/13 职场文书
市优秀教师事迹材料
2014/02/05 职场文书
Nginx下配置Https证书详细过程
2021/04/01 Servers
Java使用httpRequest+Jsoup爬取红蓝球号码
2021/07/02 Java/Android
SpringBoot集成Druid连接池连接MySQL8.0.11
2021/07/02 Java/Android
Java基于Dijkstra算法实现校园导游程序
2022/03/17 Java/Android