Пример #1
0
 /**
  * Recalculate and verify the HMAC of the input file
  *
  * @param resource $input
  * @param resource|string $mac (hash context)
  * @param Config $config
  *
  * @return array Hashes of various chunks
  * @throws CryptoException\CannotPerformOperation
  * @throws CryptoException\InvalidMessage
  */
 private static final function streamVerify(ReadOnlyFile $input, $mac, Config $config) : array
 {
     $start = $input->getPos();
     $cipher_end = $input->getSize() - $config->MAC_SIZE;
     $input->reset($cipher_end);
     $stored_mac = $input->readBytes($config->MAC_SIZE);
     $input->reset($start);
     $chunk_macs = [];
     $break = false;
     while (!$break && $input->getPos() < $cipher_end) {
         /**
          * Would a full BUFFER read put it past the end of the
          * ciphertext? If so, only return a portion of the file.
          */
         if ($input->getPos() + $config->BUFFER >= $cipher_end) {
             $break = true;
             $read = $input->readBytes($cipher_end - $input->getPos());
         } else {
             $read = $input->readBytes($config->BUFFER);
         }
         /**
          * We're updating our HMAC and nothing else
          */
         if ($config->USE_BLAKE2B) {
             \Sodium\crypto_generichash_update($mac, $read);
             $chunkMAC = '' . $mac;
             $chunk_macs[] = \Sodium\crypto_generichash_final($chunkMAC, $config->MAC_SIZE);
         } else {
             \hash_update($mac, $read);
             /**
              * Store a MAC of each chunk
              */
             $chunkMAC = \hash_copy($mac);
             if ($chunkMAC === false) {
                 throw new CryptoException\CannotPerformOperation('An unknown error has occurred');
             }
             $chunk_macs[] = \hash_final($chunkMAC, true);
         }
     }
     /**
      * We should now have enough data to generate an identical HMAC
      */
     if ($config->USE_BLAKE2B) {
         $finalHMAC = \Sodium\crypto_generichash_final($mac, $config->MAC_SIZE);
     } else {
         $finalHMAC = \hash_final($mac, true);
     }
     /**
      * Use hash_equals() to be timing-invariant
      */
     if (!\hash_equals($finalHMAC, $stored_mac)) {
         throw new CryptoException\InvalidMessage('Invalid message authentication code');
     }
     $input->reset($start);
     return $chunk_macs;
 }
Пример #2
0
 /**
  * Calculate a BLAHE2b checksum of a file
  * 
  * @param string $fileHandle The file you'd like to checksum
  * @param string $key An optional BLAKE2b key
  * @param bool $raw Set to true if you don't want hex
  * 
  * @return string
  */
 public static function checksumResource($fileHandle, \ParagonIE\Halite\Contract\CryptoKeyInterface $key = null, $raw = false)
 {
     // Input validation
     if (!\is_resource($fileHandle)) {
         throw new \ParagonIE\Halite\Alerts\InvalidType('Expected input handle to be a resource');
     }
     $config = self::getConfig(Halite::HALITE_VERSION, 'checksum');
     if ($key) {
         $state = \Sodium\crypto_generichash_init($key->get(), $config['HASH_LEN']);
     } else {
         $state = \Sodium\crypto_generichash_init(null, $config['HASH_LEN']);
     }
     while (!\feof($fileHandle)) {
         $read = \fread($fileHandle, $config['BUFFER']);
         if ($read === false) {
             throw new CryptoException\FileAccessDenied('Could not read from the file');
         }
         \Sodium\crypto_generichash_update($state, $read);
     }
     if ($raw) {
         return \Sodium\crypto_generichash_final($state, $config['HASH_LEN']);
     }
     return \Sodium\bin2hex(\Sodium\crypto_generichash_final($state, $config['HASH_LEN']));
 }
