<?php
header("HTTP/1.1 301 Moved Permanently");
header("Location: /image-steganography/");
exit;
?>
<html>
  <head>
    <link rel="stylesheet" href="/style.css">
    <title>Image steganography</title>
    <style type="text/css">
      p.error { color: #ff0000; }
      p.familiar { font-size: 0.8em; }
    </style>
  </head>
  <body>
<?php echo file_get_contents("/home/james/www/page_header.html"); ?>
    <h1>Image steganography</h1>
<?php session_start();
   //$dir MUST end in the path separator
   function gen_filename($dir, $extension) {
     do {
       $path = $dir.time()."_".rand().$extension;
     } while(file_exists($path));
     return $path;
   }

   function file_ext($file) {
      return substr($file, strrpos($file, '.'));
   }


  if(isset($_POST['action'])) {
    $error = "";
        if($_POST['xor'] == "") $xor = "";
        else $xor = " xor";
    switch($_POST['action']) {
      case "hide":
        //Check that the cover image has been uploaded
        if(is_uploaded_file($_FILES['cover']['tmp_name'])) {
          $cover = gen_filename("/home/james/www/images/", file_ext($_FILES['cover']['name']));
          move_uploaded_file($_FILES['cover']['tmp_name'], $cover);
        } else {
          $error .= "Cover image was not uploaded correctly<br>";
        }
        //Check that the secret image has been uploaded
        if(is_uploaded_file($_FILES['secret']['tmp_name'])) {
          $secret = gen_filename("/home/james/www/images/", file_ext($_FILES['secret']['name']));
          move_uploaded_file($_FILES['secret']['tmp_name'], $secret);
        } else {
          $error .= "Secret image was not uploaded correctly<br>";
        }
        //Check that hidbits is valid
        $hidbits = intval($_POST['hidbits']);
        if(($hidbits < 1) || ($hidbits > 7)) {
          $error .= "Hidden bits value was out of range. Should be 1 to 7.<br>";
        }
        //Generate output path
        $output_path = gen_filename("/home/james/www/images/", ".png");
        $_SESSION['output_path'] = $output_path;
        //Call hideimage with required stuff
        if($error != "") break;
        $ret = shell_exec("/home/james/bin/hideimage ".escapeshellarg($cover)." ".escapeshellarg($secret)." ".escapeshellarg($output_path)." ".escapeshellarg($_POST['hidbits']).$xor);
        if(!file_exists($output_path)) {
          echo "<p class=\"error\">An error occured which meant that the image was not generated.</p>";
        } else {
          echo "Click image for full-size copy.<br>";
          echo "<a href=\"/tools/hideimageoutput.php?thumb=0\"><img width=200px src=\"/tools/hideimageoutput.php?thumb=1\" alt=\"Generated Image\"></a><br>";
        }
        break;
      case "unhide":
        //Check that image was uploaded
        if(is_uploaded_file($_FILES['image']['tmp_name'])) {
          $image = gen_filename("/home/james/www/images/", file_ext($_FILES['image']['name']));
          move_uploaded_file($_FILES['image']['tmp_name'], $image);
        } else {
          $error .= "Image was not uploaded correctly<br>";
        }
        //Check that hidbits is valid
        $hidbits = intval($_POST['hidbits']);
        if(($hidbits < 1) || ($hidbits > 7)) {
          $error .= "Hidden bits value was out of range. Should be in 1 to 7 inclusive.<br>";
        }
        //Generate output path
        $output_path = gen_filename("/home/james/www/images/", ".png");
        $_SESSION['output_path'] = $output_path;
        //Call unhideimage with required stuff
        if($error != "") break;
        $ret = shell_exec("/home/james/bin/unhideimage ".escapeshellarg($image)." ".escapeshellarg($output_path)." ".escapeshellarg($_POST['hidbits']).$xor);
        if(!file_exists($output_path)) {
          echo "<p class=\"error\">An error occured which meant that the image was not generated.</p>";
        } else {
          echo "Click image for full-size copy.<br>";
          echo "<a href=\"/tools/hideimageoutput.php?thumb=0\"><img width=200px src=\"/tools/hideimageoutput.php?thumb=1\" alt=\"Generated Image\"></a><br>";
        }
        break;
    }
  }
  if($error != "") echo "<p class=\"error\">$error</p>";
?>
On this page you may upload an image to be hidden inside another image by my <a href="/software/hideimage.tar.gz">hideimage</a> program. Note that if you want to be secure, do not use this page. Your image will be sent in clear through the internet to my server. Anyone in between you and me (including me) can see the image. There is also an <b>extremely</b> small chance that my script can get confused and show somebody else your image. This is so unlikely that it's hardly worth mentioning, I'm just saying that if you want secure, don't use this page.<br><br>
<b>Update:</b> I now have a self-signed SSL certificate. Visit this page over <a href="https://<?php echo $_SERVER['HTTP_HOST'] ?>/tools/hideimage.php">SSL</a> if you want encryption, but be warned that my certificate is not signed by a root CA (so there is no way to be sure that there is no man-in-the-middle), and that I can still see your images, by necessity, as they are stored temporarily on the server.
<br><br>
The cover image and secret image parameters are self explanatory. Hidden bits is the number of bits to the byte of the secret image to use. The most significant bits will be chosen. The least significant bits of the cover image will be replaced by these. The XOR parameter specifies whether or not the least significant bits of the resulting image should be XOR'd by the most significant bits.<br>
<ul class="bullets">
Supported image types are:
<li><strike>JPEG</strike> - the Allegro JPEG library seems to segfault on the 64-bit server. No more JPEG.</li>
<li>PNG</li>
<li>BMP</li>
<li>TGA</li>
<li>LBM</li>
<li>PCX</li>
If you get an error about not being able to load, it is likely that your image is not in one of the above formats.
</ul><br>
The output image will always be a PNG, and will be deleted at 3am, 6am, 9am, midday, 3pm, 6pm, 9pm, or midnight - whichever comes first. The image should only be accessible by your session, and cookies must be enabled in order for you to get the output.<br><br>
<b>Hide image:</b>
<form method="post" action="/tools/hideimage.php" enctype="multipart/form-data">
<table>
<tr><td>Cover image:</td><td><input type="file" name="cover"></td></tr>
<tr><td>Secret image:</td><td><input type="file" name="secret"></td></tr>
<tr><td>Hidden bits:
  <select name="hidbits">
    <option>1</option>
    <option>2</option>
    <option>3</option>
    <option>4</option>
    <option>5</option>
    <option>6</option>
    <option>7</option>
  </select></td><td>
  <input type="checkbox" name="xor" value="xor">XOR last bits of pixel by first ones</td></tr>
<tr><td colspan=2><input type="submit" value="Go!"><input type="hidden" name="action" value="hide"></td></tr>
</table>
</form><br>
<p class="familiar">To do the example of the tree and the cat from <a href="http://en.wikipedia.org/wiki/Steganography#Digital_steganography">Wikipedia</a>, download the tree image, select it in the file box, select 2 hidden bits, and ensure that XOR is not checked. Then click 'Go!' and you will be presented with the cat.</p>
<b>Unhide image:</b>
<form method="post" action="/tools/hideimage.php" enctype="multipart/form-data">
<table>
<tr><td>Image:</td><td><input type="file" name="image"></td></tr>
<tr><td>Hidden bits:
  <select name="hidbits">
    <option>1</option>
    <option>2</option>
    <option>3</option>
    <option>4</option>
    <option>5</option>
    <option>6</option>
    <option>7</option>
  </select></td><td>
  <input type="checkbox" name="xor" value="xor">XOR last bits of pixel by first ones</td></tr>
<tr><td colspan=2><input type="submit" value="Go!"><input type="hidden" name="action" value="unhide"></td></tr>
</table>
</form>
<?php echo file_get_contents("/home/james/www/page_footer.html"); ?>
</body>
</html>
