ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç PKh\>E NeedsTrait.phpnu[buf = new ByteArray(16); $this->h = new ByteArray( \openssl_encrypt( \str_repeat("\0", 16), "aes-{$keySize}-ecb", $aesKey->get(), OPENSSL_RAW_DATA | OPENSSL_NO_PADDING ) ); $this->key = $aesKey; $this->x = new ByteArray(16); $this->hf = new ByteArray( \openssl_encrypt( $nonce, "aes-{$keySize}-ecb", $aesKey->get(), OPENSSL_RAW_DATA | OPENSSL_NO_PADDING ) ); } /** * Update the object with some data. * * This method mutates this Gmac object. * * @param ByteArray $blocks * @return self */ public function update(ByteArray $blocks) { if (($blocks->count() + $this->bufLength) < self::BLOCK_SIZE) { // Write to internal buffer until we reach enough to write. $this->buf->set($blocks, $this->bufLength); $this->bufLength += $blocks->count(); return $this; } // Process internal buffer first. if ($this->bufLength > 0) { // 0 <= state.buf_len < BLOCK_SIZE is an invariant $tmp = new ByteArray(self::BLOCK_SIZE); $tmp->set($this->buf->slice(0, $this->bufLength)); $remainingBlockLength = self::BLOCK_SIZE - $this->bufLength; $tmp->set($blocks->slice(0, $remainingBlockLength), $this->bufLength); $blocks = $blocks->slice($remainingBlockLength); $this->bufLength = 0; $this->x = $this->blockMultiply($this->x->exclusiveOr($tmp), $this->h); } // Process full blocks. $numBlocks = $blocks->count() >> 4; for ($i = 0; $i < $numBlocks; ++$i) { $tmp = $blocks->slice($i << 4, self::BLOCK_SIZE); $this->x = $this->blockMultiply($this->x->exclusiveOr($tmp), $this->h); } $last = $numBlocks << 4; // Zero-fill buffer for ($i = 0; $i < 16; ++$i) { $this->buf[$i] = 0; } // Feed leftover into buffer. if ($last < $blocks->count()) { $tmp = $blocks->slice($last); $this->buf->set($tmp); $this->bufLength += ($blocks->count() - $last); } return $this; } /** * Finish processing the authentication tag. * * This method mutates this Gmac object (effectively resetting it). * * @param int $aadLength * @param int $ciphertextLength * @return ByteArray */ public function finish($aadLength, $ciphertextLength) { $lengthBlock = new ByteArray(16); $state = $this->flush(); // AES-GCM expects bit lengths, not byte lengths. $lengthBlock->set(ByteArray::enc32be($aadLength >> 29), 0); $lengthBlock->set(ByteArray::enc32be($aadLength << 3), 4); $lengthBlock->set(ByteArray::enc32be($ciphertextLength >> 29), 8); $lengthBlock->set(ByteArray::enc32be($ciphertextLength << 3), 12); $state->update($lengthBlock); $output = $state->x->exclusiveOr($state->hf); // Zeroize the internal values as a best-effort. $state->buf->zeroize(); $state->x->zeroize(); $state->h->zeroize(); $state->hf->zeroize(); return $output; } /** * Get a specific bit from the provided array, at the given index. * * [01234567], 8+[01234567], 16+[01234567], ... * * @param ByteArray $x * @param int $i * @return int */ protected function bit(ByteArray $x, $i) { $byte = $i >> 3; return ($x[$byte] >> ((7 - $i) & 7)) & 1; } /** * Galois Field Multiplication * * This function is the critical path that must be constant-time in order to * avoid timing side-channels against AES-GCM. * * The contents of each are always calculated, regardless of the branching * condition, to prevent another kind of timing leak. * * @param ByteArray $x * @param ByteArray $y * @return ByteArray */ protected function blockMultiply(ByteArray $x, ByteArray $y) { static $fieldPolynomial = null; if (!$fieldPolynomial) { $fieldPolynomial = new ByteArray([ 0xe1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]); } self::needs($x->count() === 16, 'Argument 1 must be a ByteArray of exactly 16 bytes'); self::needs($y->count() === 16, 'Argument 2 must be a ByteArray of exactly 16 bytes'); $v = clone $y; $z = new ByteArray(16); for ($i = 0; $i < 128; ++$i) { // if ($b) $z = $z->exclusiveOr($v); $b = $this->bit($x, $i); $z = ByteArray::select( $b, $z->exclusiveOr($v), $z ); // if ($b) $v = $v->exclusiveOr($fieldPolynomial); $b = $v[15] & 1; $v = $v->rshift(); $v = ByteArray::select( $b, $v->exclusiveOr($fieldPolynomial), $v ); } return $z; } /** * Finish processing any leftover bytes in the internal buffer. * * @return self */ public function flush() { if ($this->bufLength !== 0) { $this->x = $this->blockMultiply( $this->x->exclusiveOr($this->buf), $this->h ); $this->bufLength = 0; } return $this; } } PKh\qZZ ByteArray.phpnu[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); } } PKh\qTKey.phpnu[internalString = $str; } /** * Defense in depth: * * PHP 7.2 includes the Sodium cryptography library, which (among other things) * exposes a function called sodium_memzero() that we can use to zero-fill strings * to minimize the risk of sensitive cryptographic materials persisting in memory. * * If this function is not available, we XOR the string in-place with itself as a * best-effort attempt. */ public function __destruct() { if (extension_loaded('sodium') && function_exists('sodium_memzero')) { try { \sodium_memzero($this->internalString); } catch (\SodiumException $ex) { // This is a best effort, but does not provide the same guarantees as sodium_memzero(): $this->internalString ^= $this->internalString; } } } /** * @return string */ public function get() { return $this->internalString; } /** * @return int */ public function length() { if (\is_callable('\\mb_strlen')) { return (int) \mb_strlen($this->internalString, '8bit'); } return (int) \strlen($this->internalString); } } PKh\`u22 AesGcm.phpnu[ 0 && $blockSize <= PHP_INT_MAX, 'Block size must be a positive integer.', RangeException::class ); self::needs( $aesKey->length() << 3 === $keySize, 'Incorrect key size; expected ' . $keySize . ' bits, got ' . ($aesKey->length() << 3) . ' bits.' ); $this->aesKey = $aesKey; $this->keySize = $keySize; } /** * Encryption interface for AES-GCM * * @param string $plaintext Message to be encrypted * @param string $nonce Number to be used ONCE * @param Key $key AES Key * @param string $aad Additional authenticated data * @param string &$tag Reference to variable to hold tag * @param int $keySize Key size (bits) * @param int $blockSize Block size (bytes) -- How much memory to buffer * @return string * @throws InvalidArgumentException */ public static function encrypt( $plaintext, $nonce, Key $key, $aad, &$tag, $keySize = 256, $blockSize = 8192 ) { self::needs( self::strlen($nonce) === 12, 'Nonce must be exactly 12 bytes', InvalidArgumentException::class ); $encryptor = new AesGcm($key, $keySize, $blockSize); list($aadLength, $gmac) = $encryptor->gmacInit($nonce, $aad); $ciphertext = \openssl_encrypt( $plaintext, "aes-{$encryptor->keySize}-ctr", $key->get(), OPENSSL_NO_PADDING | OPENSSL_RAW_DATA, $nonce . "\x00\x00\x00\x02" ); /* Calculate auth tag in a streaming fashion to minimize memory usage: */ $ciphertextLength = self::strlen($ciphertext); for ($i = 0; $i < $ciphertextLength; $i += $encryptor->blockSize) { $cBlock = new ByteArray(self::substr($ciphertext, $i, $encryptor->blockSize)); $gmac->update($cBlock); } $tag = $gmac->finish($aadLength, $ciphertextLength)->toString(); return $ciphertext; } /** * Decryption interface for AES-GCM * * @param string $ciphertext Ciphertext to decrypt * @param string $nonce Number to be used ONCE * @param Key $key AES key * @param string $aad Additional authenticated data * @param string $tag Authentication tag * @param int $keySize Key size (bits) * @param int $blockSize Block size (bytes) -- How much memory to buffer * @return string Plaintext * * @throws CryptoPolyfillException * @throws InvalidArgumentException */ public static function decrypt( $ciphertext, $nonce, Key $key, $aad, &$tag, $keySize = 256, $blockSize = 8192 ) { /* Precondition: */ self::needs( self::strlen($nonce) === 12, 'Nonce must be exactly 12 bytes', InvalidArgumentException::class ); $encryptor = new AesGcm($key, $keySize, $blockSize); list($aadLength, $gmac) = $encryptor->gmacInit($nonce, $aad); /* Calculate auth tag in a streaming fashion to minimize memory usage: */ $ciphertextLength = self::strlen($ciphertext); for ($i = 0; $i < $ciphertextLength; $i += $encryptor->blockSize) { $cBlock = new ByteArray(self::substr($ciphertext, $i, $encryptor->blockSize)); $gmac->update($cBlock); } /* Validate auth tag in constant-time: */ $calc = $gmac->finish($aadLength, $ciphertextLength); $expected = new ByteArray($tag); self::needs($calc->equals($expected), 'Invalid authentication tag'); /* Return plaintext if auth tag check succeeded: */ return \openssl_decrypt( $ciphertext, "aes-{$encryptor->keySize}-ctr", $key->get(), OPENSSL_NO_PADDING | OPENSSL_RAW_DATA, $nonce . "\x00\x00\x00\x02" ); } /** * Initialize a Gmac object with the nonce and this object's key. * * @param string $nonce Must be exactly 12 bytes long. * @param string|null $aad * @return array */ protected function gmacInit($nonce, $aad = null) { $gmac = new Gmac( $this->aesKey, $nonce . "\x00\x00\x00\x01", $this->keySize ); $aadBlock = new ByteArray($aad); $aadLength = $aadBlock->count(); $gmac->update($aadBlock); $gmac->flush(); return [$aadLength, $gmac]; } /** * Calculate the length of a string. * * Uses the appropriate PHP function without being brittle to * mbstring.func_overload. * * @param string $string * @return int */ protected static function strlen($string) { if (\is_callable('\\mb_strlen')) { return (int) \mb_strlen($string, '8bit'); } return (int) \strlen($string); } /** * Return a substring of the provided string. * * Uses the appropriate PHP function without being brittle to * mbstring.func_overload. * * @param string $string * @param int $offset * @param int|null $length * @return string */ protected static function substr($string, $offset = 0, $length = null) { if (\is_callable('\\mb_substr')) { return \mb_substr($string, $offset, $length, '8bit'); } elseif (!\is_null($length)) { return \substr($string, $offset, $length); } return \substr($string, $offset); } } PK;\{E}}StreamedReadingTrait.phpnu[read($path)) { return false; } $stream = fopen('php://temp', 'w+b'); fwrite($stream, $data['contents']); rewind($stream); $data['stream'] = $stream; unset($data['contents']); return $data; } /** * Reads a file. * * @param string $path * * @return array|false * * @see League\Flysystem\ReadInterface::read() */ abstract public function read($path); } PK;\:StreamedTrait.phpnu[stream($path, $resource, $config, 'write'); } /** * Update a file using a stream. * * @param string $path * @param resource $resource * @param Config $config Config object or visibility setting * * @return mixed false of file metadata */ public function updateStream($path, $resource, Config $config) { return $this->stream($path, $resource, $config, 'update'); } // Required abstract methods abstract public function write($pash, $contents, Config $config); abstract public function update($pash, $contents, Config $config); } PK;\*%%StreamedCopyTrait.phpnu[readStream($path); if ($response === false || ! is_resource($response['stream'])) { return false; } $result = $this->writeStream($newpath, $response['stream'], new Config()); if ($result !== false && is_resource($response['stream'])) { fclose($response['stream']); } return $result !== false; } // Required abstract method /** * @param string $path * * @return resource */ abstract public function readStream($path); /** * @param string $path * @param resource $resource * @param Config $config * * @return resource */ abstract public function writeStream($path, $resource, Config $config); } PKh\>E NeedsTrait.phpnu[PKh\o:7Gmac.phpnu[PKh\qZZ  ByteArray.phpnu[PKh\qT8Key.phpnu[PKh\`u22 ?AesGcm.phpnu[PK;\{E}}[StreamedReadingTrait.phpnu[PK;\:^StreamedTrait.phpnu[PK;\\I _NotSupportingVisibilityTrait.phpnu[PK;\tU!!bStreamedWritingTrait.phpnu[PK;\*%%;iStreamedCopyTrait.phpnu[PK *m