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
1
  • Here is how to convert byte array into float in PHP. Commented Jun 27, 2019 at 8:18

4 Answers 4

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);
}
Sign up to request clarification or add additional context in comments.

Comments

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);
}

3 Comments

Actually it really looks a little bit ugly, but it seems to be a viable solution.
Removed up-vote because the code is using Big-Endian byte-order. Still accepting the answer because it led me the right way.
Whoops, that was dumb of me, I'll switch it around. Glad it helped anyway.
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.

Comments

0

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

1 Comment

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...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.