4

PHP is one of those languages I use periodically, but usually have to dust the cobwebs off when I start using it again. The same applies this week whilst I port some C code to PHP. This uses a lot of AES encryption and SHA256 hashing - all working fine so far. However, decrypted strings come out in "C" form - i.e. terminated with a zero byte followed by "garbage" padding bytes.

I currently "trim" these C-style strings to PHP form with the following:

$iv = strpos( $hashsalt8, "\0");
if ($iv)
   $hashsalt8 = substr( $hashsalt8, 0, $iv );

Seems long-winded and that there should be a one line function call instead, but I can't find it?

Note: Although in this case the "hash salt" name implies I might know the length of the original string, this is unknown in the general case. Clearly a one line solution is available using substr() when the length is known a priori.

winwaed
  • 7,645
  • 6
  • 36
  • 81

3 Answers3

6

Use strstr:

$hashsalt8 = strstr($hashsalt8, "\0", TRUE);

An uglier solution for versions less than 5.3.0 (where the third parameter isn't available) uses the strrev, substr and strrchr functions instead:

$hashsalt8 = strrev(substr(strrchr(strrev($hashsalt8), "\0"), 1));
You
  • 22,800
  • 3
  • 51
  • 64
  • 3
    Note that the third parameter is only available in PHP 5.3+. – BoltClock Oct 27 '10 at 17:51
  • Ah that explains it: I'm getting a "Wrong parameter count" error, but running with PHP 5.1.6. If it was my own server I'd probably override the supplied PHP, but it isn't, so I'm not going to try. – winwaed Oct 27 '10 at 18:04
  • This looks like it is the answer for people using later versions of PHP. If nothing else is forthcoming that applies to PHP 5.1.6, I'll mark this as the answer tomorrow. – winwaed Oct 27 '10 at 18:06
  • 1
    @winwaed: Added a less elegant solution for versions <5.3.0 – You Oct 27 '10 at 18:08
  • 1
    Yes, not as elegant. I think I'll stick with what I have, recognizing your original strstr( ) approach is the best for later versions of PHP. I'll mark it as the answer. – winwaed Oct 27 '10 at 19:07
1

There should never need to be more than 32 bytes of padding right? (from your comment here)

You might be able to do something like this:

preg_replace('/\x00.{0,32}$/', "", $hashsalt8);

Note the single quotes instead of the doubles, if you use the double quotes the \x00 seems to break preg :)

gnarf
  • 105,192
  • 25
  • 127
  • 161
  • Looks to be 32 bytes: currently have 15 bytes of junk in the first instance. Interesting approach, but simplicity is perhaps a subjective thing (I tend not to like regexes for simple problems). – winwaed Oct 27 '10 at 19:06
  • You *can* use double quotes, just escape the backslash so you get `\\x00` and it won't be interpreted by PHP as a null byte, but literally `\x00`. – BoltClock Oct 29 '10 at 17:28
1

The strtok function will do it in one pass rather than two:

$hashsalt8 = strtok($hashsalt8, "\0");

Since PHP 4.1.0, however, strtok will not return an empty string if the input string begins with a zero byte. You could do the following to handle that case:

if ($hashsalt8[0] == "\0") {
  $hashsalt8 = '';
}
else {
  $hashsalt8 = strtok($hashsalt8, "\0");
}

Note that an input string beginning with a zero byte also exposes a bug in your current code. In that case, strpos will return 0 and if ($iv) will fail.

You should use the !== operator to differentiate between 0 and false:

$iv = strpos($hashsalt8, "\0");
if ($iv !== false) {
   $hashsalt8 = substr($hashsalt8, 0, $iv);
}
  • Thanks! Yes that would be "simple". Thanks also for the note about the !== operator. I don't think this situation occurs for my specific code but it is clearly the right thing to do for the general case (or even safe programming in general) – winwaed Oct 28 '10 at 13:04