123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- <?php
- namespace Aws\Crypto\Polyfill;
- /**
- * Class ByteArray
- */
- class ByteArray extends \SplFixedArray
- {
- use NeedsTrait;
- /**
- * ByteArray constructor.
- *
- * @param int|string|int[] $size
- * If you pass in an integer, it creates a ByteArray of that size.
- * If you pass in a string or array, it converts it to an array of
- * integers between 0 and 255.
- * @throws \InvalidArgumentException
- */
- public function __construct($size = 0)
- {
- $arr = null;
- // Integer? This behaves just like SplFixedArray.
- if (\is_array($size)) {
- // Array? We need to pass the count to parent::__construct() then populate
- $arr = $size;
- $size = \count($arr);
- } elseif (\is_string($size)) {
- // We need to avoid mbstring.func_overload
- if (\is_callable('\\mb_str_split')) {
- $tmp = \mb_str_split($size, 1, '8bit');
- } else {
- $tmp = \str_split($size, 1);
- }
- // Let's convert each character to an 8-bit integer and store in $arr
- $arr = [];
- if (!empty($tmp)) {
- foreach ($tmp as $t) {
- if (strlen($t) < 1) {
- continue;
- }
- $arr []= \unpack('C', $t)[1] & 0xff;
- }
- }
- $size = \count($arr);
- } elseif ($size instanceof ByteArray) {
- $arr = $size->toArray();
- $size = $size->count();
- } elseif (!\is_int($size)) {
- throw new \InvalidArgumentException(
- 'Argument must be an integer, string, or array of integers.'
- );
- }
- parent::__construct($size);
- if (!empty($arr)) {
- // Populate this object with values from constructor argument
- foreach ($arr as $i => $v) {
- $this->offsetSet($i, $v);
- }
- } else {
- // Initialize to zero.
- for ($i = 0; $i < $size; ++$i) {
- $this->offsetSet($i, 0);
- }
- }
- }
- /**
- * Encode an integer into a byte array. 32-bit (unsigned), big endian byte order.
- *
- * @param int $num
- * @return self
- */
- public static function enc32be($num)
- {
- return new ByteArray(\pack('N', $num));
- }
- /**
- * @param ByteArray $other
- * @return bool
- */
- public function equals(ByteArray $other)
- {
- if ($this->count() !== $other->count()) {
- return false;
- }
- $d = 0;
- for ($i = $this->count() - 1; $i >= 0; --$i) {
- $d |= $this[$i] ^ $other[$i];
- }
- return $d === 0;
- }
- /**
- * @param ByteArray $array
- * @return ByteArray
- */
- public function exclusiveOr(ByteArray $array)
- {
- self::needs(
- $this->count() === $array->count(),
- 'Both ByteArrays must be equal size for exclusiveOr()'
- );
- $out = clone $this;
- for ($i = 0; $i < $this->count(); ++$i) {
- $out[$i] = $array[$i] ^ $out[$i];
- }
- return $out;
- }
- /**
- * Returns a new ByteArray incremented by 1 (big endian byte order).
- *
- * @param int $increase
- * @return self
- */
- public function getIncremented($increase = 1)
- {
- $clone = clone $this;
- $index = $clone->count();
- while ($index > 0) {
- --$index;
- $tmp = ($clone[$index] + $increase) & PHP_INT_MAX;
- $clone[$index] = $tmp & 0xff;
- $increase = $tmp >> 8;
- }
- return $clone;
- }
- /**
- * Sets a value. See SplFixedArray for more.
- *
- * @param int $index
- * @param int $newval
- * @return void
- */
- #[\ReturnTypeWillChange]
- public function offsetSet($index, $newval)
- {
- parent::offsetSet($index, $newval & 0xff);
- }
- /**
- * Return a copy of this ByteArray, bitshifted to the right by 1.
- * Used in Gmac.
- *
- * @return self
- */
- public function rshift()
- {
- $out = clone $this;
- for ($j = $this->count() - 1; $j > 0; --$j) {
- $out[$j] = (($out[$j - 1] & 1) << 7) | ($out[$j] >> 1);
- }
- $out[0] >>= 1;
- return $out;
- }
- /**
- * Constant-time conditional select. This is meant to read like a ternary operator.
- *
- * $z = ByteArray::select(1, $x, $y); // $z is equal to $x
- * $z = ByteArray::select(0, $x, $y); // $z is equal to $y
- *
- * @param int $select
- * @param ByteArray $left
- * @param ByteArray $right
- * @return ByteArray
- */
- public static function select($select, ByteArray $left, ByteArray $right)
- {
- self::needs(
- $left->count() === $right->count(),
- 'Both ByteArrays must be equal size for select()'
- );
- $rightLength = $right->count();
- $out = clone $right;
- $mask = (-($select & 1)) & 0xff;
- for ($i = 0; $i < $rightLength; $i++) {
- $out[$i] = $out[$i] ^ (($left[$i] ^ $right[$i]) & $mask);
- }
- return $out;
- }
- /**
- * Overwrite values of this ByteArray based on a separate ByteArray, with
- * a given starting offset and length.
- *
- * See JavaScript's Uint8Array.set() for more information.
- *
- * @param ByteArray $input
- * @param int $offset
- * @param int|null $length
- * @return self
- */
- public function set(ByteArray $input, $offset = 0, $length = null)
- {
- self::needs(
- is_int($offset) && $offset >= 0,
- 'Offset must be a positive integer or zero'
- );
- if (is_null($length)) {
- $length = $input->count();
- }
- $i = 0; $j = $offset;
- while ($i < $length && $j < $this->count()) {
- $this[$j] = $input[$i];
- ++$i;
- ++$j;
- }
- return $this;
- }
- /**
- * Returns a slice of this ByteArray.
- *
- * @param int $start
- * @param null $length
- * @return self
- */
- public function slice($start = 0, $length = null)
- {
- return new ByteArray(\array_slice($this->toArray(), $start, $length));
- }
- /**
- * Mutates the current state and sets all values to zero.
- *
- * @return void
- */
- public function zeroize()
- {
- for ($i = $this->count() - 1; $i >= 0; --$i) {
- $this->offsetSet($i, 0);
- }
- }
- /**
- * Converts the ByteArray to a raw binary string.
- *
- * @return string
- */
- public function toString()
- {
- $count = $this->count();
- if ($count === 0) {
- return '';
- }
- $args = $this->toArray();
- \array_unshift($args, \str_repeat('C', $count));
- // constant-time, PHP <5.6 equivalent to pack('C*', ...$args);
- return \call_user_func_array('\\pack', $args);
- }
- }
|