cryptal  latest
Cryptography Abstraction Layer
Camellia.php
1 <?php
2 
4 
13 
20 class Camellia implements CryptoInterface
21 {
23  protected $keyLength;
24 
25  protected $cipher;
26  protected $key;
27 
29  protected $k;
30 
32  protected $ke;
33 
35  protected $kw;
36 
38  protected $k2;
39 
41  protected $ke2;
42 
44  protected $kw2;
45 
47  const SIGMA1 = "\xA0\x9E\x66\x7F\x3B\xCC\x90\x8B";
48 
50  const SIGMA2 = "\xB6\x7A\xE8\x58\x4C\xAA\x73\xB2";
51 
53  const SIGMA3 = "\xC6\xEF\x37\x2F\xE9\x4F\x82\xBE";
54 
56  const SIGMA4 = "\x54\xFF\x53\xA5\xF1\xD3\x6F\x1C";
57 
59  const SIGMA5 = "\x10\xE5\x27\xFA\xDE\x68\x2D\x1D";
60 
62  const SIGMA6 = "\xB0\x56\x88\xC2\xB3\xE6\xC1\xFD";
63 
65  protected static $sbox1 = null;
66 
67  public function __construct(
68  CipherEnum $cipher,
69  ModeEnum $mode,
70  PaddingInterface $padding,
71  $key,
72  $tagLength = self::DEFAULT_TAG_LENGTH
73  ) {
74  if (null === self::$sbox1) {
75  // Build and cache sbox1
76  self::$sbox1 =
77  "\x70\x82\x2C\xEC\xB3\x27\xC0\xE5\xE4\x85\x57\x35\xEA\x0C\xAE\x41" .
78  "\x23\xEF\x6B\x93\x45\x19\xA5\x21\xED\x0E\x4F\x4E\x1D\x65\x92\xBD" .
79  "\x86\xB8\xAF\x8F\x7C\xEB\x1F\xCE\x3E\x30\xDC\x5F\x5E\xC5\x0B\x1A" .
80  "\xA6\xE1\x39\xCA\xD5\x47\x5D\x3D\xD9\x01\x5A\xD6\x51\x56\x6C\x4D" .
81  "\x8B\x0D\x9A\x66\xFB\xCC\xB0\x2D\x74\x12\x2B\x20\xF0\xB1\x84\x99" .
82  "\xDF\x4C\xCB\xC2\x34\x7E\x76\x05\x6D\xB7\xA9\x31\xD1\x17\x04\xD7" .
83  "\x14\x58\x3A\x61\xDE\x1B\x11\x1C\x32\x0F\x9C\x16\x53\x18\xF2\x22" .
84  "\xFE\x44\xCF\xB2\xC3\xB5\x7A\x91\x24\x08\xE8\xA8\x60\xFC\x69\x50" .
85  "\xAA\xD0\xA0\x7D\xA1\x89\x62\x97\x54\x5B\x1E\x95\xE0\xFF\x64\xD2" .
86  "\x10\xC4\x00\x48\xA3\xF7\x75\xDB\x8A\x03\xE6\xDA\x09\x3F\xDD\x94" .
87  "\x87\x5C\x83\x02\xCD\x4A\x90\x33\x73\x67\xF6\xF3\x9D\x7F\xBF\xE2" .
88  "\x52\x9B\xD8\x26\xC8\x37\xC6\x3B\x81\x96\x6F\x4B\x13\xBE\x63\x2E" .
89  "\xE9\x79\xA7\x8C\x9F\x6E\xBC\x8E\x29\xF5\xF9\xB6\x2F\xFD\xB4\x59" .
90  "\x78\x98\x06\x6A\xE7\x46\x71\xBA\xD4\x25\xAB\x42\x88\xA2\x8D\xFA" .
91  "\x72\x07\xB9\x55\xF8\xEE\xAC\x0A\x36\x49\x2A\x68\x3C\x38\xF1\xA4" .
92  "\x40\x28\xD3\x7B\xBB\xC9\x43\xC1\x15\xE3\xAD\xF4\x77\xC7\x80\x9E";
93  }
94 
95  $supported = array(
96  CipherEnum::CIPHER_CAMELIA_128(),
97  CipherEnum::CIPHER_CAMELIA_192(),
98  CipherEnum::CIPHER_CAMELIA_256(),
99  );
100 
101  if (!in_array($cipher, $supported)) {
102  throw new \InvalidArgumentException('Unsupported cipher');
103  }
104 
105  if (ModeEnum::MODE_ECB() != $mode) {
106  throw new \InvalidArgumentException('Unsupported mode');
107  }
108 
109  $this->scheduleKeys($key);
110  $this->key = $key;
111  $this->cipher = $cipher;
112  }
113 
126  protected static function rotateLeft($value, $n)
127  {
128  $codes = array_map('ord', str_split($value));
129  $binary = vsprintf(str_repeat("%08b", strlen($value)), $codes);
130  $rot = substr($binary, $n) . substr($binary, 0, $n);
131  $codes = array_map('bindec', str_split($rot, 8));
132  return implode('', array_map('chr', $codes));
133  }
134 
147  protected function scheduleKeys($key)
148  {
149  // Compute KL & KR
150  $KL = substr($key, 0, 16);
151  $this->keyLength = strlen($key) << 3;
152  switch ($this->keyLength) {
153  case 128:
154  $KR = str_repeat("\x00", 16);
155  break;
156  case 192:
157  $KR = substr($key, -8) . (substr($key, -8) ^ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF");
158  break;
159  case 256:
160  $KR = substr($key, -16);
161  break;
162  default:
163  throw new \InvalidArgumentException('Invalid key length');
164  }
165 
166  // Compute KA & KB from KL & KR
167  $D1 = substr($KL ^ $KR, 0, 8);
168  $D2 = substr($KL ^ $KR, 8);
169  $D2 ^= self::f($D1, self::SIGMA1);
170  $D1 ^= self::f($D2, self::SIGMA2);
171  $D1 ^= substr($KL, 0, 8);
172  $D2 ^= substr($KL, 8);
173  $D2 ^= self::f($D1, self::SIGMA3);
174  $D1 ^= self::f($D2, self::SIGMA4);
175  $KA = $D1 . $D2;
176  $D1 = substr($KA ^ $KR, 0, 8);
177  $D2 = substr($KA ^ $KR, 8);
178  $D2 ^= self::f($D1, self::SIGMA5);
179  $D1 ^= self::f($D2, self::SIGMA6);
180  $KB = $D1 . $D2;
181  unset($D1, $D2);
182 
183  // Alias KB & KR when the key is only 128-bit long
184  if (128 === $this->keyLength) {
185  $KB = $KA;
186  $KR = $KL;
187  }
188 
189  // Compute kw1..kw2, k1..k6
190  $kw = $k = $ke = array(null);
191  $kw[] = substr(self::rotateLeft($KL, 0), 0, 8); // kw1
192  $kw[] = substr(self::rotateLeft($KL, 0), 8); // kw2
193  $k[] = substr(self::rotateLeft($KB, 0), 0, 8); // k1
194  $k[] = substr(self::rotateLeft($KB, 0), 8); // k2
195  $k[] = substr(self::rotateLeft($KR, 15), 0, 8); // k3
196  $k[] = substr(self::rotateLeft($KR, 15), 8); // k4
197  $k[] = substr(self::rotateLeft($KA, 15), 0, 8); // k5
198  $k[] = substr(self::rotateLeft($KA, 15), 8); // k6
199 
200  if (128 === $this->keyLength) {
201  $ke[] = substr(self::rotateLeft($KA, 30), 0, 8); // ke1
202  $ke[] = substr(self::rotateLeft($KA, 30), 8); // ke2
203  } else {
204  $ke[] = substr(self::rotateLeft($KR, 30), 0, 8); // ke1
205  $ke[] = substr(self::rotateLeft($KR, 30), 8); // ke2
206  $k[] = substr(self::rotateLeft($KB, 30), 0, 8); // k7
207  $k[] = substr(self::rotateLeft($KB, 30), 8); // k8
208  }
209 
210  // k7..k9 or k9..k11, depending on key size
211  $k[] = substr(self::rotateLeft($KL, 45), 0, 8);
212  $k[] = substr(self::rotateLeft($KL, 45), 8);
213  $k[] = substr(self::rotateLeft($KA, 45), 0, 8);
214 
215  if (128 === $this->keyLength) {
216  $k[] = substr(self::rotateLeft($KL, 60), 8); // k10
217  } else {
218  $k[] = substr(self::rotateLeft($KA, 45), 8); // k12
219  $ke[] = substr(self::rotateLeft($KL, 60), 0, 8); // ke3
220  $ke[] = substr(self::rotateLeft($KL, 60), 8); // ke4
221  $k[] = substr(self::rotateLeft($KR, 60), 0, 8); // k13
222  $k[] = substr(self::rotateLeft($KR, 60), 8); // k14
223  }
224 
225  // k11..k12 or k15..k16, depending on key size
226  $k[] = substr(self::rotateLeft($KB, 60), 0, 8);
227  $k[] = substr(self::rotateLeft($KB, 60), 8);
228 
229  if (128 === $this->keyLength) {
230  $ke[] = substr(self::rotateLeft($KL, 77), 0, 8); // ke3
231  $ke[] = substr(self::rotateLeft($KL, 77), 8); // ke4
232  } else {
233  $k[] = substr(self::rotateLeft($KL, 77), 0, 8); // k17
234  $k[] = substr(self::rotateLeft($KL, 77), 8); // k18
235  $ke[] = substr(self::rotateLeft($KA, 77), 0, 8); // ke5
236  $ke[] = substr(self::rotateLeft($KA, 77), 8); // ke6
237  }
238 
239  // k13..k18 or k19..k24, and kw3..kw4
240  $k[] = substr(self::rotateLeft($KR, 94), 0, 8);
241  $k[] = substr(self::rotateLeft($KR, 94), 8);
242  $k[] = substr(self::rotateLeft($KA, 94), 0, 8);
243  $k[] = substr(self::rotateLeft($KA, 94), 8);
244  $k[] = substr(self::rotateLeft($KL, 111), 0, 8);
245  $k[] = substr(self::rotateLeft($KL, 111), 8);
246  $kw[] = substr(self::rotateLeft($KB, 111), 0, 8);
247  $kw[] = substr(self::rotateLeft($KB, 111), 8);
248 
249  unset($k[0], $ke[0], $kw[0]);
250  $this->k = $k;
251  $this->ke = $ke;
252  $this->kw = $kw;
253 
254  // Build the reverse map for keys
255  $k2 = $ke2 = $kw2 = array();
256  for ($i = 1, $n = count($k); $i <= $n; $i++) {
257  $k2[$i] = $k[$n - $i + 1];
258  }
259  for ($i = 1, $n = count($ke); $i <= $n; $i++) {
260  $ke2[$i] = $ke[$n - $i + 1];
261  }
262  $kw2[1] = $kw[3];
263  $kw2[2] = $kw[4];
264  $kw2[3] = $kw[1];
265  $kw2[4] = $kw[2];
266  $this->k2 = $k2;
267  $this->ke2 = $ke2;
268  $this->kw2 = $kw2;
269  }
270 
286  protected static function sbox($n, $x)
287  {
288  // We try to make this method resilient against timing attacks.
289  if (4 === $n) {
290  $x = self::rotateLeft($x, 1);
291  } else {
292  $x = self::rotateLeft($x, 0);
293  }
294 
295  $rotation = array(1 => 0, 1, 7, 0);
296  return self::rotateLeft(self::$sbox1[ord($x)], $rotation[$n]);
297  }
298 
311  protected function f($F_IN, $KE)
312  {
313  $x = $F_IN ^ $KE;
314  $t = str_split($x);
315  $t1 = self::sbox(1, $t[0]);
316  $t2 = self::sbox(2, $t[1]);
317  $t3 = self::sbox(3, $t[2]);
318  $t4 = self::sbox(4, $t[3]);
319  $t5 = self::sbox(2, $t[4]);
320  $t6 = self::sbox(3, $t[5]);
321  $t7 = self::sbox(4, $t[6]);
322  $t8 = self::sbox(1, $t[7]);
323  $y1 = $t1 ^ $t3 ^ $t4 ^ $t6 ^ $t7 ^ $t8;
324  $y2 = $t1 ^ $t2 ^ $t4 ^ $t5 ^ $t7 ^ $t8;
325  $y3 = $t1 ^ $t2 ^ $t3 ^ $t5 ^ $t6 ^ $t8;
326  $y4 = $t2 ^ $t3 ^ $t4 ^ $t5 ^ $t6 ^ $t7;
327  $y5 = $t1 ^ $t2 ^ $t6 ^ $t7 ^ $t8;
328  $y6 = $t2 ^ $t3 ^ $t5 ^ $t7 ^ $t8;
329  $y7 = $t3 ^ $t4 ^ $t5 ^ $t6 ^ $t8;
330  $y8 = $t1 ^ $t4 ^ $t5 ^ $t6 ^ $t7;
331  $res = $y1 . $y2 . $y3 . $y4 . $y5 . $y6 . $y7 . $y8;
332  return $res;
333  }
334 
350  protected static function fl($FL_IN, $KE)
351  {
352  $x1 = substr($FL_IN, 0, 4);
353  $x2 = substr($FL_IN, 4);
354  $k1 = substr($KE, 0, 4);
355  $k2 = substr($KE, 4);
356  $x2 ^= self::rotateLeft($x1 & $k1, 1);
357  $x1 ^= ($x2 | $k2);
358  $res = $x1 . $x2;
359  return $res;
360  }
361 
377  protected static function flinv($FLINV_IN, $KE)
378  {
379  $y1 = substr($FLINV_IN, 0, 4);
380  $y2 = substr($FLINV_IN, 4);
381  $k1 = substr($KE, 0, 4);
382  $k2 = substr($KE, 4);
383  $y1 ^= ($y2 | $k2);
384  $y2 ^= self::rotateLeft($y1 & $k1, 1);
385  $res = $y1 . $y2;
386  return $res;
387  }
388 
411  protected function xcrypt($m, array $k, array $ke, array $kw)
412  {
413  $D1 = substr($m, 0, 8);
414  $D2 = substr($m, 8);
415 
416  // Pre-whitening
417  $D1 ^= $kw[1];
418  $D2 ^= $kw[2];
419 
420  $nbBlocks = count($k) / 6;
421  for ($i = 0; $i < $nbBlocks; $i++) {
422  if ($i > 0) {
423  $D1 = self::fl($D1, $ke[$i * 2 - 1]);
424  $D2 = self::flinv($D2, $ke[$i * 2]);
425  }
426 
427  $D2 ^= self::f($D1, $k[$i * 6 + 1]);
428  $D1 ^= self::f($D2, $k[$i * 6 + 2]);
429  $D2 ^= self::f($D1, $k[$i * 6 + 3]);
430  $D1 ^= self::f($D2, $k[$i * 6 + 4]);
431  $D2 ^= self::f($D1, $k[$i * 6 + 5]);
432  $D1 ^= self::f($D2, $k[$i * 6 + 6]);
433  }
434 
435  // Post-whitening
436  $D2 ^= $kw[3];
437  $D1 ^= $kw[4];
438 
439  return $D2 . $D1;
440  }
441 
442  public function encrypt($iv, $data, &$tag = null, $aad = '')
443  {
444  $blockSize = $this->getBlockSize();
445  if (strlen($data) % $blockSize) {
446  throw new \InvalidArgumentException('Invalid block');
447  }
448 
449  $res = '';
450  foreach (str_split($data, $blockSize) as $block) {
451  $res .= $this->xcrypt($block, $this->k, $this->ke, $this->kw);
452  }
453  return $res;
454  }
455 
456  public function decrypt($iv, $data, $tag = null, $aad = '')
457  {
458  $blockSize = $this->getBlockSize();
459  if (strlen($data) % $blockSize) {
460  throw new \InvalidArgumentException('Invalid block');
461  }
462 
463  $res = '';
464  foreach (str_split($data, $blockSize) as $block) {
465  $res .= $this->xcrypt($block, $this->k2, $this->ke2, $this->kw2);
466  }
467  return $res;
468  }
469 
470  public function getIVSize()
471  {
472  return 16;
473  }
474 
475  public function getBlockSize()
476  {
477  return 16;
478  }
479 
480  public function getCipher()
481  {
482  return $this->cipher;
483  }
484 
485  public function getKey()
486  {
487  return $this->key;
488  }
489 }
const SIGMA5
Sigma5 constant (from the RFC)
Definition: Camellia.php:59
__construct(CipherEnum $cipher, ModeEnum $mode, PaddingInterface $padding, $key, $tagLength=self::DEFAULT_TAG_LENGTH)
Definition: Camellia.php:67
$kw
Subkeys used for whitening during encryption.
Definition: Camellia.php:35
$ke
Subkeys used by the Feistel structure during encryption.
Definition: Camellia.php:32
encrypt($iv, $data, &$tag=null, $aad= '')
Definition: Camellia.php:442
$k
Subkeys used for encryption.
Definition: Camellia.php:29
$keyLength
Original key length in bits (128, 192 or 256)
Definition: Camellia.php:23
const SIGMA2
Sigma2 constant (from the RFC)
Definition: Camellia.php:50
static $sbox1
Character string containing the whole sbox1 crypto-box.
Definition: Camellia.php:65
$k2
Subkeys used for decryption.
Definition: Camellia.php:38
$kw2
Subkeys used for whitening during decryption.
Definition: Camellia.php:44
const SIGMA3
Sigma3 constant (from the RFC)
Definition: Camellia.php:53
$ke2
Subkeys used by the Feistel structure during decryption.
Definition: Camellia.php:41
const SIGMA1
Sigma1 constant (from the RFC)
Definition: Camellia.php:47
const SIGMA4
Sigma4 constant (from the RFC)
Definition: Camellia.php:56
decrypt($iv, $data, $tag=null, $aad= '')
Definition: Camellia.php:456
xcrypt($m, array $k, array $ke, array $kw)
Definition: Camellia.php:411
const SIGMA6
Sigma6 constant (from the RFC)
Definition: Camellia.php:62