add methods to decrypt return data from router
[GitHub/Stricted/speedport-hybrid-php-api.git] / CryptLib / MAC / Implementation / CMAC.php
1 <?php
2 /**
3 * A Cipher based MAC generator (Based upon the CMAC specification)
4 *
5 * PHP version 5.3
6 *
7 * @see http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf
8 * @category PHPCryptLib
9 * @package MAC
10 * @subpackage Implementation
11 * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
12 * @copyright 2011 The Authors
13 * @license http://www.opensource.org/licenses/mit-license.html MIT License
14 * @version Build @@version@@
15 */
16 namespace CryptLib\MAC\Implementation;
17
18 use \CryptLib\Cipher\Factory;
19
20 /**
21 * A Cipher based MAC generator (Based upon the CMAC specification)
22 *
23 * @see http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf
24 * @category PHPCryptLib
25 * @package MAC
26 * @subpackage Implementation
27 */
28 class CMAC extends \CryptLib\MAC\AbstractMAC {
29
30 protected $cipher = null;
31
32 /**
33 * @var array The stored options for this instance
34 */
35 protected $options = array(
36 'cipher' => 'aes-128',
37 'cipherFactory' => null,
38 );
39
40 /**
41 * Build the instance of the MAC generator
42 *
43 * @param array $options The options for the instance
44 *
45 * @return void
46 */
47 public function __construct(array $options = array()) {
48 parent::__construct($options);
49 if (is_null($this->options['cipherFactory'])) {
50 $this->options['cipherFactory'] = new Factory;
51 }
52 $this->cipher = $this->options['cipherFactory']->getBlockCipher(
53 $this->options['cipher']
54 );
55 }
56
57 /**
58 * Generate the MAC using the supplied data
59 *
60 * @param string $data The data to use to generate the MAC with
61 * @param string $key The key to generate the MAC
62 * @param int $size The size of the output to return
63 *
64 * @return string The generated MAC of the appropriate size
65 */
66 public function generate($data, $key, $size = 0) {
67 $blockSize = $this->cipher->getBlockSize();
68 if ($size == 0) {
69 $size = $blockSize;
70 }
71 if ($size > $blockSize) {
72 throw new \OutOfRangeException(
73 sprintf(
74 'The size is too big for the cipher primitive [%d:%d]',
75 $size,
76 $blockSize
77 )
78 );
79 }
80 $this->cipher->setKey($key);
81 $keys = $this->generateKeys();
82 $mBlocks = $this->splitDataIntoMBlocks($data, $keys);
83 $cBlock = str_repeat(chr(0), $blockSize);
84 foreach ($mBlocks as $key => $block) {
85 $cBlock = $this->cipher->encryptBlock($cBlock ^ $block);
86 }
87 return substr($cBlock, 0, $size);
88 }
89
90 /**
91 * Generate a pair of keys by encrypting a block of all 0's, and then
92 * maniuplating the result
93 *
94 * @return array The generated keys
95 */
96 protected function generateKeys() {
97 $keys = array();
98 $blockSize = $this->cipher->getBlockSize();
99 $rVal = $this->getRValue($blockSize);
100 $text = str_repeat(chr(0), $blockSize);
101 $lVal = $this->cipher->encryptBlock($text);
102 $keys[0] = $this->leftShift($lVal, 1);
103 if (ord(substr($lVal, 0, 1)) > 127) {
104 $keys[0] = $keys[0] ^ $rVal;
105 }
106 $keys[1] = $this->leftShift($keys[0], 1);
107 if (ord(substr($keys[0], 0, 1)) > 127) {
108 $keys[1] = $keys[1] ^ $rVal;
109 }
110 return $keys;
111 }
112
113 /**
114 * Get an RValue based upon the block size
115 *
116 * @param int $size The size of the block in bytes
117 *
118 * @see http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf
119 * @return string A RValue of the appropriate block size
120 */
121 protected function getRValue($size) {
122 switch ($size * 8) {
123 case 64:
124 return str_repeat(chr(0), 7) . chr(0x1B);
125 case 128:
126 return str_repeat(chr(0), 15) . chr(0x87);
127 default:
128 }
129 throw new \RuntimeException('Unsupported Block Size For The Cipher');
130 }
131
132 protected function leftShift($data, $bits) {
133 $mask = (0xff << (8 - $bits)) & 0xff;
134 $state = 0;
135 $result = '';
136 $length = strlen($data);
137 for ($i = $length - 1; $i >= 0; $i--) {
138 $tmp = ord($data[$i]);
139 $result .= chr(($tmp << $bits) | $state);
140 $state = ($tmp & $mask) >> (8 - $bits);
141 }
142 return strrev($result);
143 }
144
145 /**
146 * Split the data into appropriate block chunks, encoding with the kyes
147 *
148 * @param string $data The data to split
149 * @param array $keys The keys to use for encoding
150 *
151 * @return array The array of chunked and encoded data
152 */
153 protected function splitDataIntoMBlocks($data, array $keys) {
154 $blockSize = $this->cipher->getBlockSize();
155 $data = str_split($data, $blockSize);
156 $last = end($data);
157 if (strlen($last) != $blockSize) {
158 //Pad the last element
159 $last .= chr(0x80) . str_repeat(chr(0), $blockSize - 1 - strlen($last));
160 $last = $last ^ $keys[1];
161 } else {
162 $last = $last ^ $keys[0];
163 }
164 $data[count($data) - 1] = $last;
165 return $data;
166 }
167
168 }