Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

[PHP] Steganography

Junior Spellweaver
Joined
Nov 26, 2008
Messages
196
Reaction score
62
PLEASE NOTE: Due to laziness, the class isn't that clean and it could of been coded a lot better.

This is a class that uses the steganography technique to hide encrypted data within a bitmap image (.BMP).

Th3 class can hide the data very well in 24 or 32 bit RGB images.

The class could be used to hide the data in indexed color images, for instance of 256 colors, but that would require adding a few functions to deal with the modifications to the color palette.

The class implements 4 levels of bit stream encoding. Each level uses an increasing number of bits per each byte in the RGB pixel table. Therefore, the higher level of encoding will hold more bytes of data in the bitmap image.

Class:

PHP:
<?php

class Steganography 
{
  var $m_errMsg;
  var $m_dataCarrier;
  var $m_data;
  var $m_key;
  var $m_outFile;

  function __construct() 
  {
    $this->m_errMsg = "";
    $this->m_dataCarrier = "";
    $this->m_data = "";
    $this->m_key = "ExiledHeroBmpCrypt";
    $this->m_outFile = "";
  }

  function Encrypt( $bmpFile, $indata, $key, $outFile, $level = 1)
  {
    if ( !file_exists( $bmpFile ) ) 
    {
      $this->m_errMsg = "The bitmap file '" . $bmpFile . "' was not found!";
      return false;
    }

    if ( $indata == "" ) 
    {
      $this->m_errMsg = "No data to encrypt!";
      return false;
    }

    if ( $outFile == "" ) 
    {
      $this->m_errMsg = "The output file was not specified!";
      return false;
    }

    $this->m_dataCarrier = $bmpFile;
    $this->m_data = $indata;

    if ( $key != "" ) $this->m_key = $key;
    $this->m_outFile = $outFile;

    if ( $level == 1 )
      return $this->_encrypt_1();
    else if ( $level == 2 )
      return $this->_encrypt_2();
    else if ( $level == 3 )
      return $this->_encrypt_3();
    else if ( $level == 4 )
      return $this->_encrypt_4();
    else 
    {
      $this->m_errMsg = "The encryption level is out of range!";
      return false;
    }

  }

