Skip to content

Commit

Permalink
Merge pull request #153 from paragonie/hex2bin-ignore
Browse files Browse the repository at this point in the history
Add ignore to sodium_hex2bin()
  • Loading branch information
paragonie-security authored Sep 26, 2022
2 parents 215ae42 + fa40fa3 commit 2465e19
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 18 deletions.
5 changes: 3 additions & 2 deletions lib/php72compat.php
Original file line number Diff line number Diff line change
Expand Up @@ -1286,13 +1286,14 @@ function sodium_crypto_stream_xor($message, $nonce, $key)
/**
* @see ParagonIE_Sodium_Compat::hex2bin()
* @param string $string
* @param string $ignore
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_hex2bin($string)
function sodium_hex2bin($string, $ignore = '')
{
return ParagonIE_Sodium_Compat::hex2bin($string);
return ParagonIE_Sodium_Compat::hex2bin($string, $ignore);
}
}
if (!is_callable('sodium_increment')) {
Expand Down
10 changes: 6 additions & 4 deletions src/Compat.php
Original file line number Diff line number Diff line change
Expand Up @@ -3219,26 +3219,28 @@ public static function crypto_stream_xchacha20_keygen()
* Cache-timing-safe implementation of hex2bin().
*
* @param string $string Hexadecimal string
* @param string $ignore List of characters to ignore; useful for whitespace
* @return string Raw binary string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress TooFewArguments
* @psalm-suppress MixedArgument
*/
public static function hex2bin($string)
public static function hex2bin($string, $ignore = '')
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($ignore, 'string', 2);

if (self::useNewSodiumAPI()) {
if (is_callable('sodium_hex2bin')) {
return (string) sodium_hex2bin($string);
return (string) sodium_hex2bin($string, $ignore);
}
}
if (self::use_fallback('hex2bin')) {
return (string) call_user_func('\\Sodium\\hex2bin', $string);
return (string) call_user_func('\\Sodium\\hex2bin', $string, $ignore);
}
return ParagonIE_Sodium_Core_Util::hex2bin($string);
return ParagonIE_Sodium_Core_Util::hex2bin($string, $ignore);
}

/**
Expand Down
20 changes: 8 additions & 12 deletions src/Core/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -309,27 +309,26 @@ protected static function hash_update(&$hs, $data)
* @internal You should not use this directly from another application
*
* @param string $hexString
* @param string $ignore
* @param bool $strictPadding
* @return string (raw binary)
* @throws RangeException
* @throws TypeError
*/
public static function hex2bin($hexString, $strictPadding = false)
public static function hex2bin($hexString, $ignore = '', $strictPadding = false)
{
/* Type checks: */
if (!is_string($hexString)) {
throw new TypeError('Argument 1 must be a string, ' . gettype($hexString) . ' given.');
}
if (!is_string($ignore)) {
throw new TypeError('Argument 2 must be a string, ' . gettype($hexString) . ' given.');
}

/** @var int $hex_pos */
$hex_pos = 0;
/** @var string $bin */
$bin = '';
/** @var int $c_acc */
$c_acc = 0;
/** @var int $hex_len */
$hex_len = self::strlen($hexString);
/** @var int $state */
$state = 0;
if (($hex_len & 1) !== 0) {
if ($strictPadding) {
Expand All @@ -347,20 +346,18 @@ public static function hex2bin($hexString, $strictPadding = false)
++$hex_pos;
/** @var int $c */
$c = $chunk[$hex_pos];
/** @var int $c_num */
$c_num = $c ^ 48;
/** @var int $c_num0 */
$c_num0 = ($c_num - 10) >> 8;
/** @var int $c_alpha */
$c_alpha = ($c & ~32) - 55;
/** @var int $c_alpha0 */
$c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8;
if (($c_num0 | $c_alpha0) === 0) {
if ($ignore && $state === 0 && strpos($ignore, self::intToChr($c)) !== false) {
continue;
}
throw new RangeException(
'hex2bin() only expects hexadecimal characters'
);
}
/** @var int $c_val */
$c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0);
if ($state === 0) {
$c_acc = $c_val * 16;
Expand All @@ -382,7 +379,6 @@ public static function hex2bin($hexString, $strictPadding = false)
*/
public static function intArrayToString(array $ints)
{
/** @var array<int, int> $args */
$args = $ints;
foreach ($args as $i => $v) {
$args[$i] = (int) ($v & 0xff);
Expand Down
32 changes: 32 additions & 0 deletions tests/unit/HexTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

class HexTest extends PHPUnit_Framework_TestCase
{
public function hexProvider()
{
return array(
array('DEADBEEF', '', "\xde\xad\xbe\xef", false),
array('DeAdBeeF', '', "\xde\xad\xbe\xef", false),
array("De\nAdBe\neF", "\n", "\xde\xad\xbe\xef", false),
array("De\nAdBe eF", "\n", "\xde\xad\xbe\xef", true),
array("De\nAdBe eF", "\n ", "\xde\xad\xbe\xef", false),
array("De AdBe eF", " ", "\xde\xad\xbe\xef", false),
);
}

/**
* @dataProvider hexProvider
*/
public function testHex2Bin($hex, $ignore, $binary, $fail)
{
try {
$decoded = ParagonIE_Sodium_Compat::hex2bin($hex, $ignore);
$this->assertFalse($fail, 'This should have failed but did not!');
$this->assertSame($binary, $decoded, 'Binary mismatch');
} catch (RangeException $ex) {
$this->assertTrue($fail, 'An unexpected hex2bin failure occurred');
} catch (SodiumException $ex) {
$this->assertTrue($fail, 'An unexpected hex2bin failure occurred');
}
}
}

0 comments on commit 2465e19

Please sign in to comment.