1

Let's say I have a byte-stream in which I know the location of a 64-bit value (a 64-bit nonce). The byte-order is Little-Endian. As PHP's integer data-type is limited to 32-bit (at least on 32-bit operating systems) how would I convert the byte-sequence into a PHP numeric representation (float would be sufficient I think)?

$serverChallenge = substr($bytes, 24, 8);
// $serverChallenge now contains the byte-sequence 
// of which I know that it's a 64-bit value
mskfisher
  • 3,291
  • 4
  • 35
  • 48
Stefan Gehrig
  • 82,642
  • 24
  • 155
  • 189
  • [Here](https://stackoverflow.com/questions/56786533/how-to-convert-byte-array-to-float-in-php) is how to convert byte array into float in PHP. – Syed Azhar Abbas Jun 27 '19 at 08:18

4 Answers4

7

Just looked up the code for Zend_Crypt_Math_BigInteger_Bcmath and Zend_Crypt_Math_BigInteger_Gmp which deals with this problem:

Using BCmath (Big-Endian)

This is essentially the solution posted by Chad Birch.

public static function bc_binaryToInteger($operand)
{
    $result = '0';
    while (strlen($operand)) {
        $ord = ord(substr($operand, 0, 1));
        $result = bcadd(bcmul($result, 256), $ord);
        $operand = substr($operand, 1);
    }
    return $result;
}

Using GMP (Big-Endian)

Same algorithem - just different function names.

public static function gmp_binaryToInteger($operand)
{
    $result = '0';
    while (strlen($operand)) {
        $ord = ord(substr($operand, 0, 1));
        $result = gmp_add(gmp_mul($result, 256), $ord);
        $operand = substr($operand, 1);
    }
    return gmp_strval($result);
}

Changing the algorithem to use Litte-Endian byte-order is quite simple: just read the binary data from end to start:

Using BCmath (Litte-Endian)

public static function bc_binaryToInteger($operand)
{
    // Just reverse the binray data
    $operand = strrev($operand);
    $result = '0';
    while (strlen($operand)) {
        $ord = ord(substr($operand, 0, 1));
        $result = bcadd(bcmul($result, 256), $ord);
        $operand = substr($operand, 1);
    }
    return $result;
}

Using GMP (Litte-Endian)

public static function gmp_binaryToInteger($operand)
{
    // Just reverse the binray data
    $operand = strrev($operand);
    $result = '0';
    while (strlen($operand)) {
        $ord = ord(substr($operand, 0, 1));
        $result = gmp_add(gmp_mul($result, 256), $ord);
        $operand = substr($operand, 1);
    }
    return gmp_strval($result);
}
Community
  • 1
  • 1
Stefan Gehrig
  • 82,642
  • 24
  • 155
  • 189
1

Two years late to the party, but if anyone still cares: unpack is the built-in way to go here, you can unpack it as a couple of 32-bit ints, or as a double.

Anon
  • 11
  • 1
1

This seems like a total hack, but it should do the job, assuming you have the BC Math functions that daemonmoi recommended:

$result = "0";
for ($i = strlen($serverChallenge) - 1; $i >= 0; $i--)
{
    $result = bcmul($result, 256); // shift result

    $nextByte = (string)(ord($serverChallenge[$i]));
    $result = bcadd($result, $nextByte);
}
Chad Birch
  • 73,098
  • 23
  • 151
  • 149
0

I know this is not quite the answer to the question, but check out the BC Math functions to handle big numbers.

user39113
  • 297
  • 2
  • 4
  • Actually I know the BCMath extension but these functions won't be helpful because they need the integer-value as a string - but I only have a byte-stream which must be converted into something that PHP (or BCMath or GMP) can use as a number... – Stefan Gehrig Apr 07 '09 at 14:58