123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- <?php
- /*
- * The RandomLib library for securely generating random numbers and strings in PHP
- *
- * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
- * @copyright 2011 The Authors
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
- * @version Build @@version@@
- */
- /**
- * An abstract mixer to implement a common mixing strategy
- *
- * PHP version 5.3
- *
- * @category PHPSecurityLib
- * @package Random
- *
- * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
- * @author Paragon Initiative Enterprises <security@paragonie.com>
- * @copyright 2011 The Authors
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
- *
- * @version Build @@version@@
- */
- namespace RandomLib;
- use SecurityLib\Util;
- /**
- * An abstract mixer to implement a common mixing strategy
- *
- * @see http://tools.ietf.org/html/rfc4086#section-5.2
- *
- * @category PHPSecurityLib
- * @package Random
- *
- * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
- * @author Paragon Initiative Enterprises <security@paragonie.com>
- */
- abstract class AbstractMixer implements \RandomLib\Mixer
- {
- /**
- * Get the block size (the size of the individual blocks used for the mixing)
- *
- * @return int The block size
- */
- abstract protected function getPartSize();
- /**
- * Mix 2 parts together using one method
- *
- * @param string $part1 The first part to mix
- * @param string $part2 The second part to mix
- *
- * @return string The mixed data
- */
- abstract protected function mixParts1($part1, $part2);
- /**
- * Mix 2 parts together using another different method
- *
- * @param string $part1 The first part to mix
- * @param string $part2 The second part to mix
- *
- * @return string The mixed data
- */
- abstract protected function mixParts2($part1, $part2);
- /**
- * @return bool
- */
- public static function advisable()
- {
- return static::test();
- }
- /**
- * Mix the provided array of strings into a single output of the same size
- *
- * All elements of the array should be the same size.
- *
- * @param array<int, string> $parts The parts to be mixed
- *
- * @return string The mixed result
- * @psalm-suppress MixedArgument
- */
- public function mix(array $parts)
- {
- if (empty($parts)) {
- return '';
- }
- /** @var int $len */
- $len = Util::safeStrlen($parts[0]);
- /** @var array<int, array<int, string>> $parts */
- $parts = $this->normalizeParts($parts);
- $stringSize = \count($parts[0]);
- $partsSize = \count($parts);
- /** @var string $result */
- $result = '';
- /** @var int $offset */
- $offset = 0;
- for ($i = 0; $i < $stringSize; ++$i) {
- /** @var string $stub */
- $stub = (string) $parts[$offset][$i];
- for ($j = 1; $j < $partsSize; ++$j) {
- /** @var string $newKey */
- $newKey = $parts[($j + $offset) % $partsSize][$i];
- //Alternately mix the output for each source
- if ($j % 2 == 1) {
- $stub ^= $this->mixParts1($stub, $newKey);
- } else {
- $stub ^= $this->mixParts2($stub, $newKey);
- }
- }
- $result .= $stub;
- $offset = ($offset + 1) % $partsSize;
- }
- /** @var string $final */
- $final = Util::safeSubstr($result, 0, $len);
- return $final;
- }
- /**
- * Normalize the part array and split it block part size.
- *
- * This will make all parts the same length and a multiple
- * of the part size
- *
- * @param array<int, string> $parts The parts to normalize
- *
- * @return array The normalized and split parts
- * @psalm-suppress MissingClosureReturnType
- * @psalm-suppress UntypedParam
- * @psalm-suppress MissingArgument
- */
- protected function normalizeParts(array $parts)
- {
- if (empty($parts)) {
- return $parts;
- }
- $blockSize = $this->getPartSize();
- $callback =
- /**
- * @var callable $callback
- * @param string $value
- * @return int
- */
- function ($value) {
- return (int) Util::safeStrlen($value);
- };
- $mapped = array_map($callback, $parts);
- if (count($mapped) < 1) {
- return array();
- }
- /** @var int $maxSize */
- $maxSize = count($mapped) > 1
- ? max($mapped)
- : array_shift($mapped);
- if ($maxSize % $blockSize != 0) {
- $maxSize += $blockSize - ($maxSize % $blockSize);
- }
- foreach ($parts as &$part) {
- $part = $this->str_pad($part, $maxSize, chr(0));
- $part = str_split($part, $blockSize);
- }
- return $parts;
- }
- /**
- * @param string $string
- * @param int $size
- * @param string $character
- * @return string
- */
- private function str_pad($string, $size, $character)
- {
- $start = Util::safeStrlen($string);
- $inc = Util::safeStrlen($character);
- for ($i = $start; $i < $size; $i+= $inc) {
- $string = $string . $character;
- }
- return Util::safeSubstr($string, 0, $size);
- }
- }
|