Example #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;
 }
Example #2
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;
 }