* $stream = fopen('http://www.guardtime.com/data.txt', 'r'); * * $hash = new GTDataHash(GTHashAlgorithm::getByName('DEFAULT')); * $hash->update(array(0, 1, 2)); * $hash->updateFile('data.txt'); * $hahs->updateStream($stream); * $hash->close(); * * print_r($hash->getHashedMessage()); * * * Example 2 - hash with existing hash value: * * * $bytes = array( * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1 * ); * * $hash = new GTDataHash(GTHashAlgorithm::getByName('SHA256'), $bytes); * * * Example 3 - hash from dataImprint: * * * $dataImprint = array( * GTHashAlgorithm::getByName('SHA256')->getGtid(), * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1 * ); * * $hash = GTDataHash::getInstance($dataImprint); * * * @package tsp */ class GTDataHash { private $hashContext; private $hashAlgorithm; private $hashedMessage; /** * Builds a new hash object with the given hashAlgorithm and hashedMessage. * * When hashedMessage is null the GTDataHash will be open and it will be * possible to add more data using update methods. * * When hashedMessage is specified the GTDataHash will be closed and it's * not possible to add more data using update methods. * * * @throws GTException * @param GTHashAlgorithm $hashAlgorithm hash algorithm to use * @param array $hashedMessage hash bytes */ public function __construct($hashAlgorithm, $hashedMessage = null) { if (empty($hashAlgorithm)) { throw new GTException("parameter hashAlgorithm must not be empty"); } if (!($hashAlgorithm instanceof GTHashAlgorithm)) { throw new GTException("parameter hashAlgorithm must be an instance of GTHashAlgorithm"); } $this->hashAlgorithm = $hashAlgorithm; if ($hashedMessage == null) { $this->hashContext = hash_init($this->hashAlgorithm->getName()); if (!is_resource($this->hashContext)) { throw new GTException("Unable to init GTDataHash with algorithm: {$this->hashAlgorithm->getName()}"); } } else { if (!is_array($hashedMessage)) { throw new GTException("hash must be an array of bytes"); } if (count($hashedMessage) != $this->hashAlgorithm->getLength()) { throw new GTException("hash length does not match with that defined in hash algorithm"); } $this->hashedMessage = $hashedMessage; } } /** * Updates this hash calculator with the given bytes. * * @throws GTException * @param $bytes byte array to feed to this hash calculator * @return void */ public function update($bytes) { if ($this->isClosed()) { throw new GTException("hash calculator already closed"); } if (empty($bytes)) { throw new GTException("parameter bytes must not be empty"); } $result = hash_update($this->hashContext, GTUtil::fromByteArray($bytes)); if (!$result) { throw new GTException("hash update failed with unknown error"); } } /** * Updates this hash calculator with the bytes from the given file. * * @throws GTException * @param string $file file to feed to this hash calculator * @return void */ public function updateFile($file) { if ($this->isClosed()) { throw new GTException("hash calculator already closed"); } if (empty($file)) { throw new GTException("parameter file must not be empty"); } if (!is_file($file)) { throw new GTException("file must be a file"); } if (!is_readable($file)) { throw new GTException("file must be readable"); } if (filesize($file) == 0) { throw new GTException("file must not be 0 bytes"); } $result = hash_update_file($this->hashContext, $file); if (!$result) { throw new GTException("hash updateFile failed with unknown error"); } } /** * Updates this hash calculator with the bytes from the given stream. * * @throws GTException * @param $handle handle of the stream to feed to this hash calculator * @return void */ public function updateStream($handle) { if ($this->isClosed()) { throw new GTException("hash calculator already closed"); } if (empty($handle)) { throw new GTException("parameter handle must not be empty"); } if (!is_resource($handle)) { throw new GTException("parameter handle must be a resource"); } $result = hash_update_stream($this->hashContext, $handle); if (!$result) { throw new GTException("hash updateStream failed with unknown error"); } } /** * Explicitly closes this hash calculator. * * After the hash calculator is closed all calls to update methods will throw an exception. * * @return GTDataHash */ public function close() { if (!$this->isClosed()) { $this->hashedMessage = GTUtil::toByteArray(hash_final($this->hashContext, true)); $this->hashContext = null; } return $this; } /** * Checks if this hash calculator is closed. * * @return bool true if this hash calculator is closed. */ public function isClosed() { return $this->hashContext == null; } /** * Gets the GTHashAlgorithm used by this hash calculator. * * @return GTHashAlgorithm the currently used algorithm */ public function getHashAlgorithm() { return $this->hashAlgorithm; } /** * Gets the current hash bytes. * * This method will also close the hash calculator when called. After closing * all update() methods will throw an exception. * * @return array */ public function getHashedMessage() { if ($this->isClosed()) { $this->close(); } return $this->hashedMessage; } /** * Gets the current hash data imprint. * * This method will also close the hash calculator when called. After closing * all update() methods will throw an exception. * * Data imprint is an array of bytes consisting of GTHashAlgorithm->getGtid() + hash bytes * * @return array the data imprint */ public function getDataImprint() { if (!$this->isClosed()) { $this->close(); } $result = array($this->hashAlgorithm->getGtid()); foreach ($this->hashedMessage as $byte) { array_push($result, $byte); } return $result; } /** * Gets a GTDataHash instance from a $dataImprint. * * DataImprint is an array of bytes consisting of GTHashAlgorithm->getGtid() and hash bytes. * * * $dataImprint = array( * GTHashAlgorithm::getByName('SHA256')->getGtid(), * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1 * ); * * * @static * @throws GTException * @param array $dataImprint dataImprint bytes * @return GTDataHash */ public static function getInstance($dataImprint) { if (empty($dataImprint)) { throw new GTException("parameter dataImprint must not be empty"); } if (!is_array($dataImprint)) { throw new GTException("parameter dataImprint must be an array of bytes"); } if (count($dataImprint) < 2) { throw new GTException("parameter dataImprint must be at least 2 bytes long"); } $hashAlgorithm = GTHashAlgorithm::getByGtid($dataImprint[0]); $hashedMessage = array_slice($dataImprint, 1); return new GTDataHash($hashAlgorithm, $hashedMessage); } } ?>