Des.class.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. namespace Think\Crypt\Driver;
  12. /**
  13. * Des 加密实现类
  14. * Converted from JavaScript to PHP by Jim Gibbs, June 2004 Paul Tero, July 2001
  15. * Optimised for performance with large blocks by Michael Hayworth, November 2001
  16. * http://www.netdealing.com
  17. */
  18. class Des
  19. {
  20. /**
  21. * 加密字符串
  22. * @param string $str 字符串
  23. * @param string $key 加密key
  24. * @param integer $expire 有效期(秒)
  25. * @return string
  26. */
  27. public static function encrypt($str, $key, $expire = 0)
  28. {
  29. if ("" == $str) {
  30. return "";
  31. }
  32. $expire = sprintf('%010d', $expire ? $expire + time() : 0);
  33. $str = $expire . $str;
  34. return self::_des($key, $str, 1);
  35. }
  36. /**
  37. * 解密字符串
  38. * @param string $str 字符串
  39. * @param string $key 加密key
  40. * @return string
  41. */
  42. public static function decrypt($str, $key)
  43. {
  44. if ("" == $str) {
  45. return "";
  46. }
  47. $data = self::_des($key, $str, 0);
  48. $expire = substr($data, 0, 10);
  49. if ($expire > 0 && $expire < time()) {
  50. return '';
  51. }
  52. $data = substr($data, 10);
  53. return $data;
  54. }
  55. /**
  56. * Des算法
  57. * @param string $str 字符串
  58. * @param string $key 加密key
  59. * @return string
  60. */
  61. private static function _des($key, $message, $encrypt, $mode = 0, $iv = null)
  62. {
  63. //declaring this locally speeds things up a bit
  64. $spfunction1 = array(0x1010400, 0, 0x10000, 0x1010404, 0x1010004, 0x10404, 0x4, 0x10000, 0x400, 0x1010400, 0x1010404, 0x400, 0x1000404, 0x1010004, 0x1000000, 0x4, 0x404, 0x1000400, 0x1000400, 0x10400, 0x10400, 0x1010000, 0x1010000, 0x1000404, 0x10004, 0x1000004, 0x1000004, 0x10004, 0, 0x404, 0x10404, 0x1000000, 0x10000, 0x1010404, 0x4, 0x1010000, 0x1010400, 0x1000000, 0x1000000, 0x400, 0x1010004, 0x10000, 0x10400, 0x1000004, 0x400, 0x4, 0x1000404, 0x10404, 0x1010404, 0x10004, 0x1010000, 0x1000404, 0x1000004, 0x404, 0x10404, 0x1010400, 0x404, 0x1000400, 0x1000400, 0, 0x10004, 0x10400, 0, 0x1010004);
  65. $spfunction2 = array(-0x7fef7fe0, -0x7fff8000, 0x8000, 0x108020, 0x100000, 0x20, -0x7fefffe0, -0x7fff7fe0, -0x7fffffe0, -0x7fef7fe0, -0x7fef8000, -0x80000000, -0x7fff8000, 0x100000, 0x20, -0x7fefffe0, 0x108000, 0x100020, -0x7fff7fe0, 0, -0x80000000, 0x8000, 0x108020, -0x7ff00000, 0x100020, -0x7fffffe0, 0, 0x108000, 0x8020, -0x7fef8000, -0x7ff00000, 0x8020, 0, 0x108020, -0x7fefffe0, 0x100000, -0x7fff7fe0, -0x7ff00000, -0x7fef8000, 0x8000, -0x7ff00000, -0x7fff8000, 0x20, -0x7fef7fe0, 0x108020, 0x20, 0x8000, -0x80000000, 0x8020, -0x7fef8000, 0x100000, -0x7fffffe0, 0x100020, -0x7fff7fe0, -0x7fffffe0, 0x100020, 0x108000, 0, -0x7fff8000, 0x8020, -0x80000000, -0x7fefffe0, -0x7fef7fe0, 0x108000);
  66. $spfunction3 = array(0x208, 0x8020200, 0, 0x8020008, 0x8000200, 0, 0x20208, 0x8000200, 0x20008, 0x8000008, 0x8000008, 0x20000, 0x8020208, 0x20008, 0x8020000, 0x208, 0x8000000, 0x8, 0x8020200, 0x200, 0x20200, 0x8020000, 0x8020008, 0x20208, 0x8000208, 0x20200, 0x20000, 0x8000208, 0x8, 0x8020208, 0x200, 0x8000000, 0x8020200, 0x8000000, 0x20008, 0x208, 0x20000, 0x8020200, 0x8000200, 0, 0x200, 0x20008, 0x8020208, 0x8000200, 0x8000008, 0x200, 0, 0x8020008, 0x8000208, 0x20000, 0x8000000, 0x8020208, 0x8, 0x20208, 0x20200, 0x8000008, 0x8020000, 0x8000208, 0x208, 0x8020000, 0x20208, 0x8, 0x8020008, 0x20200);
  67. $spfunction4 = array(0x802001, 0x2081, 0x2081, 0x80, 0x802080, 0x800081, 0x800001, 0x2001, 0, 0x802000, 0x802000, 0x802081, 0x81, 0, 0x800080, 0x800001, 0x1, 0x2000, 0x800000, 0x802001, 0x80, 0x800000, 0x2001, 0x2080, 0x800081, 0x1, 0x2080, 0x800080, 0x2000, 0x802080, 0x802081, 0x81, 0x800080, 0x800001, 0x802000, 0x802081, 0x81, 0, 0, 0x802000, 0x2080, 0x800080, 0x800081, 0x1, 0x802001, 0x2081, 0x2081, 0x80, 0x802081, 0x81, 0x1, 0x2000, 0x800001, 0x2001, 0x802080, 0x800081, 0x2001, 0x2080, 0x800000, 0x802001, 0x80, 0x800000, 0x2000, 0x802080);
  68. $spfunction5 = array(0x100, 0x2080100, 0x2080000, 0x42000100, 0x80000, 0x100, 0x40000000, 0x2080000, 0x40080100, 0x80000, 0x2000100, 0x40080100, 0x42000100, 0x42080000, 0x80100, 0x40000000, 0x2000000, 0x40080000, 0x40080000, 0, 0x40000100, 0x42080100, 0x42080100, 0x2000100, 0x42080000, 0x40000100, 0, 0x42000000, 0x2080100, 0x2000000, 0x42000000, 0x80100, 0x80000, 0x42000100, 0x100, 0x2000000, 0x40000000, 0x2080000, 0x42000100, 0x40080100, 0x2000100, 0x40000000, 0x42080000, 0x2080100, 0x40080100, 0x100, 0x2000000, 0x42080000, 0x42080100, 0x80100, 0x42000000, 0x42080100, 0x2080000, 0, 0x40080000, 0x42000000, 0x80100, 0x2000100, 0x40000100, 0x80000, 0, 0x40080000, 0x2080100, 0x40000100);
  69. $spfunction6 = array(0x20000010, 0x20400000, 0x4000, 0x20404010, 0x20400000, 0x10, 0x20404010, 0x400000, 0x20004000, 0x404010, 0x400000, 0x20000010, 0x400010, 0x20004000, 0x20000000, 0x4010, 0, 0x400010, 0x20004010, 0x4000, 0x404000, 0x20004010, 0x10, 0x20400010, 0x20400010, 0, 0x404010, 0x20404000, 0x4010, 0x404000, 0x20404000, 0x20000000, 0x20004000, 0x10, 0x20400010, 0x404000, 0x20404010, 0x400000, 0x4010, 0x20000010, 0x400000, 0x20004000, 0x20000000, 0x4010, 0x20000010, 0x20404010, 0x404000, 0x20400000, 0x404010, 0x20404000, 0, 0x20400010, 0x10, 0x4000, 0x20400000, 0x404010, 0x4000, 0x400010, 0x20004010, 0, 0x20404000, 0x20000000, 0x400010, 0x20004010);
  70. $spfunction7 = array(0x200000, 0x4200002, 0x4000802, 0, 0x800, 0x4000802, 0x200802, 0x4200800, 0x4200802, 0x200000, 0, 0x4000002, 0x2, 0x4000000, 0x4200002, 0x802, 0x4000800, 0x200802, 0x200002, 0x4000800, 0x4000002, 0x4200000, 0x4200800, 0x200002, 0x4200000, 0x800, 0x802, 0x4200802, 0x200800, 0x2, 0x4000000, 0x200800, 0x4000000, 0x200800, 0x200000, 0x4000802, 0x4000802, 0x4200002, 0x4200002, 0x2, 0x200002, 0x4000000, 0x4000800, 0x200000, 0x4200800, 0x802, 0x200802, 0x4200800, 0x802, 0x4000002, 0x4200802, 0x4200000, 0x200800, 0, 0x2, 0x4200802, 0, 0x200802, 0x4200000, 0x800, 0x4000002, 0x4000800, 0x800, 0x200002);
  71. $spfunction8 = array(0x10001040, 0x1000, 0x40000, 0x10041040, 0x10000000, 0x10001040, 0x40, 0x10000000, 0x40040, 0x10040000, 0x10041040, 0x41000, 0x10041000, 0x41040, 0x1000, 0x40, 0x10040000, 0x10000040, 0x10001000, 0x1040, 0x41000, 0x40040, 0x10040040, 0x10041000, 0x1040, 0, 0, 0x10040040, 0x10000040, 0x10001000, 0x41040, 0x40000, 0x41040, 0x40000, 0x10041000, 0x1000, 0x40, 0x10040040, 0x1000, 0x41040, 0x10001000, 0x40, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x40000, 0x10001040, 0, 0x10041040, 0x40040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0, 0x10041040, 0x41000, 0x41000, 0x1040, 0x1040, 0x40040, 0x10000000, 0x10041000);
  72. $masks = array(4294967295, 2147483647, 1073741823, 536870911, 268435455, 134217727, 67108863, 33554431, 16777215, 8388607, 4194303, 2097151, 1048575, 524287, 262143, 131071, 65535, 32767, 16383, 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0);
  73. //create the 16 or 48 subkeys we will need
  74. $keys = self::_createKeys($key);
  75. $m = 0;
  76. $len = strlen($message);
  77. $chunk = 0;
  78. //set up the loops for single and triple des
  79. $iterations = ((count($keys) == 32) ? 3 : 9); //single or triple des
  80. if (3 == $iterations) {$looping = (($encrypt) ? array(0, 32, 2) : array(30, -2, -2));} else { $looping = (($encrypt) ? array(0, 32, 2, 62, 30, -2, 64, 96, 2) : array(94, 62, -2, 32, 64, 2, 30, -2, -2));}
  81. $message .= (chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0)); //pad the message out with null bytes
  82. //store the result here
  83. $result = "";
  84. $tempresult = "";
  85. if (1 == $mode) {
  86. //CBC mode
  87. $cbcleft = (ord($iv{$m++}) << 24) | (ord($iv{$m++}) << 16) | (ord($iv{$m++}) << 8) | ord($iv{$m++});
  88. $cbcright = (ord($iv{$m++}) << 24) | (ord($iv{$m++}) << 16) | (ord($iv{$m++}) << 8) | ord($iv{$m++});
  89. $m = 0;
  90. }
  91. //loop through each 64 bit chunk of the message
  92. while ($m < $len) {
  93. $left = (ord($message{$m++}) << 24) | (ord($message{$m++}) << 16) | (ord($message{$m++}) << 8) | ord($message{$m++});
  94. $right = (ord($message{$m++}) << 24) | (ord($message{$m++}) << 16) | (ord($message{$m++}) << 8) | ord($message{$m++});
  95. //for Cipher Block Chaining mode, xor the message with the previous result
  96. if (1 == $mode) {
  97. if ($encrypt) {$left ^= $cbcleft;
  98. $right ^= $cbcright;} else {
  99. $cbcleft2 = $cbcleft;
  100. $cbcright2 = $cbcright;
  101. $cbcleft = $left;
  102. $cbcright = $right;}}
  103. //first each 64 but chunk of the message must be permuted according to IP
  104. $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f;
  105. $right ^= $temp;
  106. $left ^= ($temp << 4);
  107. $temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff;
  108. $right ^= $temp;
  109. $left ^= ($temp << 16);
  110. $temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333;
  111. $left ^= $temp;
  112. $right ^= ($temp << 2);
  113. $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff;
  114. $left ^= $temp;
  115. $right ^= ($temp << 8);
  116. $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555;
  117. $right ^= $temp;
  118. $left ^= ($temp << 1);
  119. $left = (($left << 1) | ($left >> 31 & $masks[31]));
  120. $right = (($right << 1) | ($right >> 31 & $masks[31]));
  121. //do this either 1 or 3 times for each chunk of the message
  122. for ($j = 0; $j < $iterations; $j += 3) {
  123. $endloop = $looping[$j + 1];
  124. $loopinc = $looping[$j + 2];
  125. //now go through and perform the encryption or decryption
  126. for ($i = $looping[$j]; $i != $endloop; $i += $loopinc) {
  127. //for efficiency
  128. $right1 = $right ^ $keys[$i];
  129. $right2 = (($right >> 4 & $masks[4]) | ($right << 28)) ^ $keys[$i + 1];
  130. //the result is attained by passing these bytes through the S selection functions
  131. $temp = $left;
  132. $left = $right;
  133. $right = $temp ^ ($spfunction2[($right1 >> 24 & $masks[24]) & 0x3f] | $spfunction4[($right1 >> 16 & $masks[16]) & 0x3f]
  134. | $spfunction6[($right1 >> 8 & $masks[8]) & 0x3f] | $spfunction8[$right1 & 0x3f]
  135. | $spfunction1[($right2 >> 24 & $masks[24]) & 0x3f] | $spfunction3[($right2 >> 16 & $masks[16]) & 0x3f]
  136. | $spfunction5[($right2 >> 8 & $masks[8]) & 0x3f] | $spfunction7[$right2 & 0x3f]);
  137. }
  138. $temp = $left;
  139. $left = $right;
  140. $right = $temp; //unreverse left and right
  141. } //for either 1 or 3 iterations
  142. //move then each one bit to the right
  143. $left = (($left >> 1 & $masks[1]) | ($left << 31));
  144. $right = (($right >> 1 & $masks[1]) | ($right << 31));
  145. //now perform IP-1, which is IP in the opposite direction
  146. $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555;
  147. $right ^= $temp;
  148. $left ^= ($temp << 1);
  149. $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff;
  150. $left ^= $temp;
  151. $right ^= ($temp << 8);
  152. $temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333;
  153. $left ^= $temp;
  154. $right ^= ($temp << 2);
  155. $temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff;
  156. $right ^= $temp;
  157. $left ^= ($temp << 16);
  158. $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f;
  159. $right ^= $temp;
  160. $left ^= ($temp << 4);
  161. //for Cipher Block Chaining mode, xor the message with the previous result
  162. if (1 == $mode) {
  163. if ($encrypt) {$cbcleft = $left;
  164. $cbcright = $right;} else {
  165. $left ^= $cbcleft2;
  166. $right ^= $cbcright2;}}
  167. $tempresult .= (chr($left >> 24 & $masks[24]) . chr(($left >> 16 & $masks[16]) & 0xff) . chr(($left >> 8 & $masks[8]) & 0xff) . chr($left & 0xff) . chr($right >> 24 & $masks[24]) . chr(($right >> 16 & $masks[16]) & 0xff) . chr(($right >> 8 & $masks[8]) & 0xff) . chr($right & 0xff));
  168. $chunk += 8;
  169. if (512 == $chunk) {
  170. $result .= $tempresult;
  171. $tempresult = "";
  172. $chunk = 0;}
  173. } //for every 8 characters, or 64 bits in the message
  174. //return the result as an array
  175. return ($result . $tempresult);
  176. } //end of des
  177. /**
  178. * createKeys
  179. * this takes as input a 64 bit key (even though only 56 bits are used)
  180. * as an array of 2 integers, and returns 16 48 bit keys
  181. * @param string $key 加密key
  182. * @return string
  183. */
  184. private static function _createKeys($key)
  185. {
  186. //declaring this locally speeds things up a bit
  187. $pc2bytes0 = array(0, 0x4, 0x20000000, 0x20000004, 0x10000, 0x10004, 0x20010000, 0x20010004, 0x200, 0x204, 0x20000200, 0x20000204, 0x10200, 0x10204, 0x20010200, 0x20010204);
  188. $pc2bytes1 = array(0, 0x1, 0x100000, 0x100001, 0x4000000, 0x4000001, 0x4100000, 0x4100001, 0x100, 0x101, 0x100100, 0x100101, 0x4000100, 0x4000101, 0x4100100, 0x4100101);
  189. $pc2bytes2 = array(0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808, 0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808);
  190. $pc2bytes3 = array(0, 0x200000, 0x8000000, 0x8200000, 0x2000, 0x202000, 0x8002000, 0x8202000, 0x20000, 0x220000, 0x8020000, 0x8220000, 0x22000, 0x222000, 0x8022000, 0x8222000);
  191. $pc2bytes4 = array(0, 0x40000, 0x10, 0x40010, 0, 0x40000, 0x10, 0x40010, 0x1000, 0x41000, 0x1010, 0x41010, 0x1000, 0x41000, 0x1010, 0x41010);
  192. $pc2bytes5 = array(0, 0x400, 0x20, 0x420, 0, 0x400, 0x20, 0x420, 0x2000000, 0x2000400, 0x2000020, 0x2000420, 0x2000000, 0x2000400, 0x2000020, 0x2000420);
  193. $pc2bytes6 = array(0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002, 0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002);
  194. $pc2bytes7 = array(0, 0x10000, 0x800, 0x10800, 0x20000000, 0x20010000, 0x20000800, 0x20010800, 0x20000, 0x30000, 0x20800, 0x30800, 0x20020000, 0x20030000, 0x20020800, 0x20030800);
  195. $pc2bytes8 = array(0, 0x40000, 0, 0x40000, 0x2, 0x40002, 0x2, 0x40002, 0x2000000, 0x2040000, 0x2000000, 0x2040000, 0x2000002, 0x2040002, 0x2000002, 0x2040002);
  196. $pc2bytes9 = array(0, 0x10000000, 0x8, 0x10000008, 0, 0x10000000, 0x8, 0x10000008, 0x400, 0x10000400, 0x408, 0x10000408, 0x400, 0x10000400, 0x408, 0x10000408);
  197. $pc2bytes10 = array(0, 0x20, 0, 0x20, 0x100000, 0x100020, 0x100000, 0x100020, 0x2000, 0x2020, 0x2000, 0x2020, 0x102000, 0x102020, 0x102000, 0x102020);
  198. $pc2bytes11 = array(0, 0x1000000, 0x200, 0x1000200, 0x200000, 0x1200000, 0x200200, 0x1200200, 0x4000000, 0x5000000, 0x4000200, 0x5000200, 0x4200000, 0x5200000, 0x4200200, 0x5200200);
  199. $pc2bytes12 = array(0, 0x1000, 0x8000000, 0x8001000, 0x80000, 0x81000, 0x8080000, 0x8081000, 0x10, 0x1010, 0x8000010, 0x8001010, 0x80010, 0x81010, 0x8080010, 0x8081010);
  200. $pc2bytes13 = array(0, 0x4, 0x100, 0x104, 0, 0x4, 0x100, 0x104, 0x1, 0x5, 0x101, 0x105, 0x1, 0x5, 0x101, 0x105);
  201. $masks = array(4294967295, 2147483647, 1073741823, 536870911, 268435455, 134217727, 67108863, 33554431, 16777215, 8388607, 4194303, 2097151, 1048575, 524287, 262143, 131071, 65535, 32767, 16383, 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0);
  202. //how many iterations (1 for des, 3 for triple des)
  203. $iterations = ((strlen($key) >= 24) ? 3 : 1);
  204. //stores the return keys
  205. $keys = array(); // size = 32 * iterations but you don't specify this in php
  206. //now define the left shifts which need to be done
  207. $shifts = array(0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0);
  208. //other variables
  209. $m = 0;
  210. $n = 0;
  211. for ($j = 0; $j < $iterations; $j++) {
  212. //either 1 or 3 iterations
  213. $left = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++});
  214. $right = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++});
  215. $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f;
  216. $right ^= $temp;
  217. $left ^= ($temp << 4);
  218. $temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff;
  219. $left ^= $temp;
  220. $right ^= ($temp << -16);
  221. $temp = (($left >> 2 & $masks[2]) ^ $right) & 0x33333333;
  222. $right ^= $temp;
  223. $left ^= ($temp << 2);
  224. $temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff;
  225. $left ^= $temp;
  226. $right ^= ($temp << -16);
  227. $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555;
  228. $right ^= $temp;
  229. $left ^= ($temp << 1);
  230. $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff;
  231. $left ^= $temp;
  232. $right ^= ($temp << 8);
  233. $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555;
  234. $right ^= $temp;
  235. $left ^= ($temp << 1);
  236. //the right side needs to be shifted and to get the last four bits of the left side
  237. $temp = ($left << 8) | (($right >> 20 & $masks[20]) & 0x000000f0);
  238. //left needs to be put upside down
  239. $left = ($right << 24) | (($right << 8) & 0xff0000) | (($right >> 8 & $masks[8]) & 0xff00) | (($right >> 24 & $masks[24]) & 0xf0);
  240. $right = $temp;
  241. //now go through and perform these shifts on the left and right keys
  242. for ($i = 0; $i < count($shifts); $i++) {
  243. //shift the keys either one or two bits to the left
  244. if ($shifts[$i] > 0) {
  245. $left = (($left << 2) | ($left >> 26 & $masks[26]));
  246. $right = (($right << 2) | ($right >> 26 & $masks[26]));
  247. } else {
  248. $left = (($left << 1) | ($left >> 27 & $masks[27]));
  249. $right = (($right << 1) | ($right >> 27 & $masks[27]));
  250. }
  251. $left = $left & -0xf;
  252. $right = $right & -0xf;
  253. //now apply PC-2, in such a way that E is easier when encrypting or decrypting
  254. //this conversion will look like PC-2 except only the last 6 bits of each byte are used
  255. //rather than 48 consecutive bits and the order of lines will be according to
  256. //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7
  257. $lefttemp = $pc2bytes0[$left >> 28 & $masks[28]] | $pc2bytes1[($left >> 24 & $masks[24]) & 0xf]
  258. | $pc2bytes2[($left >> 20 & $masks[20]) & 0xf] | $pc2bytes3[($left >> 16 & $masks[16]) & 0xf]
  259. | $pc2bytes4[($left >> 12 & $masks[12]) & 0xf] | $pc2bytes5[($left >> 8 & $masks[8]) & 0xf]
  260. | $pc2bytes6[($left >> 4 & $masks[4]) & 0xf];
  261. $righttemp = $pc2bytes7[$right >> 28 & $masks[28]] | $pc2bytes8[($right >> 24 & $masks[24]) & 0xf]
  262. | $pc2bytes9[($right >> 20 & $masks[20]) & 0xf] | $pc2bytes10[($right >> 16 & $masks[16]) & 0xf]
  263. | $pc2bytes11[($right >> 12 & $masks[12]) & 0xf] | $pc2bytes12[($right >> 8 & $masks[8]) & 0xf]
  264. | $pc2bytes13[($right >> 4 & $masks[4]) & 0xf];
  265. $temp = (($righttemp >> 16 & $masks[16]) ^ $lefttemp) & 0x0000ffff;
  266. $keys[$n++] = $lefttemp ^ $temp;
  267. $keys[$n++] = $righttemp ^ ($temp << 16);
  268. }
  269. } //for each iterations
  270. //return the keys we've created
  271. return $keys;
  272. } //end of des_createKeys
  273. }