cryptal  latest
Cryptography Abstraction Layer
Cmac.php
1 <?php
2 
4 
13 
18 class Cmac extends AbstractMac
19 {
24  protected static $polynomials = array(
25  48 => "\x00\x2D",
26  64 => "\x00\x1B",
27  96 => "\x06\x41",
28  128 => "\x00\x87",
29  160 => "\x00\x2D",
30  192 => "\x00\x87",
31  224 => "\x03\x09",
32  256 => "\x04\x25",
33  384 => "\x10\x0D",
34  512 => "\x01\x25",
35  );
36 
37  private $data;
38  private $k1;
39  private $k2;
40  private $cipher;
41 
42  public function __construct(MacEnum $macAlgorithm, SubAlgorithmAbstractEnum $innerAlgorithm, $key, $nonce = '')
43  {
44  if (MacEnum::MAC_CMAC() != $macAlgorithm) {
45  throw new \InvalidArgumentException('Unsupported algorithm');
46  }
47 
48  if (!($innerAlgorithm instanceof CipherEnum)) {
49  throw new \InvalidArgumentException('A cipher was expected for the inner algorithm');
50  }
51 
52  $cipher = Registry::buildCipher($innerAlgorithm, ModeEnum::MODE_ECB(), new None, $key, 0, true);
53  $blockSize = $cipher->getBlockSize();
54  if (!isset(self::$polynomials[$blockSize << 3])) {
55  throw new \InvalidArgumentException('Unsupported cipher');
56  }
57 
58  $null = str_repeat("\x00", $blockSize);
59  $polynomial = str_pad(self::$polynomials[$blockSize << 3], $blockSize, "\x00", STR_PAD_LEFT);
60  $k0 = $cipher->encrypt('', $null);
61 
62  if ((ord($k0[0]) & 0x80) === 0) {
63  $k1 = self::mul2mod($k0, $blockSize);
64  } else {
65  $k1 = self::mul2mod($k0, $blockSize) ^ $polynomial;
66  }
67 
68  if ((ord($k1[0]) & 0x80) === 0) {
69  $k2 = self::mul2mod($k1, $blockSize);
70  } else {
71  $k2 = self::mul2mod($k1, $blockSize) ^ $polynomial;
72  }
73 
74  $this->data = '';
75  $this->k1 = $k1;
76  $this->k2 = $k2;
77  $this->cipher = $cipher;
78  }
79 
80  private static function mul2mod($n, $l)
81  {
82  $c = 0;
83  for ($i = $l - 1; $i >= 0; $i--) {
84  $t = (ord($n[$i]) << 1) + $c;
85  $c = $t >> 8;
86  // chr() takes care of overflows for us
87  $n[$i] = chr($t);
88  }
89  return $n;
90  }
91 
92  protected function internalUpdate($data)
93  {
94  $this->data .= $data;
95  }
96 
97  protected function internalFinalize()
98  {
99  $blockSize = $this->cipher->getBlockSize();
100  $m = str_split($this->data, $blockSize);
101  $last = count($m) - 1;
102  $mk1 = $m[$last] ^ $this->k1;
103  $mk2 = $this->k2 ^ str_pad($m[$last] . "\x80", $blockSize, "\x00", STR_PAD_RIGHT);
104 
105  if (strlen($m[$last]) === $blockSize) {
106  $m[$last] = $mk1;
107  } else {
108  $m[$last] = $mk2;
109  }
110 
111  $c = str_repeat("\x00", $blockSize);
112  for ($i = 0, $max = count($m); $i < $max; $i++) {
113  $c = $this->cipher->encrypt('', $c ^ $m[$i]);
114  }
115  return $c;
116  }
117 }
__construct(MacEnum $macAlgorithm, SubAlgorithmAbstractEnum $innerAlgorithm, $key, $nonce= '')
Definition: Cmac.php:42