  function Decrypt( $bmpFile, $key, $outFile = "" ) 
  {

    if ( !file_exists( $bmpFile ) ) 
    {
      $this->m_errMsg = "The bitmap file '" . $bmpFile . "' was not found!";
      return false;
    }

    if ( $key != "" ) $this->m_key = $key;
    $this->m_outFile = $outFile;

    $this->m_dataCarrier = $bmpFile;

    $this->m_data = file_get_contents( $this->m_dataCarrier );

    if ( !$this->_get_encryption_info( $level, $cryptKey, $offset, $datSize ) ) 
      return false;

    $nbytes = ( $level == 1 ) ? 8 : ( ( $level == 2 ) ? 4 : ( ( $level == 3 ) ? 3 : 2 ) );

    if ( $offset + $datSize * $nbytes > strlen( $this->m_data ) ) 
    {
      $this->m_errMsg = "The bitmap file '" . $this->m_dataCarrier . "' contains no encrypted data!" . $level . ", $nbytes";
      return false;
    }

    $data = "";    

    for ( $i = 0; $i < $datSize; $i++ )
      $data = chr( 0 );

    for ( $i = $offset, $j = 0; $i < $offset + $datSize * $nbytes; $i += $nbytes, $j++ ) 
    {
      if ( $level == 1 ) 
      {
        for ( $k = 0, $n = 7; $k < 8; $k++, $n-- )
          $data[ $j ] = chr( ord( $data[ $j ] ) | ( ( ord( $this->m_data[ $i + $k ] ) & 1 ) << $n ) );
      }
      else if ( $level == 2 )
      {
        for ( $k = 0, $n = 6; $k < 4; $k++, $n -= 2 )
          $data[ $j ] = chr( ord( $data[ $j ] ) | ( ( ord( $this->m_data[ $i + $k ] ) & 3 ) << $n ) );
      }
      else if ( $level == 3 ) 
      {
        for ( $k = 0; $k < 3; $k++ ) 
        {
          if ( $k == 0 )
            $data[ $j ] = chr( ord( $data[ $j ] ) | ( ( ord( $this->m_data[ $i ] ) & 7 ) << 5 ) );
          else if ( $k == 1 )
            $data[ $j ] = chr( ord( $data[ $j ] ) | ( ( ord( $this->m_data[ $i + 1 ] ) & 7 ) << 2 ) );
          else
            $data[ $j ] = chr( ord( $data[ $j ] ) | ( ord( $this->m_data[ $i + 2 ] ) & 3 ) );
        }
      }
      else if ( $level == 4 ) 
      {
        for ( $k = 0; $k < 2; $k++ ) 
        { 
          if ( $k == 0 )
            $data[ $j ] = chr( ord( $data[ $j ] ) | ( ( ord( $this->m_data[ $i ] ) & 15 ) << 4 ) );
          else
            $data[ $j ] = chr( ord( $data[ $j ] ) | ( ( ord( $this->m_data[ $i + 1 ] ) & 15 ) );
        }
      }
    }

    for ( $i = 0, $j = 0; $i < $datSize; $i++, $j = ( $j + 1 ) % 32 )
      $data[ $i ] = chr( ord( $data[ $i ] ) ^ ord( $cryptKey[ $j ] ) );

    if ( $this->m_outFile != "" ) 
    (
      $fp = fopen( $this->m_outFile, "wb" );
      fwrite( $fp, $data, $datSize );
      fclose( $fp );
      return true;
    }

    return $data;
  }

  function GetErrorMessage()
  {
    return "ERROR: " . $this->m_errMsg;
  }

  function _encrypt_1() 
  {
    $bmpSize = filesize( $this->m_dataCarrier );
    $datSize = strlen( $this->m_data );
    $totalSize = ( 12 + $datSize ) * 8;
    
    if ( ( $bmpSize - 55 ) < $totalSize ) 
    {      
      $this->m_errMsg = "The bitmap file '" . $bmpFile . "' is too small to carry the input data!";
      return false;
    }

    $cryptKey = md5( $this->m_key );

    $cryptData = sprintf( "SCC1%08x", $datSize );

    $bmpBuffer = file_get_contents( $this->m_dataCarrier );

    for ( $i = 0, $j = 0; $i < $datSize; $i++, $j = ( $j + 1 ) % 32 )     
      $cryptData . = chr( ord( $this->m_data[ $i ] ) ^ ord( $cryptKey[ $j ] ) );

    for ( $i = 0, $j = 55; $i < strlen( $cryptData ); $i++, $j += 8 ) 
    { 
      $temp = sprintf( "%08s", decbin( ord( $cryptData[ $i ] ) ) );
      
      for ( $k = 0; $k < 8; $k++ ) 
      {
        $bmpBuffer[ $k + $j ] = chr( ord( $bmpBuffer[ $k + $j ] ) & 254 );
        if ( $temp[ $k ] == '1' ) $bmpBuffer[ $k + $j ] = chr( ord( $bmpBuffer[ $k + $j ] ) + 1 );
      }
    }

    $fp = fopen($ this->m_outFile, "wb" );
    fwrite( $fp, $bmpBuffer );
    fclose( $fp );

    return true;
  }

  function _encrypt_2() 
  {
    $bmpSize = filesize( $this->m_dataCarrier );
    $datSize = strlen( $this->m_data );
    $totalSize = ( 12 + $datSize ) * 4;
    if ( ( $bmpSize - 55 ) < $totalSize ) 
    {
      $this->m_errMsg = "The bitmap file '" . $this->m_dataCarrier . "' is too small to carry the input data!";
      return false;
    }

    $cryptKey = md5( md5( $this->m_key ) );

    $cryptData = sprintf( "SCC2%08x", $datSize );

    $bmpBuffer = file_get_contents( $this->m_dataCarrier );

    for ( $i = 0, $j = 0; $i < $datSize; $i++, $j = ( $j + 1 ) % 32 ) 
      $cryptData .= chr( ord( $this->m_data[ $i ] ) ^ ord( $cryptKey[ $j ] ) );

    for ( $i = 0, $j = 55; $i < strlen( $cryptData ); $i++, $j += 4 ) 
    { 
      $temp = sprintf( "%08s", decbin( ord( $cryptData[ $i ] ) ) );  
      for ( $k = 0; $k < 4; $k++ ) 
      {
        $bmpBuffer[ $k + $j ] = chr( ord( $bmpBuffer[ $k + $j ] ) & 252 );
        $n = ( $temp[ $k * 2 ] == '1' ) ? 2 : 0;
        $n += ( $temp[ $k * 2 + 1 ] == '1' ) ? 1 : 0;
        if ( $n != 0 ) $bmpBuffer[ $k + $j ] = chr( ord( $bmpBuffer[ $k + $j ] ) + $n ); 
      }
    }

    $fp = fopen( $this->m_outFile, "wb" );
    fwrite( $fp, $bmpBuffer );
    fclose( $fp );

    return true;
  }

  function _encrypt_3() 
  {
    $bmpSize = filesize( $this->m_dataCarrier );
    $datSize = strlen( $this->m_data );
    $totalSize = ( 12 + $datSize ) * 3;
  
    if ( ( $bmpSize - 55 ) < $totalSize ) 
    {
      $this->m_errMsg = "The bitmap file '" . $this->m_dataCarrier . "' is too small to carry the input data!";
      return false;
    }

    $cryptKey = md5( md5( md5( $this->m_key ) ) );

    $cryptData = sprintf( "SCC3%08x", $datSize );  

    $bmpBuffer = file_get_contents( $this->m_dataCarrier );

    for ($i = 0, $j = 0; $i < $datSize; $i++, $j = ( $j + 1 ) % 32 )
      $cryptData .= chr( ord( $this->m_data[ $i ] ) ^ ord( $cryptKey[ $j ] ) );

    for ( $i = 0, $j = 55; $i < strlen( $cryptData ); $i++, $j += 3 ) 
    {
      $temp = sprintf( "%08s", decbin( ord( $cryptData[ $i ] ) ) );
      
      for ( $k = 0; $k < 3; $k++ ) 
      {
        if ( $k != 2 ) 
        {
          $bmpBuffer[ $k + $j ] = chr( ord( $bmpBuffer[ $k + $j ] ) & 248 );
          $n = ( $temp[ $k * 3 ] == '1' ) ? 4 : 0;
          $n += ( $temp[ $k * 3 + 1 ] ==  '1' ) ? 2 : 0;
          $n += ( $temp[ $k * 3 + 2 ] == '1') ? 1 : 0;

          if ( $n != 0 ) $bmpBuffer[ $k + $j ] = chr( ord( $bmpBuffer[ $k + $j ] ) + $n ); 
        }
        else 
        {
          $bmpBuffer[ $k + $j ] = chr( ord( $bmpBuffer[ $k + $j ] ) & 252 );  
          $n = ( $temp[ $k * 3 ] == '1' ) ? 2 : 0;
          $n += ( $temp[ $k * 3 + 1 ] == '1' ) ? 1 : 0;
          if ( $n != 0 ) $bmpBuffer[ $k + $j ] = chr( ord( $bmpBuffer[ $k + $j ] ) + $n );
        }
      }
    }

    $fp = fopen( $this->m_outFile, "wb" );
    fwrite( $fp, $bmpBuffer );
    fclose( $fp ); 

    return true;
  }

  function _encrypt_4() 
  {

    $bmpSize = filesize( $this->m_dataCarrier );
    $datSize = strlen( $this->m_data );
    $totalSize = ( 12 + $datSize ) * 2;
    
    if ( ( $bmpSize - 55 ) < $totalSize ) 
    { 
      $this->m_errMsg = "The bitmap file '" . $this->m_dataCarrier . "' is too small to carry the input data!";
      return false;
    }

    $cryptKey = md5( md5( md5( md5( $this->m_key ) ) ) );

    $cryptData = sprintf( "SCC4%08x", $datSize );

    $bmpBuffer = file_get_contents( $this->m_dataCarrier );

    for ( $i = 0, $j = 0; $i < $datSize; $i++, $j = ( $j + 1 ) % 32 ) 
      $cryptData .= chr( ord( $this->m_data[ $i ] ) ^ ord( $cryptKey[ $j ] ) );

    for ( $i = 0, $j = 55; $i < strlen( $cryptData ); $i++, $j += 2 ) 
    {
      $temp = sprintf( "%08s", decbin( ord( $cryptData[ $i ] ) ) );
      
      for ( $k = 0; $k < 2; $k++ ) 
      {
        $bmpBuffer[ $k + $j ] = chr( ord( $bmpBuffer[ $k + $j ] ) & 240 );
        $n = ( $temp[ $k * 4 ] == '1' ) ? 8 : 0;
        $n += ( $temp[ $k * 4 + 1] == '1' ) ? 4 : 0;
        $n += ( $temp[ $k * 4 + 2 ] == '1' ) ? 2 : 0;
        $n += ( $temp[ $k * 4 + 3] == '1' ) ? 1 : 0;
        if ( $n != 0 ) $bmpBuffer[ $k + $j ] = chr( ord( $bmpBuffer[ $k + $j ] ) + $n );
      }
    }

    $fp = fopen( $this->m_outFile, "wb" );
    fwrite( $fp, $bmpBuffer );
    fclose( $fp );

    return true;
  }

  function _get_encryption_info( &$level, &$cryptKey, &$offset, &$datSize ) 
  {
    $cryptKey = md5( $this->m_key );

    $cryptHeader = "";
    for ( $i = 0; $i < 12; $i++ )
      $cryptHeader = chr( 0 );

    for ( $i = 55, $j = 7, $k = 0; $i < 151; $i++ ) 
    {
      $cryptHeader[ $k ] = chr( ord( $cryptHeader[ $k ] ) | ( ( ord( $this->m_data[ $i ] ) & 1 ) << $j ) );
      $j--;
      
      if ( $j < 0 ) 
      {
        $j = 7;
        $k++;
      }
    }

    if ( !strcmp( substr( $cryptHeader, 0, 4 ), "SCC1" ) )
    {
      sscanf( substr( $cryptHeader, 4, 8 ), "%x", $datSize );
      $level = 1;
      $offset = 151;
      return true;
    }

    $cryptKey = md5( $cryptKey );

    $cryptHeader = "";

    for ( $i = 0; $i < 12; $i++ )
      $cryptHeader = chr( 0 );

    for ( $i = 55, $j = 6, $k = 0; $i < 103; $i++ ) 
    {
      $cryptHeader[ $k ] = chr( ord( $cryptHeader[ $k ] ) | ( ( ord( $this->m_data[ $i ] ) & 3 ) << $j ) );
      $j -= 2;
      
      if ( $j < 0 ) 
      {
        $j = 6;
        $k++;
      }
    }

    if ( !strcmp( substr( $cryptHeader, 0, 4 ), "SCC2" ) ) 
    {
      sscanf( substr( $cryptHeader, 4, 8 ), "%x", $datSize );
      $level = 2;
      $offset = 103;
      return true;
    }

    $cryptKey = md5( $cryptKey );

    $cryptHeader = "";

    for ( $i = 0; $i < 12; $i++ )
      $cryptHeader = chr( 0 );

    for ( $i = 55, $j = 0; $i < 91; $i += 3, $j++ ) 
    {
      for ( $k = 0; $k < 3; $k++ ) 
      {
        if ( $k == 0 )
          $cryptHeader[ $j ] = chr( ord( $cryptHeader[ $j ] ) | ( ( ord( $this->m_data[ $i ] ) & 7 ) << 5 ) );
        else if ( $k == 1 )
          $cryptHeader[ $j ] = chr( ord( $cryptHeader[ $j ] ) | ( ( ord( $this->m_data[ $i + 1 ] ) & 7 ) << 2 ) );
        else
          $cryptHeader[ $j ] = chr( ord( $cryptHeader[ $j ] ) | ( ord( $this->m_data[ $i + 2 ] ) & 3 ) );
      }
    }

    if ( !strcmp( substr( $cryptHeader, 0, 4 ), "SCC3" ) ) 
    {
      sscanf( substr( $cryptHeader, 4, 8 ), "%x", $datSize );
      $level = 3;
      $offset = 91;
      return true;
    }

    $cryptKey = md5( $cryptKey );

    $cryptHeader = "";

    for ( $i = 0; $i < 12; $i++ )
      $cryptHeader = chr( 0 );

    for ( $i = 55, $j = 0; $i < 79; $i += 2, $j++ ) 
    {
      for ( $k = 0; $k < 2; $k++ ) 
      {
        if ( $k == 0 )
          $cryptHeader[ $j ] = chr( ord($cryptHeader[ $j ] ) | ( ( ord( $this->m_data[ $i ] ) & 15 ) << 4 ) );
        else
          $cryptHeader[ $j ] = chr( ord( $cryptHeader[ $j ] ) | ( ord( $this->m_data[ $i + 1 ] ) & 15 ) );
        }
      }

    if ( !strcmp( substr( $cryptHeader, 0, 4 ), "SCC4" ) ) 
    { 
      sscanf( substr( $cryptHeader, 4, 8 ), "%x", $datSize );
      $level = 4;
      $offset = 79;
      return true;
    }

    $this->m_errMsg = "The bitmap file '" . $this->m_dataCarrier . "' contains no encrypted data!" . $cryptHeader;
    return false;
  }

}

/* EOF */

Command Line example:

PHP:
<?php

include("steganography.php");

$method = "";

if ( $argc > 1 )
{
  if ( strcmp( $argv[ 1 ], "-e" ) == 0 ) $method = " Encrypt ";
  else if ( strcmp( $argv[ 1 ], "-d" ) == 0 ) $method = " Decrypt ";
}

if ( $method == "Encrypt" && $argc >= 4 ) 
{
  if ( !file_exists( $argv[ 3 ] ) ) 
  {
    echo "File '" . $argv[ 3 ] . "' was not found!\n";
    exit();
  }
    
  $bmpEnc = new BmpCrypt();
  $return = $bmpEnc->Encrypt( $argv[ 2 ], file_get_contents( $argv[ 3 ] ), ( $argc > 4 ) ? $argv[ 5 ] : "", $argv[ 4 ], ( $argc > 5 ) ? $argv[ 6 ] : 1 );
  
  if ( $return == false ) echo $bmpEnc->GetErrorMessage() . "\n";
}
  
else if ( $method == "Decrypt" && $argc >= 3 ) 
{
  $bmpEnc = new Steganography();
  $return = $bmpEnc->Decrypt($argv[2], ($argc > 3) ? $argv[4] : "", $argv[3]);
    
  if ( $return == false ) echo $bmpEnc->GetErrorMessage() . "\n";
}
else 
{
  echo "USAGE:\n";
  echo "   To encrypt data and hide it in a bitmap file:\n";
  echo "      php -f Steg_CmdLine_Example.php -e bitmap_file data_file output_file [key] [level]\n";
  echo "   To decrypt data and recover it from a bitmap file:\n";
  echo "      php -f Steg_CmdLine_Example.php -d bitmap_file output_file [key]\n";
}

/* EOF */

I'll edit this post once I done the webpage example.
 
Last edited:
Vous Pas Reel
Loyal Member
Joined
Nov 6, 2007
Messages
880
Reaction score
11
I think this is simply genius!
I do like your work here sire.
 
Junior Spellweaver
Joined
Nov 26, 2008
Messages
196
Reaction score
62
Why thank you.

Still haven't had time to do the web based example but I'll get around to it. I give credits to Burn Notice for the idea.

I also have written a script that simulates router decision using neural networks.
 
Newbie Spellweaver
Joined
Jun 27, 2005
Messages
11
Reaction score
0
lol nice find...its the same coding with different class name only...
 
Initiate Mage
Joined
Jul 13, 2014
Messages
1
Reaction score
0
Here is Chao-Chyuan Shih, the original author of BmpCrypt and TxtCrypt...
 
Back
Top