3 * An implementation of the DES cipher, using the phpseclib implementation
5 * This was forked from phpseclib and modified to use CryptLib conventions
9 * @category PHPCryptLib
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@@
19 namespace CryptLib\Cipher\Block\Cipher
;
22 * An implementation of the DES cipher, using the phpseclib implementation
24 * @category PHPCryptLib
27 * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
29 class DES
extends \CryptLib\Cipher\Block\AbstractCipher
{
32 * @var int The block size for the cipher
34 protected $blockSize = 8;
37 * @var int The key size for the cipher
39 protected $keySize = 8;
42 * @var array The prepared key schedule
44 protected $preparedKeys = array();
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
52 * @var array The S-boxes
54 protected static $sbox = 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
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
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
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
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
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
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
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
106 * @var array The key shift sequence for shifts per round of DES block
108 protected static $keyShifts = array(
109 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
113 * Get a list of supported ciphers for this class implementation
115 * @return array A list of supported ciphers
117 public static function getSupportedCiphers() {
122 * Decrypt a block of data using the supplied string key
124 * Note that the supplied data should be the same size as the block size of
125 * the cipher being used.
127 * @param string $data The data to decrypt
129 * @return string The result decrypted data
131 protected function decryptBlockData($data) {
132 $keys = array_reverse($this->preparedKeys
);
133 return $this->processBlock($data, $keys);
137 * Encrypt a block of data using the supplied string key
139 * Note that the supplied data should be the same size as the block size of
140 * the cipher being used.
142 * @param string $data The data to encrypt
144 * @return string The result encrypted data
146 protected function encryptBlockData($data) {
147 return $this->processBlock($data, $this->preparedKeys
);
151 * Initialize the cipher by preparing the key
153 * @return boolean The status of the initialization
155 protected function initialize() {
156 $this->preparedKeys
= $this->prepareKey($this->key
);
161 * Compute the keys necessary to execute the block cipher
163 * @param string $key The key to prepare
165 * @return array The prepared keys
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));
171 $temp = unpack('Na/Nb', $key);
172 $key = array($temp['a'], $temp['b']);
177 $key[0] &= 0x7FFFFFFF;
178 $key[1] &= 0x7FFFFFFF;
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)
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;
211 $key[1] <<= static::$keyShifts[$i];
212 $temp = ($key[1] & 0xF0000000) >> 28;
213 $key[1] = ($key[1] |
$temp) & 0x0FFFFFFF;
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)
249 * Process a block of data and encrypt (or decrypt depending upon key sequence)
251 * @param string $block The block of data to process
252 * @param array $keys The array of prepared keys to use
254 * @return string The processed block data
256 protected function processBlock($block, array $keys) {
257 $temp = unpack('Na/Nb', $block);
258 $block = array($temp['a'], $temp['b']);
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
269 ($block[0] >> 31) & 1,
270 ($block[1] >> 31) & 1
272 $block[0] &= 0x7FFFFFFF;
273 $block[1] &= 0x7FFFFFFF;
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.
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)
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]);
334 $msb = ($temp >> 31) & 1;
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
351 $block[1] = $block[0] ^
$nwB;
356 ($block[0] >> 31) & 1,
357 ($block[1] >> 31) & 1
359 $block[0] &= 0x7FFFFFFF;
360 $block[1] &= 0x7FFFFFFF;
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)
393 return pack('NN', $block[0], $block[1]);