add methods to decrypt return data from router
[GitHub/Stricted/speedport-hybrid-php-api.git] / CryptLib / Cipher / Block / Cipher / DES.php
1 <?php
2 /**
3 * An implementation of the DES cipher, using the phpseclib implementation
4 *
5 * This was forked from phpseclib and modified to use CryptLib conventions
6 *
7 * PHP version 5.3
8 *
9 * @category PHPCryptLib
10 * @package Cipher
11 * @subpackage Block
12 * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
13 * @author Jim Wigginton <terrafrost@php.net>
14 * @copyright 2011 The Authors
15 * @license http://www.opensource.org/licenses/mit-license.html MIT License
16 * @version Build @@version@@
17 */
18
19 namespace CryptLib\Cipher\Block\Cipher;
20
21 /**
22 * An implementation of the DES cipher, using the phpseclib implementation
23 *
24 * @category PHPCryptLib
25 * @package Cipher
26 * @subpackage Block
27 * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
28 */
29 class DES extends \CryptLib\Cipher\Block\AbstractCipher {
30
31 /**
32 * @var int The block size for the cipher
33 */
34 protected $blockSize = 8;
35
36 /**
37 * @var int The key size for the cipher
38 */
39 protected $keySize = 8;
40
41 /**
42 * @var array The prepared key schedule
43 */
44 protected $preparedKeys = array();
45
46 /**
47 * In the official DES docs, they're described as being matrices that one
48 * accesses by using the first and last bits to determine the row and the
49 * middle four bits to determine the column. in this implementation,
50 * they've been converted to vectors
51 *
52 * @var array The S-boxes
53 */
54 protected static $sbox = array(
55 array(
56 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,
57 3, 10 ,10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,
58 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,
59 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13
60 ),
61 array(
62 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,
63 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,
64 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,
65 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9
66 ),
67 array(
68 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,
69 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,
70 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,
71 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12
72 ),
73 array(
74 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,
75 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,
76 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,
77 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14
78 ),
79 array(
80 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,
81 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,
82 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,
83 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3
84 ),
85 array(
86 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,
87 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,
88 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,
89 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13
90 ),
91 array(
92 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,
93 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,
94 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
95 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12
96 ),
97 array(
98 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,
99 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,
100 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,
101 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11
102 )
103 );
104
105 /**
106 * @var array The key shift sequence for shifts per round of DES block
107 */
108 protected static $keyShifts = array(
109 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
110 );
111
112 /**
113 * Get a list of supported ciphers for this class implementation
114 *
115 * @return array A list of supported ciphers
116 */
117 public static function getSupportedCiphers() {
118 return array('des');
119 }
120
121 /**
122 * Decrypt a block of data using the supplied string key
123 *
124 * Note that the supplied data should be the same size as the block size of
125 * the cipher being used.
126 *
127 * @param string $data The data to decrypt
128 *
129 * @return string The result decrypted data
130 */
131 protected function decryptBlockData($data) {
132 $keys = array_reverse($this->preparedKeys);
133 return $this->processBlock($data, $keys);
134 }
135
136 /**
137 * Encrypt a block of data using the supplied string key
138 *
139 * Note that the supplied data should be the same size as the block size of
140 * the cipher being used.
141 *
142 * @param string $data The data to encrypt
143 *
144 * @return string The result encrypted data
145 */
146 protected function encryptBlockData($data) {
147 return $this->processBlock($data, $this->preparedKeys);
148 }
149
150 /**
151 * Initialize the cipher by preparing the key
152 *
153 * @return boolean The status of the initialization
154 */
155 protected function initialize() {
156 $this->preparedKeys = $this->prepareKey($this->key);
157 return true;
158 }
159
160 /**
161 * Compute the keys necessary to execute the block cipher
162 *
163 * @param string $key The key to prepare
164 *
165 * @return array The prepared keys
166 */
167 private function prepareKey($key) {
168 // pad the key and remove extra characters as appropriate.
169 $key = str_pad(substr($key, 0, 8), 8, chr(0));
170
171 $temp = unpack('Na/Nb', $key);
172 $key = array($temp['a'], $temp['b']);
173 $msb = array(
174 ($key[0] >> 31) & 1,
175 ($key[1] >> 31) & 1
176 );
177 $key[0] &= 0x7FFFFFFF;
178 $key[1] &= 0x7FFFFFFF;
179
180 $key = array(
181 (($key[1] & 0x00000002) << 26) | (($key[1] & 0x00000204) << 17) |
182 (($key[1] & 0x00020408) << 8) | (($key[1] & 0x02040800) >> 1) |
183 (($key[0] & 0x00000002) << 22) | (($key[0] & 0x00000204) << 13) |
184 (($key[0] & 0x00020408) << 4) | (($key[0] & 0x02040800) >> 5) |
185 (($key[1] & 0x04080000) >> 10) | (($key[0] & 0x04080000) >> 14) |
186 (($key[1] & 0x08000000) >> 19) | (($key[0] & 0x08000000) >> 23) |
187 (($key[0] & 0x00000010) >> 1) | (($key[0] & 0x00001000) >> 10) |
188 (($key[0] & 0x00100000) >> 19) | (($key[0] & 0x10000000) >> 28),
189 (($key[1] & 0x00000080) << 20) | (($key[1] & 0x00008000) << 11) |
190 (($key[1] & 0x00800000) << 2) | (($key[0] & 0x00000080) << 16) |
191 (($key[0] & 0x00008000) << 7) | (($key[0] & 0x00800000) >> 2) |
192 (($key[1] & 0x00000040) << 13) | (($key[1] & 0x00004000) << 4) |
193 (($key[1] & 0x00400000) >> 5) | (($key[1] & 0x40000000) >> 14) |
194 (($key[0] & 0x00000040) << 9) | ( $key[0] & 0x00004000 ) |
195 (($key[0] & 0x00400000) >> 9) | (($key[0] & 0x40000000) >> 18) |
196 (($key[1] & 0x00000020) << 6) | (($key[1] & 0x00002000) >> 3) |
197 (($key[1] & 0x00200000) >> 12) | (($key[1] & 0x20000000) >> 21) |
198 (($key[0] & 0x00000020) << 2) | (($key[0] & 0x00002000) >> 7) |
199 (($key[0] & 0x00200000) >> 16) | (($key[0] & 0x20000000) >> 25) |
200 (($key[1] & 0x00000010) >> 1) | (($key[1] & 0x00001000) >> 10) |
201 (($key[1] & 0x00100000) >> 19) | (($key[1] & 0x10000000) >> 28) |
202 ($msb[1] << 24) | ($msb[0] << 20)
203 );
204
205 $keys = array();
206 for ($i = 0; $i < 16; $i++) {
207 $key[0] <<= static::$keyShifts[$i];
208 $temp = ($key[0] & 0xF0000000) >> 28;
209 $key[0] = ($key[0] | $temp) & 0x0FFFFFFF;
210
211 $key[1] <<= static::$keyShifts[$i];
212 $temp = ($key[1] & 0xF0000000) >> 28;
213 $key[1] = ($key[1] | $temp) & 0x0FFFFFFF;
214
215 $temp = array(
216 (($key[1] & 0x00004000) >> 9) | (($key[1] & 0x00000800) >> 7) |
217 (($key[1] & 0x00020000) >> 14) | (($key[1] & 0x00000010) >> 2) |
218 (($key[1] & 0x08000000) >> 26) | (($key[1] & 0x00800000) >> 23),
219 (($key[1] & 0x02400000) >> 20) | (($key[1] & 0x00000001) << 4) |
220 (($key[1] & 0x00002000) >> 10) | (($key[1] & 0x00040000) >> 18) |
221 (($key[1] & 0x00000080) >> 6),
222 ( $key[1] & 0x00000020 ) | (($key[1] & 0x00000200) >> 5) |
223 (($key[1] & 0x00010000) >> 13) | (($key[1] & 0x01000000) >> 22) |
224 (($key[1] & 0x00000004) >> 1) | (($key[1] & 0x00100000) >> 20),
225 (($key[1] & 0x00001000) >> 7) | (($key[1] & 0x00200000) >> 17) |
226 (($key[1] & 0x00000002) << 2) | (($key[1] & 0x00000100) >> 6) |
227 (($key[1] & 0x00008000) >> 14) | (($key[1] & 0x04000000) >> 26),
228 (($key[0] & 0x00008000) >> 10) | ( $key[0] & 0x00000010 ) |
229 (($key[0] & 0x02000000) >> 22) | (($key[0] & 0x00080000) >> 17) |
230 (($key[0] & 0x00000200) >> 8) | (($key[0] & 0x00000002) >> 1),
231 (($key[0] & 0x04000000) >> 21) | (($key[0] & 0x00010000) >> 12) |
232 (($key[0] & 0x00000020) >> 2) | (($key[0] & 0x00000800) >> 9) |
233 (($key[0] & 0x00800000) >> 22) | (($key[0] & 0x00000100) >> 8),
234 (($key[0] & 0x00001000) >> 7) | (($key[0] & 0x00000088) >> 3) |
235 (($key[0] & 0x00020000) >> 14) | (($key[0] & 0x00000001) << 2) |
236 (($key[0] & 0x00400000) >> 21),
237 (($key[0] & 0x00000400) >> 5) | (($key[0] & 0x00004000) >> 10) |
238 (($key[0] & 0x00000040) >> 3) | (($key[0] & 0x00100000) >> 18) |
239 (($key[0] & 0x08000000) >> 26) | (($key[0] & 0x01000000) >> 24)
240 );
241
242 $keys[] = $temp;
243 }
244
245 return $keys;
246 }
247
248 /**
249 * Process a block of data and encrypt (or decrypt depending upon key sequence)
250 *
251 * @param string $block The block of data to process
252 * @param array $keys The array of prepared keys to use
253 *
254 * @return string The processed block data
255 */
256 protected function processBlock($block, array $keys) {
257 $temp = unpack('Na/Nb', $block);
258 $block = array($temp['a'], $temp['b']);
259
260 /**
261 * Because php does arithmetic right shifts, if the most significant bits
262 * are set, right shifting those into the correct position will add 1's -
263 * not 0's. this will intefere with the | operation unless a second & is
264 * done. so we isolate these bits and left shift them into place. we
265 * then & each block with 0x7FFFFFFF to prevennt 1's from being added for
266 * any other shifts.
267 */
268 $msb = array(
269 ($block[0] >> 31) & 1,
270 ($block[1] >> 31) & 1
271 );
272 $block[0] &= 0x7FFFFFFF;
273 $block[1] &= 0x7FFFFFFF;
274
275 /**
276 * We isolate the appropriate bit in the appropriate integer and shift as
277 * appropriate. In some cases, there are going to be multiple bits in the
278 * same integer that need to be shifted in the same way. we combine those
279 * into one shift operation.
280 */
281 $block = array(
282 (($block[1] & 0x00000040) << 25) | (($block[1] & 0x00004000) << 16) |
283 (($block[1] & 0x00400001) << 7) | (($block[1] & 0x40000100) >> 2) |
284 (($block[0] & 0x00000040) << 21) | (($block[0] & 0x00004000) << 12) |
285 (($block[0] & 0x00400001) << 3) | (($block[0] & 0x40000100) >> 6) |
286 (($block[1] & 0x00000010) << 19) | (($block[1] & 0x00001000) << 10) |
287 (($block[1] & 0x00100000) << 1) | (($block[1] & 0x10000000) >> 8) |
288 (($block[0] & 0x00000010) << 15) | (($block[0] & 0x00001000) << 6) |
289 (($block[0] & 0x00100000) >> 3) | (($block[0] & 0x10000000) >> 12) |
290 (($block[1] & 0x00000004) << 13) | (($block[1] & 0x00000400) << 4) |
291 (($block[1] & 0x00040000) >> 5) | (($block[1] & 0x04000000) >> 14) |
292 (($block[0] & 0x00000004) << 9) | ( $block[0] & 0x00000400 ) |
293 (($block[0] & 0x00040000) >> 9) | (($block[0] & 0x04000000) >> 18) |
294 (($block[1] & 0x00010000) >> 11) | (($block[1] & 0x01000000) >> 20) |
295 (($block[0] & 0x00010000) >> 15) | (($block[0] & 0x01000000) >> 24),
296 (($block[1] & 0x00000080) << 24) | (($block[1] & 0x00008000) << 15) |
297 (($block[1] & 0x00800002) << 6) | (($block[0] & 0x00000080) << 20) |
298 (($block[0] & 0x00008000) << 11) | (($block[0] & 0x00800002) << 2) |
299 (($block[1] & 0x00000020) << 18) | (($block[1] & 0x00002000) << 9) |
300 ( $block[1] & 0x00200000 ) | (($block[1] & 0x20000000) >> 9) |
301 (($block[0] & 0x00000020) << 14) | (($block[0] & 0x00002000) << 5) |
302 (($block[0] & 0x00200000) >> 4) | (($block[0] & 0x20000000) >> 13) |
303 (($block[1] & 0x00000008) << 12) | (($block[1] & 0x00000800) << 3) |
304 (($block[1] & 0x00080000) >> 6) | (($block[1] & 0x08000000) >> 15) |
305 (($block[0] & 0x00000008) << 8) | (($block[0] & 0x00000800) >> 1) |
306 (($block[0] & 0x00080000) >> 10) | (($block[0] & 0x08000000) >> 19) |
307 (($block[1] & 0x00000200) >> 3) | (($block[0] & 0x00000200) >> 7) |
308 (($block[1] & 0x00020000) >> 12) | (($block[1] & 0x02000000) >> 21) |
309 (($block[0] & 0x00020000) >> 16) | (($block[0] & 0x02000000) >> 25) |
310 ($msb[1] << 28) | ($msb[0] << 24)
311 );
312
313 for ($i = 0; $i < 16; $i++) {
314 // start of "the Feistel (F) function"
315 $key = ((($block[1] >> 27) & 0x1F)
316 | (($block[1] & 1) << 5)) ^ $keys[$i][0];
317 $temp = ((static::$sbox[0][$key]) << 28);
318 $key = (($block[1] & 0x1F800000) >> 23) ^ $keys[$i][1];
319 $temp |= ((static::$sbox[1][$key]) << 24);
320 $key = (($block[1] & 0x01F80000) >> 19) ^ $keys[$i][2];
321 $temp |= ((static::$sbox[2][$key]) << 20);
322 $key = (($block[1] & 0x001F8000) >> 15) ^ $keys[$i][3];
323 $temp |= ((static::$sbox[3][$key]) << 16);
324 $key = (($block[1] & 0x0001F800) >> 11) ^ $keys[$i][4];
325 $temp |= ((static::$sbox[4][$key]) << 12);
326 $key = (($block[1] & 0x00001F80) >> 7) ^ $keys[$i][5];
327 $temp |= ((static::$sbox[5][$key]) << 8);
328 $key = (($block[1] & 0x000001F8) >> 3) ^ $keys[$i][6];
329 $temp |= ((static::$sbox[6][$key]) << 4);
330 $key = ((($block[1] & 0x1F) << 1)
331 | (($block[1] >> 31) & 1)) ^ $keys[$i][7];
332 $temp |= ( static::$sbox[7][$key]);
333
334 $msb = ($temp >> 31) & 1;
335 $temp &= 0x7FFFFFFF;
336 $nwB = (($temp & 0x00010000) << 15) | (($temp & 0x02020120) << 5);
337 $nwB |= (($temp & 0x00001800) << 17) | (($temp & 0x01000000) >> 10);
338 $nwB |= (($temp & 0x00000008) << 24) | (($temp & 0x00100000) << 6);
339 $nwB |= (($temp & 0x00000010) << 21) | (($temp & 0x00008000) << 9);
340 $nwB |= (($temp & 0x00000200) << 12) | (($temp & 0x10000000) >> 27);
341 $nwB |= (($temp & 0x00000040) << 14) | (($temp & 0x08000000) >> 8);
342 $nwB |= (($temp & 0x00004000) << 4) | (($temp & 0x00000002) << 16);
343 $nwB |= (($temp & 0x00442000) >> 6) | (($temp & 0x40800000) >> 15);
344 $nwB |= (($temp & 0x00000001) << 11) | (($temp & 0x20000000) >> 20);
345 $nwB |= (($temp & 0x00080000) >> 13) | (($temp & 0x00000004) << 3);
346 $nwB |= (($temp & 0x04000000) >> 22) | (($temp & 0x00000480) >> 7);
347 $nwB |= (($temp & 0x00200000) >> 19) | ($msb << 23);
348 // end of "the Feistel (F) function" - $newBlock is F's output
349
350 $temp = $block[1];
351 $block[1] = $block[0] ^ $nwB;
352 $block[0] = $temp;
353 }
354
355 $msb = array(
356 ($block[0] >> 31) & 1,
357 ($block[1] >> 31) & 1
358 );
359 $block[0] &= 0x7FFFFFFF;
360 $block[1] &= 0x7FFFFFFF;
361
362 $block = array(
363 (($block[0] & 0x01000004) << 7) | (($block[1] & 0x01000004) << 6) |
364 (($block[0] & 0x00010000) << 13) | (($block[1] & 0x00010000) << 12) |
365 (($block[0] & 0x00000100) << 19) | (($block[1] & 0x00000100) << 18) |
366 (($block[0] & 0x00000001) << 25) | (($block[1] & 0x00000001) << 24) |
367 (($block[0] & 0x02000008) >> 2) | (($block[1] & 0x02000008) >> 3) |
368 (($block[0] & 0x00020000) << 4) | (($block[1] & 0x00020000) << 3) |
369 (($block[0] & 0x00000200) << 10) | (($block[1] & 0x00000200) << 9) |
370 (($block[0] & 0x00000002) << 16) | (($block[1] & 0x00000002) << 15) |
371 (($block[0] & 0x04000000) >> 11) | (($block[1] & 0x04000000) >> 12) |
372 (($block[0] & 0x00040000) >> 5) | (($block[1] & 0x00040000) >> 6) |
373 (($block[0] & 0x00000400) << 1) | ( $block[1] & 0x00000400 ) |
374 (($block[0] & 0x08000000) >> 20) | (($block[1] & 0x08000000) >> 21) |
375 (($block[0] & 0x00080000) >> 14) | (($block[1] & 0x00080000) >> 15) |
376 (($block[0] & 0x00000800) >> 8) | (($block[1] & 0x00000800) >> 9),
377 (($block[0] & 0x10000040) << 3) | (($block[1] & 0x10000040) << 2) |
378 (($block[0] & 0x00100000) << 9) | (($block[1] & 0x00100000) << 8) |
379 (($block[0] & 0x00001000) << 15) | (($block[1] & 0x00001000) << 14) |
380 (($block[0] & 0x00000010) << 21) | (($block[1] & 0x00000010) << 20) |
381 (($block[0] & 0x20000080) >> 6) | (($block[1] & 0x20000080) >> 7) |
382 ( $block[0] & 0x00200000 ) | (($block[1] & 0x00200000) >> 1) |
383 (($block[0] & 0x00002000) << 6) | (($block[1] & 0x00002000) << 5) |
384 (($block[0] & 0x00000020) << 12) | (($block[1] & 0x00000020) << 11) |
385 (($block[0] & 0x40000000) >> 15) | (($block[1] & 0x40000000) >> 16) |
386 (($block[0] & 0x00400000) >> 9) | (($block[1] & 0x00400000) >> 10) |
387 (($block[0] & 0x00004000) >> 3) | (($block[1] & 0x00004000) >> 4) |
388 (($block[0] & 0x00800000) >> 18) | (($block[1] & 0x00800000) >> 19) |
389 (($block[0] & 0x00008000) >> 12) | (($block[1] & 0x00008000) >> 13) |
390 ($msb[0] << 7) | ($msb[1] << 6)
391 );
392
393 return pack('NN', $block[0], $block[1]);
394 }
395
396 }