diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Encoding.php | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/src/Encoding.php b/src/Encoding.php index 3324b34..81983c2 100644 --- a/src/Encoding.php +++ b/src/Encoding.php @@ -336,6 +336,63 @@ class Encoding } /** + * Convert a binary string into a hexadecimal string without cache-timing + * leaks + * + * @param string $bin_string (raw binary) + * @return string + */ + public static function hexEncode($bin_string) + { + $hex = ''; + $len = self::safeStrlen($bin_string); + for ($i = 0; $i < $len; ++$i) { + $c = \ord($bin_string[$i]) & 0xf; + $b = \ord($bin_string[$i]) >> 4; + $hex .= \chr(87 + $b + ((($b - 10) >> 8) & ~38)); + $hex .= \chr(87 + $c + ((($c - 10) >> 8) & ~38)); + } + return $hex; + } + + /** + * Convert a hexadecimal string into a binary string without cache-timing + * leaks + * + * @param string $hex_string + * @return string (raw binary) + */ + public static function hexDecode($hex_string) + { + $hex_pos = 0; + $bin = ''; + $hex_len = self::safeStrlen($hex_string); + $state = 0; + + while ($hex_pos < $hex_len) { + $c = \ord($hex_string[$hex_pos]); + $c_num = $c ^ 48; + $c_num0 = ($c_num - 10) >> 8; + $c_alpha = ($c & ~32) - 55; + $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8; + if (($c_num0 | $c_alpha0) === 0) { + throw new \RangeException( + 'hexEncode() only expects hexadecimal characters' + ); + } + $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0); + if ($state === 0) { + $c_acc = $c_val * 16; + } else { + $bin .= \chr($c_acc | $c_val); + } + $state = $state ? 0 : 1; + ++$hex_pos; + } + return $bin; + } + + /** * * Base64 character set: * [A-Z] [a-z] [0-9] + / @@ -487,7 +544,7 @@ class Encoding * @param string $str * @return int */ - public static function safeStrlen($str) + protected static function safeStrlen($str) { if (\function_exists('mb_strlen')) { return \mb_strlen($str, '8bit'); |