Problems converting mcrypt cipher text to binary and back

For a school project I’m developing a php based steganography class. As part of it I am encrypting the message to be hidden before encoding it into an image. So this means I must convert the resulting cipher text from mcrypt into binary. My problem is that when I try converting the binary back into the cipher text the result is different from the original cipher text. (The output binary looks strange to for that matter.) I’m assuming that the problem lies with the encoding used on the cipher text and the encoding used when converting back from binary are different but I have no idea where to start to fix that. You can see a live example at dev.hersha.me/str2bin.php and my code will be posted below.

<?php

class phpSteg {

	function bin2bstr($input) {
		if (!is_string($input)) return null;
		return pack('H*', base_convert($input, 2, 16));	
	}

	function bstr2bin($input) {
		if (!is_string($input)) return null;
		$value = unpack('H*', $input);
		return base_convert($value[1], 16, 2);
	}


};

$steg = new phpSteg();

//echo $steg->bstr2bin('OMG') . "\
 <br \\>";
//echo $steg->bin2bstr('010011110100110101000111') . "\
 <br \\>";
$hash =  hash('md5',"OMGZWTF");
echo $hash . "\
 <br \\>";
$message = "OMG WTF BBQ";

$text = $message;
$key = $hash;

$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB), MCRYPT_RAND);
echo $iv . "\
 <br \\>";
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CFB, $iv);

$binenc = $steg->bstr2bin($encrypted);

$bstrenc = $steg->bin2bstr($binenc);


$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $bstrenc, MCRYPT_MODE_CFB, $iv);
echo "Cipher Text : " . $encrypted . "\
 <br \\>";

echo "Cipher Text (binary) : " . $binenc . "\
 <br \\>";

echo "Cipher Text (back from binary) : " . $bstrenc . "\
 <br \\>";

echo "Decryption : " . $decrypted; // The quick brown fox jumps over the lazy dog

?>

Start testing by encoding, and then immediately decoding the just-encoded string.

If that doesn’t work properly there’s not much point in looking further, until that side of things works as expected.

Isn’t there some trim tomfoolery required on decryption IIRC?

Well, if you have a look at the http://php.net/manual/en/function.base-convert.php you will see a large warning saying that it may lose precision.

If you look at the pack documentation page you will see that functions are provided to pack and unpack strings.


<?php 
    public function unpack_str($str, $len) { 
        $tmp_arr = unpack("c".$len."chars", $str); 
        $out_str = ""; 
        foreach($tmp_arr as $v) { 
            if($v>0) { 
                $out_str .= chr($v); 
            } 
        } 
        
        return $out_str; 
    } 
    
    public function pack_str($str, $len) {        
        $out_str = ""; 
        for($i=0; $i<$len; $i++) { 
            $out_str .= pack("c", ord(substr($str, $i, 1))); 
        } 
        return $out_str; 
    } 
?>

Hopefully these resources will be useful for you to work further from.

Thanks for the help pmw57 it was a precision issues with base_convert. I guess I should convert each character of the string to binary individually. That seems a slow and clunky way of doing it but whatever. But I don’t think that’s my only problem. If you look even though the binary of the cipher text is truncated the first few characters of the cipher text are changed from the original.

Slowly getting there got my output binary right now need to get my converstion from binary right.

My other computer (it’s a Porsche) is running SpinRite right now, so when it’s finished I’ll see if I have some good info on cryptography scripts there.

In the meantime, do you experience any conversion loss when using the pack_str and unpack_str functions?

Sigh Cant figure out how to break a long string of binary into an array of 8 bit chunks. Tried

preg_split('/[0-1]{8}/', $input, -1, PREG_SPLIT_NO_EMPTY);

but no luck. Any ideas?

I figured out the cipher inconsistencies. It was that base_convert wasn’t putting all of the leading zeros in for the special characters. using sprintf(“%08d”, $input) sorted it right out.

Changed my binary conversion function to:

 function bstr2bin($input) {
         if (!is_string($input)) return null;
         $bin = "";
         $array = preg_split('//', $input, -1, PREG_SPLIT_NO_EMPTY);
         foreach($array as $char) {
                 $hex = unpack('H*', $char);
                 echo $char . "->" . $hex[1] . "->".sprintf("%08d",base_convert($hex[1],16,2))."\
 <br />";
                 $bin .= sprintf("%08d",base_convert($hex[1], 16, 2));
         }
         //$value = unpack('H*', $input);
         return $bin; //base_convert($value[1], 16, 2);
 }

That got rid of the precision errors since its only converting one character at a time.

See [fphp]str_split/fphp. :wink:

Nice didn’t notice that one in the documentation. Man base_convert has some serious issues with leading zeros when doing these conversions. Which is completely understandable since you don’t need 0010 to get 2 all you need is 10 but its really annoying to debug.

Note to self use %02s instead of %02d with sprintf() when dealing with strings :stuck_out_tongue:

edit:
Oh also all working now to make it all a nice pretty class.
And get to work on the actually steganography part of the project.

Here’s the finished messy code if anyone is interested.

<?php

class phpSteg {

        function bin2bstr($input) {
                if (!is_string($input)) return null;
                $hex = "";
                $array = str_split($input, 8);
                //print_r ($array);
                foreach($array as $bin) {
                        echo $bin . "->".sprintf("%02s",base_convert($bin, 2, 16))."\
 <br />";
                        $string .= pack('H*', sprintf("%02s", base_convert($bin, 2, 16)));
                }
                return $string; //pack('H*', base_convert($input, 2, 16));
        }

        function bstr2bin($input) {
                if (!is_string($input)) return null;
                $bin = "";
                $array = preg_split('//', $input, -1, PREG_SPLIT_NO_EMPTY);
                foreach($array as $char) {
                        $hex = unpack('H*', $char);
                        echo $char . "->" . $hex[1] . "->".sprintf("%08s",base_convert($hex[1],16,2))."\
 <br />";
                        $bin .= sprintf("%08s",base_convert($hex[1], 16, 2));
                }
                //$value = unpack('H*', $input);
                return $bin; //base_convert($value[1], 16, 2);
        }


};


$steg = new phpSteg();

//echo $steg->bstr2bin('OMG') . "\
 <br \\>";
//echo $steg->bin2bstr('010011110100110101000111') . "\
 <br \\>";
$hash =  hash('md5',"OMGZWTF");
$message = "OMG WTF BBQ";

$text = $message;
$key = $hash;

$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB), MCRYPT_RAND);
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CFB, $iv);
$binenc = $steg->bstr2bin($encrypted);
$bstrenc = $steg->bin2bstr($binenc);
$binmsg = $steg->bstr2bin($message);
$bstrmsg = $steg->bin2bstr($binmsg);
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CFB, $iv));
$decryptedbin = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $bstrenc, MCRYPT_MODE_CFB, $iv));


echo "Message : " . $message . "\
 <br />";
echo "Simple String to Binary and Back\
 <br />";
echo "Binary Message : " . $binmsg . "\
 <br />";
echo "Back to String : " . $bstrmsg . "\
 <br />";
echo "Encryption no binary conversion\
 <br />";
echo "Key : " . $key . "\
 <br />";
echo "IV : " . $iv . "\
 <br />";
echo "Cipher Text : " . $encrypted . "\
 <br />";
echo "Decryption : " . $decrypted . "\
 <br />";
echo "Encryption with binary conversion\
 <br />";
echo "Cipher Text (binary) : " . $binenc . "\
 <br />";
echo "Cipher Text (back from binary) : " . $bstrenc . "\
 <br />";
echo "Decryption : " . $decryptedbin; // The quick brown fox jumps over the lazy dog


?>