Пример #3
0
 /**
  * 
  * @param \ParagonIE\Halite\Contract\StreamInterface $fileStream
  * @param AuthenticationKey $key
  * @param type $raw
  * @return type
  */
 public static function checksumStream(StreamInterface $fileStream, KeyInterface $key = null, $raw = false)
 {
     $config = self::getConfig(Halite::HALITE_VERSION_FILE, 'checksum');
     if ($key) {
         if (!$key instanceof AuthenticationKey) {
             throw new \ParagonIE\Halite\Alerts\InvalidKey('Argument 2: Expected an instance of AuthenticationKey');
         }
         $state = \Sodium\crypto_generichash_init($key->get(), $config->HASH_LEN);
     } else {
         $state = \Sodium\crypto_generichash_init(null, $config->HASH_LEN);
     }
     $size = $fileStream->getSize();
     while ($fileStream->remainingBytes() > 0) {
         $read = $fileStream->readBytes($fileStream->getPos() + $config->BUFFER > $size ? $size - $fileStream->getPos() : $config->BUFFER);
         \Sodium\crypto_generichash_update($state, $read);
     }
     if ($raw) {
         return \Sodium\crypto_generichash_final($state, $config->HASH_LEN);
     }
     return \Sodium\bin2hex(\Sodium\crypto_generichash_final($state, $config->HASH_LEN));
 }
Пример #4
0
 /**
  * Calculate a BLAKE2b hash of a file
  * 
  * @return string
  */
 public function getHash()
 {
     $init = $this->pos;
     \fseek($this->fp, 0, SEEK_SET);
     // Create a hash context:
     $h = \Sodium\crypto_generichash_init(null, \Sodium\CRYPTO_GENERICHASH_BYTES_MAX);
     for ($i = 0; $i < $this->stat['size']; $i += self::CHUNK) {
         if ($i + self::CHUNK > $this->stat['size']) {
             $c = \fread($this->fp, $this->stat['size'] - $i);
         } else {
             $c = \fread($this->fp, self::CHUNK);
         }
         \Sodium\crypto_generichash_update($h, $c);
     }
     // Reset the file pointer's internal cursor to where it was:
     \fseek($this->fp, $init, SEEK_SET);
     return \Sodium\crypto_generichash_final($h);
 }
Пример #5
0
 /**
  * Recalculate and verify the HMAC of the input file
  *
  * @param ReadOnlyFile $input  The file we are verifying
  * @param resource|string $mac (hash context)
  * @param Config $config       Version-specific settings
  * @return array               Hashes of various chunks
  * @throws CannotPerformOperation
  * @throws InvalidMessage
  */
 private static final function streamVerify(ReadOnlyFile $input, $mac, Config $config) : array
 {
     $start = $input->getPos();
     // Grab the stored MAC:
     $cipher_end = $input->getSize() - $config->MAC_SIZE;
     $input->reset($cipher_end);
     $stored_mac = $input->readBytes($config->MAC_SIZE);
     $input->reset($start);
     $chunkMACs = [];
     $break = false;
     while (!$break && $input->getPos() < $cipher_end) {
         /**
          * Would a full BUFFER read put it past the end of the
          * ciphertext? If so, only return a portion of the file.
          */
         if ($input->getPos() + $config->BUFFER >= $cipher_end) {
             $break = true;
             $read = $input->readBytes($cipher_end - $input->getPos());
         } else {
             $read = $input->readBytes($config->BUFFER);
         }
         /**
          * We're updating our HMAC and nothing else
          */
         \Sodium\crypto_generichash_update($mac, $read);
         // Copy the hash state then store the MAC of this chunk
         $chunkMAC = Util::safeStrcpy($mac);
         $chunkMACs[] = \Sodium\crypto_generichash_final($chunkMAC, $config->MAC_SIZE);
     }
     /**
      * We should now have enough data to generate an identical MAC
      */
     $finalHMAC = \Sodium\crypto_generichash_final($mac, $config->MAC_SIZE);
     /**
      * Use hash_equals() to be timing-invariant
      */
     if (!\hash_equals($finalHMAC, $stored_mac)) {
         throw new InvalidMessage('Invalid message authentication code');
     }
     $input->reset($start);
     return $chunkMACs;
 }