* $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);
}
}
?>