views:

93

answers:

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.

A: 
$hashsalt8 = trim($hashsalt8, "\0");
robbrit
Oops, didn't realize there were "garbage" bytes. Maybe try something like explode()?
robbrit
This will only work if `\0` is the *last* character of the string — OP states that it may be followed by garbage bytes, and in that case `trim` won't do anything.
You
Thanks for the quick reply, but that is only going to remove any \0 chars isn't it? I need to also remove all the "garbage" padding chars to the right of the \0.
winwaed
+6  A: 

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
Note that the third parameter is only available in PHP 5.3+.
BoltClock
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
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
@winwaed: Added a less elegant solution for versions <5.3.0
You
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
+1  A: 

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
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
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
+1  A: 

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