Last active
August 29, 2015 13:56
-
-
Save defuse/8911037 to your computer and use it in GitHub Desktop.
Side channel safe hex encoding?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// WARNING: THIS IS EXPERIMENTAL CODE. DO NOT USE IT. | |
// --- binary to hex encoding --- | |
function sc_bin2hex($binary) | |
{ | |
$encoded = ''; | |
for ($i = 0; $i < strlen($binary); $i++) { | |
$high_nibble = ord($binary[$i]) >> 4; | |
$low_nibble = ord($binary[$i]) & 0x0F; | |
$encoded .= sc_nibble_to_hex($high_nibble); | |
$encoded .= sc_nibble_to_hex($low_nibble); | |
} | |
return $encoded; | |
} | |
function sc_nibble_to_hex($nibble) | |
{ | |
// Assumes ASCII. FIXME Is it always ASCII in PHP? | |
$dec = ord('0') + $nibble; | |
$hex = ord('a') + $nibble - 10; | |
// All ones if $nibble is less than 10. All zeroes otherwise. | |
$lt_ten = ($nibble - 10) >> (PHP_INT_SIZE * 8 - 1); | |
return chr( (~$lt_ten & $hex) | ($lt_ten & $dec) ); | |
} | |
// --- hex to binary decoding --- | |
function sc_hex2bin($hex) | |
{ | |
if (strlen($hex) % 2 !== 0) { | |
return false; | |
} | |
$decoded = ''; | |
for ($i = 0; $i + 1 < strlen($hex); $i += 2) { | |
$high_nibble = sc_hex_to_nibble($hex[$i]); | |
$low_nibble = sc_hex_to_nibble($hex[$i+1]); | |
if ($high_nibble === false || $low_nibble === false) { | |
return false; | |
} | |
$decoded .= chr(($high_nibble << 4) | $low_nibble); | |
} | |
return $decoded; | |
} | |
function sc_hex_to_nibble($hex_digit) | |
{ | |
$hex_digit = ord($hex_digit); | |
// We have to do the decimal digit checks before | |
// making the character lower case, otherwise it | |
// will accept things like chr(25). | |
// $hex_digit is a character that comes before '0' in ASCII. | |
$lt_zero = ($hex_digit - ord('0')) >> (PHP_INT_SIZE*8 - 1); | |
// $hex_digit is a character that comes after '9' in ASCII. | |
$gt_nine = (ord('9') - $hex_digit) >> (PHP_INT_SIZE*8 - 1); | |
// ASCII hack to make it lower case. | |
$hex_digit = $hex_digit | 32; | |
// $hex_digit is a character that comes before 'a' in ASCII. | |
$lt_a = ($hex_digit - ord('a')) >> (PHP_INT_SIZE*8 - 1); | |
// $hex_digit is a character that comes after 'f' in ASCII. | |
$gt_f = (ord('f') - $hex_digit) >> (PHP_INT_SIZE*8 - 1); | |
// Assume it's in 0-9, then the nibble value will be $dec. | |
$dec = $hex_digit - ord('0'); | |
// Assume it's in a-f, then the nibble value will be $hex. | |
$hex = $hex_digit - ord('a') + 10; | |
// But which one is it? | |
$is_dec = ~$lt_zero & ~$gt_nine; | |
$is_hex = ~$lt_a & ~$gt_f; | |
// If it's not in either 0-9 or a-f... | |
if (($is_dec | $is_hex) === 0) { | |
return false; | |
} | |
// Use $dec if it's in 0-9, or $hex if it's in a-f. | |
return ($dec & $is_dec) | ($hex & $is_hex); | |
} | |
// --- testing --- | |
echo sc_hex2bin("48494A4b4c"); | |
// exit; | |
for ($i = 1; $i < 1000; $i++) { | |
$test = mcrypt_create_iv($i, MCRYPT_DEV_URANDOM); | |
$test_hex = sc_bin2hex($test); | |
$test_hex_correct = bin2hex($test); | |
$test_hex_decode = sc_hex2bin($test_hex_correct); | |
if ($test_hex !== $test_hex_correct || $test_hex_decode !== $test) { | |
echo "IT DOES NOT WORK !!!! \n"; | |
exit; | |
} else { | |
echo $test_hex . "\n"; | |
} | |
} | |
echo "ALL GOOD!\n"; | |
// // Old code | |
// | |
// function safe_string_index($string, $index) | |
// { | |
// $character = 0; | |
// for ($i = 0; $i < strlen($string); $i++) { | |
// $x = $i ^ $index; | |
// $mask = (((($x | ($x >> 16)) & 0xFFFF) + 0xFFFF) >> 16) - 1; | |
// $character |= ord($string[$i]) & $mask; | |
// } | |
// return chr($character); | |
// } | |
// | |
// function side_channel_safe_bin2hex($binary) { | |
// $hex = '0123456789abcdef'; | |
// $encoded = ''; | |
// for ($i = 0; $i < strlen($binary); $i++) { | |
// $byte = ord($binary[$i]); | |
// $encoded .= safe_string_index($hex, $byte >> 4); | |
// $encoded .= safe_string_index($hex, $byte & 0x0F); | |
// } | |
// return $encoded; | |
// } | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment