Skip to content

Commit

Permalink
Merge pull request #33 from paragonie/file-generichash
Browse files Browse the repository at this point in the history
Implement ParagonIE_Sodiuim_File::generichash()
  • Loading branch information
paragonie-scott authored Feb 21, 2017
2 parents 4874a78 + 4ad46e6 commit fd577c6
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 2 deletions.
72 changes: 70 additions & 2 deletions src/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,74 @@ public static function box_seal_open($inputFile, $outputFile, $ecdhKeypair)
return $res;
}

/**
* Calculate the BLAKE2b hash of a file.
*
* @param string $filePath Absolute path to a file on the filesystem
* @param string|null $key BLAKE2b key
* @param int $outputLength Length of hash output
*
* @return string BLAKE2b hash
* @throws Error
* @throws TypeError
*/
public static function generichash($filePath, $key = '', $outputLength = 32)
{
if (!is_string($filePath)) {
throw new TypeError('Argument 1 must be a string.');
}
if (!is_string($key)) {
if ($key === null) {
$key = '';
} else {
throw new TypeError('Argument 2 must be a string');
}
}
if (!empty($key)) {
if (self::strlen($key) < ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
throw new TypeError('Argument 2 must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes');
}
if (self::strlen($key) > ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
throw new TypeError('Argument 2 must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes');
}
}
if (!is_int($outputLength)) {
if (!is_numeric($outputLength)) {
throw new TypeError('Argument 3 must be an integer');
}
$outputLength = (int) $outputLength;
}
if ($outputLength < ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MIN) {
throw new Error('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MIN');
}
if ($outputLength > ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MAX) {
throw new Error('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MAX');
}

/** @var int $size */
$size = filesize($filePath);
if (!is_int($size)) {
throw new Error('Could not obtain the file size');
}

/** @var resource $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new Error('Could not open input file for reading');
}
$ctx = ParagonIE_Sodium_Compat::crypto_generichash_init($key, $outputLength);
while ($size > 0) {
$blockSize = $size > 64
? 64
: $size;
ParagonIE_Sodium_Compat::crypto_generichash_update($ctx, fread($fp, $blockSize));
$size -= $blockSize;
}

fclose($fp);
return ParagonIE_Sodium_Compat::crypto_generichash_final($ctx, $outputLength);
}

/**
* Encrypt a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_secretbox(), but produces
Expand Down Expand Up @@ -465,7 +533,7 @@ public static function sign($filePath, $secretKey)
throw new Error('Could not obtain the file size');
}

/** @var resource $ifp */
/** @var resource $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new Error('Could not open input file for reading');
Expand Down Expand Up @@ -581,7 +649,7 @@ public static function verify($sig, $filePath, $publicKey)
throw new Error('Could not obtain the file size');
}

/** @var resource $ifp */
/** @var resource $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new Error('Could not open input file for reading');
Expand Down
23 changes: 23 additions & 0 deletions tests/unit/FileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,29 @@ public function testBox()
unlink('plaintext-box2.data');
}

/**
* @covers ParagonIE_Sodium_File::generichash()
*/
public function testGenerichash()
{
$randomSeed = random_bytes(32);
$randomNonce = random_bytes(24);
$orig = ParagonIE_Sodium_Compat::$fastMult;
$pseudoRandom = ParagonIE_Sodium_Compat::crypto_stream(
random_int(1 << 9, 1 << 17),
$randomNonce,
$randomSeed
);
file_put_contents('plaintext-hash.data', $pseudoRandom);
$file = ParagonIE_Sodium_File::generichash('plaintext-hash.data');
$this->assertSame(
ParagonIE_Sodium_Compat::crypto_generichash($pseudoRandom),
$file
);
ParagonIE_Sodium_Compat::$fastMult = $orig;
unlink('plaintext-hash.data');
}

/**
* @covers ParagonIE_Sodium_File::box_seal()
* @covers ParagonIE_Sodium_File::box_seal_open()
Expand Down

0 comments on commit fd577c6

Please sign in to comment.