Commit | Line | Data |
---|---|---|
14d4f286 S |
1 | <?php |
2 | /** | |
3 | * An abstract mixer to implement a common mixing strategy | |
4 | * | |
5 | * PHP version 5.3 | |
6 | * | |
7 | * @category PHPCryptLib | |
8 | * @package Random | |
9 | * @author Anthony Ferrara <ircmaxell@ircmaxell.com> | |
10 | * @copyright 2011 The Authors | |
11 | * @license http://www.opensource.org/licenses/mit-license.html MIT License | |
12 | * @version Build @@version@@ | |
13 | */ | |
14 | ||
15 | namespace CryptLib\Random; | |
16 | ||
17 | /** | |
18 | * An abstract mixer to implement a common mixing strategy | |
19 | * | |
20 | * @see http://tools.ietf.org/html/rfc4086#section-5.2 | |
21 | * @category PHPCryptLib | |
22 | * @package Random | |
23 | * @author Anthony Ferrara <ircmaxell@ircmaxell.com> | |
24 | */ | |
25 | abstract class AbstractMixer implements \CryptLib\Random\Mixer { | |
26 | ||
27 | /** | |
28 | * Get the block size (the size of the individual blocks used for the mixing) | |
29 | * | |
30 | * @return int The block size | |
31 | */ | |
32 | abstract protected function getPartSize(); | |
33 | ||
34 | /** | |
35 | * Mix 2 parts together using one method | |
36 | * | |
37 | * @param string $part1 The first part to mix | |
38 | * @param string $part2 The second part to mix | |
39 | * | |
40 | * @return string The mixed data | |
41 | */ | |
42 | abstract protected function mixParts1($part1, $part2); | |
43 | ||
44 | /** | |
45 | * Mix 2 parts together using another different method | |
46 | * | |
47 | * @param string $part1 The first part to mix | |
48 | * @param string $part2 The second part to mix | |
49 | * | |
50 | * @return string The mixed data | |
51 | */ | |
52 | abstract protected function mixParts2($part1, $part2); | |
53 | ||
54 | /** | |
55 | * Mix the provided array of strings into a single output of the same size | |
56 | * | |
57 | * All elements of the array should be the same size. | |
58 | * | |
59 | * @param array $parts The parts to be mixed | |
60 | * | |
61 | * @return string The mixed result | |
62 | */ | |
63 | public function mix(array $parts) { | |
64 | if (empty($parts)) { | |
65 | return ''; | |
66 | } | |
67 | $len = strlen($parts[0]); | |
68 | $parts = $this->normalizeParts($parts); | |
69 | $stringSize = count($parts[0]); | |
70 | $partsSize = count($parts); | |
71 | $result = ''; | |
72 | $offset = 0; | |
73 | for ($i = 0; $i < $stringSize; $i++) { | |
74 | $stub = $parts[$offset][$i]; | |
75 | for ($j = 1; $j < $partsSize; $j++) { | |
76 | $newKey = $parts[($j + $offset) % $partsSize][$i]; | |
77 | //Alternately mix the output for each source | |
78 | if ($j % 2 == 1) { | |
79 | $stub ^= $this->mixParts1($stub, $newKey); | |
80 | } else { | |
81 | $stub ^= $this->mixParts2($stub, $newKey); | |
82 | } | |
83 | } | |
84 | $result .= $stub; | |
85 | $offset = ($offset + 1) % $partsSize; | |
86 | } | |
87 | return substr($result, 0, $len); | |
88 | } | |
89 | ||
90 | /** | |
91 | * Normalize the part array and split it block part size. | |
92 | * | |
93 | * This will make all parts the same length and a multiple | |
94 | * of the part size | |
95 | * | |
96 | * @param array $parts The parts to normalize | |
97 | * | |
98 | * @return array The normalized and split parts | |
99 | */ | |
100 | protected function normalizeParts(array $parts) { | |
101 | $blockSize = $this->getPartSize(); | |
102 | $callback = function($value) { | |
103 | return strlen($value); | |
104 | }; | |
105 | $maxSize = max(array_map($callback, $parts)); | |
106 | if ($maxSize % $blockSize != 0) { | |
107 | $maxSize += $blockSize - ($maxSize % $blockSize); | |
108 | } | |
109 | foreach ($parts as &$part) { | |
110 | $part = str_pad($part, $maxSize, chr(0)); | |
111 | $part = str_split($part, $blockSize); | |
112 | } | |
113 | return $parts; | |
114 | } | |
115 | } |