/** * Verify a MAC, given a MAC key * * @param string $message * @param \ParagonIE\Halite\Contract\CryptoKeyInterface $secretKey * @param string $mac * @param boolean $raw * @return boolean */ public static function verify($message, Contract\CryptoKeyInterface $secretKey, $mac, $raw = false) { if (!$raw) { $mac = \Sodium\hex2bin($mac); } return self::verifyMAC($mac, $message, $secretKey->get()); }
/** * Stream decryption - Do not call directly * * @param resource $input * @param resource $output * @param Key $encKey * @param string $nonce * @param resource $mac (hash context) * @param &array $config * @throws FileAlert\AccessDenied */ private static final function streamDecrypt($input, $output, \ParagonIE\Halite\Contract\CryptoKeyInterface $encKey, $nonce, $mac, array $config, array &$chunk_macs) { // Reset the stream pointer to the beginning of the ciphertext $start = \ftell($input); if (\fseek($input, -1 * $config['MAC_SIZE'], SEEK_END) === false) { throw new CryptoAlert\CannotPerformOperation('Stream error'); } $cipher_end = \ftell($input) - 1; if (\fseek($input, $start, SEEK_SET) === false) { throw new CryptoAlert\CannotPerformOperation('Stream error'); } $break = false; while (!$break) { $pos = \ftell($input); if ($pos === false) { throw new CryptoAlert\CannotPerformOperation('Stream error'); } // Read the data from the input buffer if ($pos + $config['BUFFER'] >= $cipher_end) { $break = true; $read = self::readBytes($input, $cipher_end - $pos + 1); } else { $read = self::readBytes($input, $config['BUFFER']); } // Let's reculcualte the MAC of this chunk, then verify it \hash_update($mac, $read); $calcMAC = \hash_copy($mac); if ($calcMAC === false) { throw new CryptoAlert\CannotPerformOperation('An unknown error has occurred'); } $calc = \hash_final($calcMAC, true); if (empty($chunk_macs)) { throw new CryptoAlert\InvalidMessage('Invalid message authentication code'); } elseif (!\hash_equals(\array_shift($chunk_macs), $calc)) { throw new CryptoAlert\InvalidMessage('Invalid message authentication code'); } $decrypted = \Sodium\crypto_stream_xor($read, $nonce, $encKey->get()); $written = \fwrite($output, $decrypted); if ($written === false) { throw new FileAlert\AccessDenied('Could not write to the file'); } \Sodium\increment($nonce); } }
/** * Verify a signed message with the correct public key * * @param string $message Message to verify * @param Key $publickey * @param string $signature * @param boolean $raw Don't hex decode the input? * * @return boolean */ public static function verify($message, Contract\CryptoKeyInterface $publickey, $signature, $raw = false) { if (!$publickey->isSigningKey()) { throw new CryptoAlert\InvalidKey('Expected a signing key'); } if (!$publickey->isPublicKey()) { throw new CryptoAlert\InvalidKey('Expected a public key'); } if (!$raw) { $signature = \Sodium\hex2bin($signature); } return \Sodium\crypto_sign_verify_detached($signature, $message, $publickey->get()); }
/** * 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'])); }