Created
March 26, 2013 07:51
-
-
Save Nevon/5243765 to your computer and use it in GitHub Desktop.
Updated version of Stegger, a library for doing simple image steganography.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
//+----------------------------------------------------------------------+ | |
//| Stegger v0.6 | | |
//+----------------------------------------------------------------------+ | |
//| Copyright (c) 2006 Warren Smith ( smythinc 'at' gmail 'dot' com ) | | |
//+----------------------------------------------------------------------+ | |
//| This library is free software; you can redistribute it and/or modify | | |
//| it under the terms of the GNU Lesser General Public License as | | |
//| published by the Free Software Foundation; either version 2.1 of the | | |
//| License, or (at your option) any later version. | | |
//| | | |
//| This library is distributed in the hope that it will be useful, but | | |
//| WITHOUT ANY WARRANTY; without even the implied warranty of | | |
//| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | | |
//| Lesser General Public License for more details. | | |
//| | | |
//| You should have received a copy of the GNU Lesser General Public | | |
//| License along with this library; if not, write to the Free Software | | |
//| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | | |
//| USA | | |
//+----------------------------------------------------------------------+ | |
//| Simple is good. | | |
//+----------------------------------------------------------------------+ | |
// | |
/* | |
+----------------------------------------------------------------------+ | |
| Package: Stegger v0.6 | | |
| Class : Stegger | | |
| Created: 03/08/2006 | | |
| Updated: 13/05/2008 | | |
+----------------------------------------------------------------------+ | |
*/ | |
/*-------------*/ | |
/* C O N F I G */ | |
/*-------------*/ | |
// This is the public key (the one you give out) to encrypt or decrypt data with | |
define('STEGGER_PUB_KEY', 'Where will the children play?'); | |
/*---------------*/ | |
/* D E F I N E S */ | |
/*---------------*/ | |
// | |
/*-----------*/ | |
/* C L A S S */ | |
/*-----------*/ | |
class Stegger { | |
/*-------------------*/ | |
/* V A R I A B L E S */ | |
/*-------------------*/ | |
// Public Properties | |
/** | |
* boolean | |
* | |
* A flag to determine if we should be verbose with output or not | |
*/ | |
var $Verbose = TRUE; | |
// Private Properties | |
/** | |
* boolean | |
* | |
* A flag to determine if we are using a command line interface or not | |
*/ | |
var $CLI = FALSE; | |
// Private Properties | |
/** | |
* object | |
* | |
* This is an object representing the image | |
*/ | |
var $Image; | |
/** | |
* object | |
* | |
* This is an object representing the main bit stream | |
*/ | |
var $BitStream; | |
/** | |
* string | |
* | |
* This is a unique boundry made up of 1's and 0's | |
*/ | |
var $BitBoundry; | |
/** | |
* array | |
* | |
* This is the secret data we are going to encode or have decoded | |
*/ | |
var $RawData = array(); | |
/*-------------------*/ | |
/* F U N C T I O N S */ | |
/*-------------------*/ | |
/* | |
+------------------------------------------------------------------+ | |
| Constructor | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function Stegger(){ | |
// Run forever | |
set_time_limit(0); | |
// Setup the environment | |
$this->SetEnvironment(); | |
// Create the bit stream object | |
$this->BitStream = new BitStream(); | |
} | |
// Public API Methods | |
/* | |
+------------------------------------------------------------------+ | |
| Encodes the $secretData into an $imageFile and encrypt with $key | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function Put($secretData, $imageFile, $key = '', $outputFile = ''){ | |
// Get the start time | |
$StartTime = microtime(TRUE); | |
// Flush any previous bit streams | |
$this->BitStream->FlushStream(); | |
// Tell the user we are loading the image | |
$this->Info('Loading image..'); | |
// Attempt to load the image | |
$this->Image = new Image($imageFile); | |
// If we don't have an image | |
if ($this->Image->EOF()){ | |
// Tell the user the problem | |
$this->FatalError('Could not load the supplied image'); | |
} else { | |
// Tell the user what we are doing | |
$this->Info('Loading data..'); | |
// If we can't load the data they provided | |
if (!$this->Input($secretData)){ | |
// Meh, I hate all this usability stuff | |
$this->FatalError('Could not load the supplied data'); | |
} else { | |
// Tell the user what we are doing | |
$this->Info('Encrypting data..'); | |
// If we can't turn the data into an encrypted string | |
if (!$this->RawToString($key)){ | |
// Tell the user we couldn't encrypt the data | |
$this->FatalError('Could not encrypt the loaded data'); | |
} else { | |
// Tell the user what we are doing | |
$this->Info('Encoding data..'); | |
// If we can't encode the data | |
if (!$this->StringToStream()){ | |
// Tell the user about the error | |
$this->FatalError('Could not encode the loaded data'); | |
} else { | |
// Tell the user what the next step is | |
$this->Info('Encoding image..'); | |
// If we can't encode the image | |
if (!$this->StreamToPixels()){ | |
// Tell the user there was a problem encoding the image | |
$this->FatalError('Could not encode the image'); | |
} else { | |
// Tell the user what we are doing now | |
$this->Info('Saving image..'); | |
// Output the image | |
$this->Image->Output($outputFile); | |
// As the kids say, wewt | |
$this->Success('Done in '.round(microtime(TRUE) - $StartTime).' seconds'); | |
} | |
} | |
} | |
} | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will decode data from an image | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function Get($imageFile, $key = '', $outputPath = ''){ | |
// Get the start time | |
$StartTime = microtime(TRUE); | |
// Flush any previous bit streams | |
$this->BitStream->FlushStream(); | |
// Tell the user we are loading the image | |
$this->Info('Loading image..'); | |
// Attempt to load the image | |
$this->Image = new Image($imageFile); | |
// If we don't have an image | |
if ($this->Image->EOF()){ | |
// Tell the user the problem | |
$this->FatalError('Could not load the supplied image'); | |
} else { | |
// Tell the user we are about to read the image | |
$this->Info('Reading image..'); | |
// Read the pixels into a bit stream | |
$this->PixelsToStream(); | |
// If we don't have a bit stream | |
if ($this->BitStream->EOF()){ | |
// Tell the user about the problems | |
$this->FatalError('No hidden data found in the image'); | |
} else { | |
// Tell the user we are decoding the data | |
$this->Info('Decoding data..'); | |
// If we can't decode the bit stream into a string | |
if (!$this->StreamToString()){ | |
// Tell the user where it all went wrong | |
$this->FatalError('Could not decode the data'); | |
} else { | |
// Tell the user that the next step is to decrypt and decompress | |
$this->Info('Decrypting data..'); | |
// If we can't decrypt and/or decompress | |
if (!$this->StringToRaw($key)){ | |
// Tell the user about the problem | |
$this->FatalError('Could not decrypt data'); | |
} else { | |
// If we have a problem outputting data | |
if (!$this->Output($outputPath)){ | |
// Fatal Error | |
$this->FatalError('Too many errors to continue'); | |
} else { | |
// We are done | |
$this->Success('Done in '.round(microtime(TRUE) - $StartTime).' seconds'); | |
} | |
} | |
} | |
} | |
} | |
} | |
// Input / Output Methods | |
/* | |
+------------------------------------------------------------------+ | |
| This will load the data to encode into the image | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function Input($data){ | |
// If the data looks like an array but NOT an uploaded file | |
if (is_array($data) && !isset($data['tmp_name'])){ | |
// Loop through each element in the array | |
foreach ($data as $Element){ | |
// Call ourselves again with the element | |
$this->Input($Element); | |
} | |
} else { | |
// Read the data into the raw data array | |
$this->ReadToRaw($data); | |
} | |
// If we have elements in our raw data array | |
if (is_array($this->RawData) && count($this->RawData > 0)){ | |
// Success | |
return TRUE; | |
} else { | |
// Failure | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will set properties relating to our run time environment | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function Output($path = ''){ | |
// If we have raw data to extract | |
if (is_array($this->RawData) && count($this->RawData)){ | |
// If we have a path set | |
if (strlen($path)){ | |
// If the path is not a directory | |
if (!is_dir($path)){ | |
// Error | |
$this->Error('The specified output path is not a directory'); | |
// Failure | |
return FALSE; | |
} | |
// If the path is not writable | |
if (!is_writable($path)){ | |
// Error | |
$this->Error('The specified output path is not writable'); | |
// Failure | |
return FALSE; | |
} | |
// While we have items in the raw data array | |
while (count($this->RawData) > 0){ | |
// If we can't write from the raw data | |
if (!$this->WriteFromRaw($path)){ | |
// Error | |
$this->Error('Problem extracting files'); | |
// Failure | |
return FALSE; | |
} | |
} | |
// If we got here we were probably successfull | |
return TRUE; | |
} else { | |
// If we are in command line mode | |
if ($this->CommandLineInterface()){ | |
// Then tell the user we're gonna need an output path | |
$this->Error('You must specify an output path when using this tool from the command line'); | |
// Failure | |
return FALSE; | |
} else { | |
// Ok browser boy, since you aren't leet enough for a shell you only get one file or message | |
$Data = $this->WriteFromRaw('', TRUE); | |
// Handle each type of data differently | |
switch ($Data['type']){ | |
// Message | |
case 'message': | |
// Send the appropriate mime type | |
header('Content-type: text/plain'); | |
// Attempt to set a file name and get the browser to download | |
header('Content-Disposition: attachment; filename=message.txt'); | |
// Output the message | |
echo $Data['message']; | |
// We should exit now so we don'taccidently send other stuff | |
exit(); | |
// Yeah, I know, redundant | |
break; | |
// File | |
case 'file': | |
// Set the file name and get the browser to download | |
header('Content-Disposition: attachment; filename='.$Data['filename']); | |
// Output the file contents | |
echo $Data['file']; | |
// Don't execute anything below this | |
exit(); | |
// Blah | |
break; | |
} | |
// If we get here we failed | |
return FALSE; | |
} | |
} | |
} else { | |
// Tell the user we had nothing to extract | |
$this->Error('No hidden data to extract from image'); | |
// Failure | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| Reads a local or remote file or a message into the raw array | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function ReadToRaw($data){ | |
// Figure out what kind of data we are dealing with here | |
switch ($this->GetArgumentType($data)){ | |
// A message | |
case 'message': | |
// If we actually have a message | |
if (strlen($data) > 0){ | |
// Add the message to the final array | |
array_push($this->RawData, array('type' => 'message', 'message' => base64_encode(gzdeflate($data)))); | |
// Success | |
return TRUE; | |
} | |
break; | |
// An uploaded file | |
case 'uploaded': | |
// Attempt to read the temporary file into a variable | |
$Contents = file_get_contents($data['tmp_name']); | |
// If we actually have contents | |
if (strlen($Contents) > 0){ | |
// Add the data to the raw data array | |
array_push($this->RawData, array('type' => 'file', 'file' => base64_encode(gzdeflate($Contents)), 'filename' => $data['name'])); | |
// Success | |
return TRUE; | |
} | |
break; | |
// A glob style string | |
case 'glob': | |
// Loop through all of the glob matches | |
foreach (glob($data) as $File){ | |
// Attempt to read the file into memory | |
$Contents = file_get_contents($File); | |
// If we have contents | |
if (strlen($Contents) > 0){ | |
// Add the data to the raw data array | |
array_push($this->RawData, array('type' => 'file', 'file' => base64_encode(gzdeflate($Contents)), 'filename' => $File)); | |
} | |
} | |
// Were probably successfull | |
return TRUE; | |
break; | |
// A path or url to a file | |
case 'file': | |
// Attempt to read the file into memory | |
$Contents = file_get_contents($data); | |
// If we have contents | |
if (strlen($Contents) > 0){ | |
// Add the data to the raw data array | |
array_push($this->RawData, array('type' => 'file', 'file' => base64_encode(gzdeflate($Contents)), 'filename' => $data)); | |
// We were probably successfull | |
return TRUE; | |
} | |
break; | |
} | |
// If we got here we failed | |
return FALSE; | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will pop another item off the raw data stack to output | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function WriteFromRaw($path = '', $return = FALSE){ | |
// If we actually have shit to extract | |
if (is_array($this->RawData) && count($this->RawData) > 0){ | |
// Pop another item off the stack | |
$Data = array_pop($this->RawData); | |
// Handle different data types differently | |
switch ($Data['type']){ | |
// Message | |
case 'message': | |
// If we aren't supposed to return | |
if ($return == FALSE){ | |
// We don't write messages, we output them | |
$this->Info('The following message was embedded in the image'); | |
$this->Info("\t".gzinflate(base64_decode($Data['message']))); | |
// Success | |
return TRUE; | |
} else { | |
// Decompress the message | |
$Data['message'] = gzinflate(base64_decode($Data['message'])); | |
// Return the data type | |
return $Data; | |
} | |
// I don't know why I do this | |
break; | |
// File | |
case 'file': | |
// If we aren't returning | |
if ($return == FALSE){ | |
// If we do not have a path | |
if (!strlen($path)){ | |
// Then this was a waste of our time | |
return FALSE; | |
} else { | |
// Get some ifnormation about the file | |
$Info = pathinfo($Data['filename']); | |
// Get some information about our path | |
$Path = pathinfo($path); | |
// Attempt to open a file pointer to the output path | |
$Pointer = fopen($Path['dirname'].'/'.$Path['basename'].'/'.$Info['basename'], 'w+'); | |
// If we have a pointer | |
if (is_resource($Pointer)){ | |
// Write to the file | |
fwrite($Pointer, gzinflate(base64_decode($Data['file']))); | |
// Close the file | |
fclose($Pointer); | |
// I'm guessing everything went OK | |
return TRUE; | |
} else { | |
// Failure | |
return FALSE; | |
} | |
} | |
} else { | |
// Just decompress and decode the file contents | |
$Data['file'] = gzinflate(base64_decode($Data['file'])); | |
// And return it | |
return $Data; | |
} | |
// | |
break; | |
} | |
} else { | |
// Meh | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will encode and compress a raw data array | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function RawToString($key = ''){ | |
// If we actually have a data array | |
if (is_array($this->RawData) && count($this->RawData) > 0){ | |
// Serialize our data array | |
$this->DataString = serialize($this->RawData); | |
// Instantiate the Secrypt object | |
$Secrypt = new Secrypt(); | |
// If we can encrypt the data | |
if ($Secrypt->Encrypt($this->DataString, $key)){ | |
// Then update the data string | |
$this->DataString = $Secrypt->Data; | |
// We are done with the raw data and encryption class | |
$this->RawData = array(); unset($Secrypt); | |
// Loop untill we have a valid bit boundry | |
while (strstr($this->DataString, $Boundry) || strlen($Boundry) <= 0){ | |
// Generate a new 24 bit boundry | |
$Boundry = chr(rand(33, 127)).chr(rand(33, 127)).chr(rand(33, 127)); | |
} | |
// Reset the bit boundry | |
$this->BitBoundry = ''; | |
// Loop through each character in the new boundry | |
for ($i = 0; $i < 3; $i++){ | |
// Add this to the bit boundry | |
$this->BitBoundry .= str_pad(decbin(ord($Boundry[$i])), 8, '0', STR_PAD_LEFT); | |
} | |
// Success | |
return TRUE; | |
} else { | |
// We have no data string | |
$this->DataString = ''; | |
// Failure | |
return FALSE; | |
} | |
} else { | |
// Nothing to do | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will decompress and decode a string into a raw data array | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function StringToRaw($key = ''){ | |
// If we actually have an encoded data string | |
if (is_string($this->DataString) && strlen($this->DataString) > 0){ | |
// Create a new instance of the Secrypt object | |
$Secrypt = new Secrypt(); | |
// If we can decrypt the string | |
if ($Secrypt->Decrypt($this->DataString, $key)){ | |
// Then unserialize the data array | |
$this->RawData = unserialize($Secrypt->Data); | |
// If we have a raw data array | |
if (is_array($this->RawData) && count($this->RawData) > 0){ | |
// Then we did it | |
return TRUE; | |
} else { | |
// Failure | |
return FALSE; | |
} | |
} else { | |
// Failure | |
return FALSE; | |
} | |
} else { | |
// Nothing to do | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will turn a bit stream into a data string | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function StreamToString(){ | |
// Make sure we have an empty data string | |
$this->DataString = ''; | |
// Loop untill the end of the bit stream | |
while (!$this->BitStream->EOF()){ | |
// Add the character representation for the next 8 bits to our data string | |
$this->DataString .= chr(bindec($this->BitStream->Read(8))); | |
} | |
// If we have a data string | |
if (strlen($this->DataString) > 0){ | |
// Trim any spare spaces off the string | |
$this->DataString = trim($this->DataString, ' '); | |
// Success | |
return TRUE; | |
} else { | |
// Summn went wrong | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will turn an encoded data string into a bit sequence | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function StringToStream(){ | |
// Flush the bit stream | |
$this->BitStream->FlushStream(); | |
// If we have a data string that will fit in the image | |
if ((strlen($this->DataString) * 8) < (($this->Image->CountPixels() - 6) * 3)){ | |
// While the length of the string is not cleanly divisible by 3 | |
while (strlen($this->DataString) % 3 > 0){ | |
// Add a white space character to the data string | |
$this->DataString .= ' '; | |
} | |
// While we still have a data string | |
while (strlen($this->DataString) > 0){ | |
// Write the next chunk of characters to the bit stream | |
$this->BitStream->Write(substr($this->DataString, 0, 1)); | |
// Remove the first character from the data string | |
$this->DataString = substr($this->DataString, 1); | |
} | |
// Success | |
return TRUE; | |
} else { | |
// Work out how many bytes this image can hold | |
$Capacity = round(($this->Image->CountPixels() * 3) / 8); | |
// If we have less than a kilobyte | |
if ($Capacity < 1024){ | |
// Make the capacity human readable | |
$Capacity = $Capacity.' bytes'; | |
// If the capacity is smaller than a megabyte | |
} elseif ($Capacity < 1048576){ | |
// Make the capacity human readable | |
$Capacity = round($Capacity / 1024, 2).' KB'; | |
// The capacity is 1 megabyte or over | |
} else { | |
// Make the capacity human readable | |
$Capacity = round(($Capacity / 1024) / 1024, 2).' MB'; | |
} | |
// Tell the user why the problem occurred | |
$this->Error('That image is not large enough to store that much data'); | |
// Now go over the top and tell the user how they can fix it | |
$this->Error('The image you supplied can only hold '.$Capacity.' of data'); | |
// Failure | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will read pixels to obtain a bit stream | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function PixelsToStream(){ | |
// Make a new bit stream for the image | |
$BitStream = new BitStream($this->Image->GetBoundry()); | |
// Move to the start pixel | |
$this->Image->StartPixel(); | |
// While we have bits and pixels | |
while (!$this->Image->EOF() && !$BitStream->EOF()){ | |
// Get the current pixels RGB value | |
$Pixel = $this->Image->GetPixel(); | |
// Write the pixel data to the bit stream | |
$BitStream->Write($Pixel); | |
// Move to the next pixel | |
$this->Image->NextPixel(); | |
} | |
// If we got to the end of the image | |
if ($this->Image->EOF()){ | |
// Then we never found our secret data | |
$BitStream->Stream = ''; | |
} | |
// Overwrite the main bit stream with our new one | |
$this->BitStream = $BitStream; | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will write a bit stream to pixels | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function StreamToPixels(){ | |
// Move to the start pixel | |
$this->Image->StartPixel(); | |
// While we have bits and pixels | |
while (!$this->Image->EOF() && !$this->BitStream->EOF()){ | |
// Read the next 3 bits from the bit stream | |
$Bits = $this->BitStream->Read(3); | |
// Write those 3 bits to the current pixel | |
$this->Image->SetPixel($Bits); | |
// Move to the next pixel | |
$this->Image->NextPixel(); | |
} | |
// Set the end bit boundry | |
$this->Image->SetBoundry($this->BitBoundry); | |
// Move to the first pixel | |
$this->Image->FirstPixel(); | |
// Set the first bit boundry | |
$this->Image->SetBoundry($this->BitBoundry); | |
// If we got here we probably succeeded | |
return TRUE; | |
} | |
// Enviromental Methods | |
/* | |
+------------------------------------------------------------------+ | |
| This will set properties relating to our run time environment | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function SetEnvironment(){ | |
// If we have a REQUEST_METHOD | |
if ($_SERVER['REQUEST_METHOD']){ | |
// Then we are probably being called from the web | |
$this->CLI = FALSE; | |
// Turn verbose output off | |
$this->Verbose = FALSE; | |
} else { | |
// We are being run as a command line (or possibly compiled) app | |
$this->CLI = TRUE; | |
// Turn verbose output on | |
$this->Verbose = TRUE; | |
// Make sure we have implicit flush set to on | |
ob_implicit_flush(1); | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will determine if we are using a command line interface | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function CommandLineInterface(){ | |
// If the command line interface flag is set | |
if ($this->CLI){ | |
// Then we are probably using a command line interface | |
return TRUE; | |
} else { | |
// Not a command line interface | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will attempt to figure out what an argument represents | | |
| | | |
| @return string | | |
+------------------------------------------------------------------+ | |
*/ | |
function GetArgumentType($argument){ | |
// If this is looks like an uploaded file | |
if (is_array($argument) && isset($argument['tmp_name'])){ | |
// Then it probably is one | |
return 'uploaded'; | |
// If this looks like a local file | |
} elseif (file_exists($argument)){ | |
// Handle as a file | |
return 'file'; | |
// If this looks like an external resource (TODO: Do this properly) | |
} elseif (strstr($argument, '://')){ | |
// Handle as a file | |
return 'file'; | |
// If the argument contains an asterix (TODO: Check the validity of the path) | |
} elseif (strstr($argument, '*') && ($argument[0] == '.' || $argument[0] == '/')){ | |
// Then I'm guessing it is a glob style string | |
return 'glob'; | |
// Everything else | |
} else { | |
// Treat it as a normal message | |
return 'message'; | |
} | |
} | |
// Message Methods | |
/* | |
+------------------------------------------------------------------+ | |
| Print out an error message to the user and exit | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function FatalError($msg){ | |
// First we show the error message to the user | |
$this->Error('Fatal Error: '.$msg); | |
// Now we exit | |
exit(-1); | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| Print out an error message to the user | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function Error($msg){ | |
// If we are running as a command line application | |
if ($this->CommandLineInterface()){ | |
// Just show the message a little formatted for the command line | |
echo '[-] '.$msg.".\n"; | |
} else { | |
// Show the error formatted for the web | |
echo '<strong>Error:</strong> '.htmlspecialchars($msg).'<br />'; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| Print out a success message to the user | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function Success($msg){ | |
// If we are in verbose mode | |
if ($this->Verbose){ | |
// If we are running as a command line application | |
if ($this->CommandLineInterface()){ | |
// Just show the message a little formatted for the command line | |
echo '[+] '.$msg.".\n"; | |
} else { | |
// Show the message formatted for the web | |
echo '<strong>Success:</strong> '.htmlspecialchars($msg).'<br />'; | |
} | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| Print out an informative message to the user | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function Info($msg){ | |
// If we are in verbose mode | |
if ($this->Verbose){ | |
// If we are running as a command line application | |
if ($this->CommandLineInterface()){ | |
// Just show the message a little formatted for the command line | |
echo '[i] '.$msg.".\n"; | |
} else { | |
// Show the message formatted for the web | |
echo '<strong>Info:</strong> '.htmlspecialchars($msg).'<br />'; | |
} | |
} | |
} | |
} | |
/* | |
+----------------------------------------------------------------------+ | |
| Package: Stegger v0.5 | | |
| Class : BitStream | | |
| Created: 03/08/2006 | | |
+----------------------------------------------------------------------+ | |
*/ | |
class BitStream { | |
/*-------------------*/ | |
/* V A R I A B L E S */ | |
/*-------------------*/ | |
/** | |
* string | |
* | |
* This is a string of 1's and 0's representing binary data | |
*/ | |
var $Stream = ''; | |
/** | |
* string | |
* | |
* This is a string of 1's and 0's representing the bit boundry | |
*/ | |
var $Boundry = ''; | |
/** | |
* boolean | |
* | |
* This is a flag to determine if the class is still new or not | |
*/ | |
var $Fresh = TRUE; | |
/*-------------------*/ | |
/* F U N C T I O N S */ | |
/*-------------------*/ | |
/* | |
+------------------------------------------------------------------+ | |
| Constructor | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function BitStream($bitBoundry = ''){ | |
// If we have a bit boundry, use it | |
if ($bitBoundry) $this->Boundry = $bitBoundry; | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will read $number bits from the bit stream | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function Read($number = 8){ | |
// If we are not on the end of the bit stream | |
if (strlen($this->Stream) > 0){ | |
// Grab the chunk of bits from the bit stream | |
$return = substr($this->Stream, 0, $number); | |
// Remove the chunk of bits from the bit stream | |
$this->Stream = substr($this->Stream, $number); | |
// Return the chunk of bits | |
return $return; | |
} else { | |
// Nothing to return | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will write data to the bit stream | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function Write($data, $binary = FALSE){ | |
// If we have binary data | |
if ($binary){ | |
// Then just add it raw | |
$this->Stream .= $data; | |
} else { | |
// Handle different data types differently | |
switch (gettype($data)){ | |
// String | |
case 'string': | |
// Loop through each character in the string | |
for ($i = 0; $i < strlen($data); $i++){ | |
// Add the bit representation for this character to the bit stream | |
$this->Stream .= str_pad(decbin(ord($data[$i])), 8, '0', STR_PAD_LEFT); | |
} | |
break; | |
// Integer | |
case 'integer': | |
// Add the bit representation for this character to the bit stream | |
$this->Stream .= str_pad(decbin($data), 8, '0', STR_PAD_LEFT); | |
break; | |
// Boolean | |
case 'boolean': | |
// If the boolean is true | |
if ($data == TRUE){ | |
// Then add a 1 to the bit stream | |
$this->Stream .= '1'; | |
} else { | |
// Add a 0 to the bit stream | |
$this->Stream .= '0'; | |
} | |
break; | |
// Array of RGB values | |
case 'array': | |
// Loop through each primary colour in this RGB array | |
foreach ($data as $PrimaryColour){ | |
// Add the bit value of this integer | |
$this->Stream .= (int) $PrimaryColour % 2; | |
} | |
break; | |
} | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will determine if we have hit the end of the bit stream | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function EOF(){ | |
// If we have not ran any methods yet | |
if ($this->Fresh){ | |
// We are no longer fresh | |
$this->Fresh = FALSE; | |
// But we are not at the end of the file either | |
return FALSE; | |
} | |
// If we have a bit of stream left | |
if (strlen($this->Stream) > 0){ | |
// If we have a bit boundry | |
if (strlen($this->Boundry)){ | |
// If we have found our bit boundry | |
if (substr($this->Stream, -24) == $this->Boundry){ | |
// Then we remove the boundry from the bit stream | |
$this->Stream = substr($this->Stream, 0, -24); | |
// We hit the end of the stream | |
return TRUE; | |
} else { | |
// We are not at the end of the stream | |
return FALSE; | |
} | |
} else { | |
// Not at the end | |
return FALSE; | |
} | |
} else { | |
// Yeah, we're at the end | |
return TRUE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will flush out the bit stream (reset it) | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function FlushStream(){ | |
// Reset the stream | |
$this->Stream = ''; | |
} | |
} | |
/* | |
+----------------------------------------------------------------------+ | |
| Package: Stegger v0.5 | | |
| Class : Image | | |
| Created: 03/08/2006 | | |
+----------------------------------------------------------------------+ | |
*/ | |
class Image { | |
/*-------------------*/ | |
/* V A R I A B L E S */ | |
/*-------------------*/ | |
/** | |
* resource | |
* | |
* This is the main image canvas we are reading from or writing too | |
*/ | |
var $Canvas; | |
/** | |
* string | |
* | |
* The name of the image we are encoding to or decoding from | |
*/ | |
var $Name = ''; | |
/** | |
* integer | |
* | |
* The main image canvas' width | |
*/ | |
var $Width = 0; | |
/** | |
* integer | |
* | |
* The main image canvas' height | |
*/ | |
var $Height = 0; | |
/** | |
* array | |
* | |
* This is an array containing the x and y co-ordinate's of the current pixel | |
*/ | |
var $PixelPointer = array('x' => 0, 'y' => 0); | |
/** | |
* boolean | |
* | |
* Determines if we are at the end of the image or not | |
*/ | |
var $EOF = TRUE; | |
/*-------------------*/ | |
/* F U N C T I O N S */ | |
/*-------------------*/ | |
/* | |
+------------------------------------------------------------------+ | |
| Constructor | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function Image($image){ | |
// If we have an image | |
if ($image){ | |
// Load it | |
$this->Load($image); | |
} else { | |
// Failure | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will load an image as a resource | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function Load($image){ | |
// If the image looks like it was uploaded | |
if (is_array($image) && isset($image['tmp_name'])){ | |
// Set the default output image name using the original file name | |
$this->SetName($image['name']); | |
// Create a canvas for this image | |
$this->CreateCanvas($image['tmp_name'], $image['name']); | |
} else { | |
// Set the default output image name using the path or url to the image | |
$this->SetName($image); | |
// Create a canvas for this image | |
$this->CreateCanvas($image); | |
} | |
// If we actually have a canvas at this point | |
if (is_resource($this->Canvas)){ | |
// We are not at the end of the file | |
$this->EOF = FALSE; | |
// Clear the canvas | |
$this->ClearCanvas(); | |
// Move to the first pixel | |
$this->FirstPixel(); | |
// Success | |
return TRUE; | |
} else { | |
// Failure | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| Creates an image canvas resource from an image url or path | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function CreateCanvas($image, $name = ''){ | |
// If we don't have the original name, then the image contains the name | |
if (!$name) $name = $image; | |
// Handle each image type differently | |
switch ($this->GetImageType($name)){ | |
// JPG | |
case 'JPG': | |
// Create a canvas from the JPG | |
$this->Canvas = imagecreatefromjpeg($image); break; | |
// PNG | |
case 'PNG': | |
// Create a canvas from the PNG | |
$this->Canvas = imagecreatefrompng($image); break; | |
// GIF | |
case 'GIF': | |
// Create a canvas from the GIF | |
$this->Canvas = imagecreatefromgif($image); break; | |
// Not Supported | |
default: | |
// Nothing else we can do | |
return; | |
} | |
// If we have an image canvas | |
if (is_resource($this->Canvas)){ | |
// Get the images width | |
$this->Width = imagesx($this->Canvas); | |
// Get the images height | |
$this->Height = imagesy($this->Canvas); | |
// We are not at the end of the file | |
$this->EOF = FALSE; | |
} else { | |
// We are at the end of the file | |
$this->EOF = TRUE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will copy the image on to a fresh canvas | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function ClearCanvas(){ | |
// Create a new true colour canvas based on our images dimensions | |
$Canvas = imagecreatetruecolor($this->Width, $this->Height); | |
// If we have a canvas and an image | |
if (is_resource($Canvas) && is_resource($this->Canvas)){ | |
// Make sure alpha blending is off | |
imagealphablending($Canvas, FALSE); | |
// Copy the contents of the original canvas to the new one | |
imagecopy($Canvas, $this->Canvas, 0, 0, 0, 0, $this->Width, $this->Height); | |
// Overwrite the old canvas with the newly prepaired one | |
$this->Canvas = $Canvas; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will output the current image to a file or the browser | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function Output($outputFile = ''){ | |
// If we have an output file specified | |
if ($outputFile){ | |
// Set the output image name | |
$this->SetName($outputFile); | |
} | |
// If we are serving to a browser | |
if ($_SERVER['REQUEST_METHOD']){ | |
// Make sure the browser knows this is a PNG image | |
header('Content-type: image/png'); | |
// Try get the browser to download the image as our name | |
header('Content-Disposition: attachment; filename='.$this->Name); | |
// Output the image to the browser | |
imagepng($this->Canvas); | |
} else { | |
// Get some information about the output path | |
$Info = pathinfo($outputFile); | |
// Write the image to the file name specified | |
imagepng($this->Canvas, $Info['dirname'].'/'.$this->Name); | |
} | |
// Destroy the canvas | |
imagedestroy($this->Canvas); | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will get the image type from a URL or path to an image | | |
| | | |
| @return string | | |
+------------------------------------------------------------------+ | |
*/ | |
function GetImageType($image){ | |
// Get some information about the path, URL or image name | |
$Info = pathinfo($image); | |
// Handle each extension type differently | |
switch (strtolower($Info['extension'])){ | |
// JPEG | |
case 'jpg': | |
case 'jpeg': | |
// We are dealing with a JPG | |
return 'JPG'; | |
// GIF | |
case 'gif': | |
// We are dealing with a GIF | |
return 'GIF'; | |
// PNG | |
case 'png': | |
// We are dealing with a PNG | |
return 'PNG'; | |
// * | |
default: | |
// No idea what the hell this is | |
return ''; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will get the RGB value of the current pixel | | |
| | | |
| @return array | | |
+------------------------------------------------------------------+ | |
*/ | |
function GetPixel(){ | |
// Get the (32 bit) RGB value from the current image | |
$RGB = imagecolorat($this->Canvas, $this->PixelPointer['x'], $this->PixelPointer['y']); | |
// Obtain the individual values for each primary colour | |
$R = ($RGB >> 16) & 0xFF; | |
$G = ($RGB >> 8) & 0xFF; | |
$B = ($RGB >> 0) & 0xFF; | |
// Return the individual RGB values in an array | |
return array($R, $G, $B); | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will set the RGB value of the current array | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function SetPixel($rgb){ | |
// If this looks like a couple of bits | |
if (is_string($rgb) && strlen($rgb) == 3){ | |
// Get the RGB value of the current pixel | |
$RGB = $this->GetPixel(); | |
// Loop through each primary colour in this pixel | |
for ($i = 0; $i < 3; $i++){ | |
// If the current char of our binary string is a 1 | |
if ($rgb[$i] == '1'){ | |
// If the current colour value isn't odd | |
if ($RGB[$i] % 2 != 1){ | |
// Increment it | |
$RGB[$i]++; | |
} | |
} else { | |
// If the current colour valie isn't even | |
if ($RGB[$i] % 2 != 0){ | |
// Decrease it | |
$RGB[$i]--; | |
} | |
} | |
} | |
// Call ourselves again with the RGB array | |
$this->SetPixel($RGB); | |
// And thats all there is to it | |
return TRUE; | |
} | |
// If we have a full RGB array | |
if (is_array($rgb) && count($rgb) == 3){ | |
// Allocate the colour to the image | |
$Colour = imagecolorallocate($this->Canvas, $rgb[0], $rgb[1], $rgb[2]); | |
// Assign the colour to the current pixel | |
imagesetpixel($this->Canvas, $this->PixelPointer['x'], $this->PixelPointer['y'], $Colour); | |
// We're done here | |
return TRUE; | |
} | |
// If we get here we failed | |
return FALSE; | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will count the total number of pixels on the canvas | | |
| | | |
| @return integer | | |
+------------------------------------------------------------------+ | |
*/ | |
function CountPixels(){ | |
// Return the width multiplied by the height | |
return round($this->Height * $this->Width); | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will move the pixel position to the first pixel | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function FirstPixel(){ | |
// Reset the pixel pointer | |
$this->PixelPointer['x'] = ($this->Width - 1); | |
$this->PixelPointer['y'] = ($this->Height - 1); | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will move the pixel pointer to the start of the data | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function StartPixel(){ | |
// The data starts 24 bits in (3 bytes) | |
$this->PixelPointer['x'] = ($this->Width - 1) - 8; | |
$this->PixelPointer['y'] = ($this->Height - 1); | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will move to the next pixel | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function NextPixel(){ | |
// If we are on the last column | |
if ($this->PixelPointer['x'] <= 0){ | |
// If we are on the last row of pixels | |
if ($this->PixelPointer['y'] <= 0){ | |
// We are at the end of the file | |
$this->EOF = TRUE; | |
// So we can't go any further | |
return $this->EOF; | |
} else { | |
// Move to the next row | |
$this->PixelPointer['y']--; | |
// Move to the first column of the new row | |
$this->PixelPointer['x'] = ($this->Width - 1); | |
} | |
} else { | |
// Move to the next column | |
$this->PixelPointer['x']--; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will move to the previous pixel | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function PrevPixel(){ | |
// If we are on the first column | |
if ($this->PixelPointer['x'] >= ($this->Width - 1)){ | |
// If we are on the first row of pixels | |
if ($this->PixelPointer['y'] >= ($this->Height - 1)){ | |
// Then we can't go back any further | |
return; | |
} else { | |
// Move to the previous row | |
$this->PixelPointer['y']++; | |
// Move to the last column of the current row | |
$this->PixelPointer['x'] = 0; | |
} | |
} else { | |
// Move to the previous column | |
$this->PixelPointer['x']++; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will get the boundry pattern for the bit stream | | |
| | | |
| @return string | | |
+------------------------------------------------------------------+ | |
*/ | |
function GetBoundry(){ | |
$return = ''; | |
// Backup the current pixel pointer | |
$PixelPointer = $this->PixelPointer; | |
// Move to the first pixel | |
$this->FirstPixel(); | |
// Go through the first 8 pixels (24 bits) | |
for ($i = 0; $i < 8; $i++){ | |
// Get this pixels RGB value | |
$Pixel = $this->GetPixel(); | |
// Loop through each primary colour in this | |
foreach ($Pixel as $PrimaryColour){ | |
// Add the bit value of this number to the final string | |
$return .= (int) $PrimaryColour % 2; | |
} | |
// Move to the next pixel | |
$this->NextPixel(); | |
} | |
// Move the pixel pointer back where it was | |
$this->PixelPointer = $PixelPointer; | |
// Return the final value | |
return $return; | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This sets the bit boundry from the current pixel position | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function SetBoundry($boundry){ | |
// If we have at least 3 bytes of data (24 bits) | |
if (strlen($boundry) >= 24){ | |
// Initiate the bit counter | |
$b = 0; | |
// Loop through 8 pixels from our current position | |
for ($i = 0; $i < 8; $i++){ | |
// Get the RGB value of the current value | |
$RGB = $this->GetPixel(); | |
// Loop through each primary colour in the RGB array | |
for ($j = 0; $j < 3; $j++){ | |
// Get the next bit from the binary string | |
$Bit = $boundry[$b]; | |
// Figure out which kind of bit this is | |
switch ($Bit){ | |
// 1 | |
case '1': | |
// If this colour is not an odd number | |
if ($RGB[$j] % 2 != 1){ | |
// Then increase it | |
$RGB[$j]++; | |
} | |
break; | |
// 0 | |
case '0': | |
// If this colour is not represented by an even number | |
if ($RGB[$j] % 2 != 0){ | |
// Decrease it | |
$RGB[$j]--; | |
} | |
break; | |
} | |
// Increment the bit counter | |
$b++; | |
} | |
// Set the pixel to our new RGB array | |
$this->SetPixel($RGB); | |
// Move to the next pixel | |
$this->NextPixel(); | |
} | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will set the name of the image we are going to output | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function SetName($image){ | |
// Get some information about the image filename, path or url | |
$Info = pathinfo($image); | |
// If we have an extension | |
if (strlen($Info['extension']) > 0){ | |
// If the extension is not a PNG | |
if (strtolower($Info['extension']) != 'png'){ | |
// Change the extension to a PNG | |
$Info['basename'] = str_replace('.'.$Info['extension'], '.png', $Info['basename']); | |
} | |
} else { | |
// If we have a basename | |
if (strlen($Info['basename']) > 0){ | |
// Then append our extension to it | |
$Info['basename'] .= '.png'; | |
} else { | |
// This guy isn't giving us much choice | |
$Info['basename'] = 'encoded.png'; | |
} | |
} | |
// Set the image name to the base name | |
$this->Name = $Info['basename']; | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will test for the end of the file (image) | | |
| | | |
| @return boolean | | |
+------------------------------------------------------------------+ | |
*/ | |
function EOF(){ | |
// Return the end of file property | |
return $this->EOF; | |
} | |
} | |
/* | |
+----------------------------------------------------------------------+ | |
| Package: Stegger v0.5 | | |
| Class : Secrypt | | |
| Created: 23/07/2006 | | |
+----------------------------------------------------------------------+ | |
*/ | |
class Secrypt { | |
/*-------------------*/ | |
/* V A R I A B L E S */ | |
/*-------------------*/ | |
// Public Properties | |
/** | |
* array | |
* | |
* This is the array of keys we use to encrypt or decrypt data | |
*/ | |
var $Keys = array('public' => '', 'private' => '', 'xfactor' => '', 'yfactor' => '', 'zfactor' => ''); | |
/** | |
* string | |
* | |
* This holds the data after it has been successfully encrypted or decrypted | |
*/ | |
var $Data = ''; | |
/** | |
* boolean | |
* | |
* Determines if we can zip the contents or not | |
*/ | |
var $Zip = TRUE; | |
/** | |
* array | |
* | |
* All the error messages in an array | |
*/ | |
var $Errors = array(); | |
// Private Properties | |
/** | |
* array | |
* | |
* An array that holds each of our base64 compatible charsets | |
*/ | |
var $Locks = array(); | |
/*-------------------*/ | |
/* F U N C T I O N S */ | |
/*-------------------*/ | |
/* | |
+------------------------------------------------------------------+ | |
| Constructor | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function Secrypt(){ | |
// If we can't zip | |
if (!function_exists('gzdeflate')){ | |
// Then we don't zip | |
$this->Zip = FALSE; | |
} | |
// Run forever | |
set_time_limit(0); | |
// Reset the lock | |
$this->ResetLock(); | |
} | |
// Public API Methods | |
/* | |
+------------------------------------------------------------------+ | |
| This will encrypt $data against the $privateKey and $publicKey | | |
| | | |
| @return string | | |
+------------------------------------------------------------------+ | |
*/ | |
function Encrypt($data, $privateKey = '', $publicKey = STEGGER_PUB_KEY){ | |
// Insert the keys | |
$this->InsertKeys($privateKey, $publicKey); | |
// Turn all the keys | |
$this->TurnKey(); | |
// Locketh the data | |
return $this->Lock($data); | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will decrypt $data against the $privateKey and $publicKey | | |
| | | |
| @return string | | |
+------------------------------------------------------------------+ | |
*/ | |
function Decrypt($data, $privateKey = '', $publicKey = STEGGER_PUB_KEY){ | |
// Insert the keys | |
$this->InsertKeys($privateKey, $publicKey); | |
// Turn all the keys | |
$this->TurnKey(); | |
// Unlock the data and return the results | |
return $this->Unlock($data); | |
} | |
// Key Methods | |
/* | |
+------------------------------------------------------------------+ | |
| This gets a reference to the key that fits in $lockType | | |
| | | |
| @return reference | | |
+------------------------------------------------------------------+ | |
*/ | |
function &GetKey($lockType){ | |
// Return the appropriate key | |
return $this->Keys[$lockType]; | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will set all the keys in the key array at once | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function InsertKeys($private, $public){ | |
// Remove all keys | |
$this->RemoveKey(); | |
// Reset all the locks | |
$this->ResetLock(); | |
// Loop through all the keys | |
foreach ($this->Keys as $KeyType => $Key){ | |
// If this is a factor key | |
if (strstr($KeyType, 'factor')){ | |
// Set the key to the md5 hash of the keys array thus far | |
$Key = md5(serialize($this->Keys)); | |
} else { | |
// Set the key to the key we were passed | |
$Key = $$KeyType; | |
} | |
// Insert the key we have in the end | |
$this->InsertKey($Key, $KeyType); | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will set a $key for $lockType | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function InsertKey($key, $lockType){ | |
// If we have a key | |
if (strlen($key) > 0){ | |
// Set the key | |
$this->Keys[$lockType] = $key; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will turn a lock based on a keys contents | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function TurnKey($lockType = ''){ | |
// If we don't have a lock type | |
if (!$lockType){ | |
// Loop through all the locks | |
foreach ($this->Locks as $LockType => $Lock){ | |
// Call ourselves with this lock type | |
$this->TurnKey($LockType); | |
} | |
// Don't pass this bit | |
return; | |
} | |
// Get a reference to the desired key | |
$Key =& $this->GetKey($lockType); | |
// Loop through each character of the key | |
for ($i = 0; $i < strlen($Key); $i++){ | |
// Work out how many steps to turn the lock | |
$Steps = ord($Key[$i]) / ($i + 1); | |
// If the decimal value of the current character is odd | |
if (ord($Key[$i]) % 2 != 0){ | |
// Turn the lock left | |
$this->TurnLock($lockType, $Steps, 'left'); | |
} else { | |
// Turn the lock right | |
$this->TurnLock($lockType, $Steps, 'right'); | |
} | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will clear a keys contents, all keys if no $lockType is set | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function RemoveKey($lockType = ''){ | |
// Loop through each of the keys | |
foreach($this->Keys as $KeyName => $Key){ | |
// If this is our desired key or we don't have a desired key | |
if ($lockType == $KeyName || strlen($lockType) == 0){ | |
// Reset this key | |
$this->Keys[$KeyName] = ''; | |
} | |
} | |
} | |
// Lock Methods | |
/* | |
+------------------------------------------------------------------+ | |
| This gets a reference to the character set a key manipulates | | |
| | | |
| @return reference | | |
+------------------------------------------------------------------+ | |
*/ | |
function &GetLock($lockType){ | |
// Return a reference to the lock | |
return $this->Locks[$lockType]; | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will lock the data according to the current character index | | |
| | | |
| @return string | | |
+------------------------------------------------------------------+ | |
*/ | |
function Lock($data){ | |
// Reset the data | |
$this->Data = ''; | |
// If we are supposed to be zipping | |
if ($this->Zip == TRUE){ | |
// If we can't compress the data | |
if (FALSE === ($data = @gzdeflate($data))){ | |
// Add the error incase the user wants to know why we failed | |
$this->Error('There was a problem compressing the data'); | |
// Huston, we have a problem | |
return FALSE; | |
} | |
} | |
// If we can compress the character | |
if (FALSE !== ($data = base64_encode($data))){ | |
// Loop through each character in the data | |
for ($i = 0; $i < strlen($data); $i++){ | |
// Convert this character to its encrypted equivilent | |
$data[$i] = $this->GetChar($data[$i], TRUE); | |
} | |
// Looks like we have ourselves some data | |
$this->Data = $data; | |
// And thats all folks | |
return $this->Data; | |
} else { | |
// Add the error to let the user know why we failed | |
$this->Error('There was a problem encoding the data'); | |
// Failure | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This unlocks the data according to the current character index | | |
| | | |
| @return string | | |
+------------------------------------------------------------------+ | |
*/ | |
function Unlock($data){ | |
// Reset the data | |
$this->Data = ''; | |
// Loop through each character in the data | |
for ($i = 0; $i < strlen($data); $i++){ | |
// Convert this character to its decrypted equivilent | |
$data[$i] = $this->GetChar($data[$i], FALSE); | |
} | |
// If we can base64 decode the data | |
if (FALSE !== ($data = base64_decode($data))){ | |
// If we can decompress data | |
if (FALSE !== ($data = @gzinflate($data))){ | |
// Looks like we have ourselves some data | |
$this->Data = $data; | |
// Thats all folks | |
return $this->Data; | |
} else { | |
// Tell the user why we failed | |
$this->Error('There was a problem decompressing the data'); | |
// Failure | |
return FALSE; | |
} | |
} else { | |
// Add the error ro the error stack | |
$this->Error('There was a problem decoding the data'); | |
// Failure | |
return FALSE; | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will turn a lock (character set) $steps steps in $direction | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function TurnLock($lockType, $steps = 5, $direction = 'right'){ | |
// Loop through the required number of steps | |
for ($i = 0; $i < $steps; $i++){ | |
// Get a reference to the lock | |
$Lock =& $this->GetLock($lockType); | |
// If we are not going right, reverse the string | |
if ($direction != 'right') $Lock = strrev($Lock); | |
// Make a copy of the counter | |
$c = $i; | |
// If we are rotating a character passed the end of the character set | |
if ($c >= strlen($Lock)){ | |
// While we still have too little characters to split | |
while ($c >= strlen($Lock)){ | |
// Minus the lock length from the counter | |
$c = $c - strlen($Lock); | |
} | |
} | |
// Isolate the first character in the charset | |
$Char = substr($Lock, 0, 1); | |
$Lock = substr($Lock, 1); | |
$c = intval($c); | |
// If our split point exists | |
if (strlen(substr($Lock, $c, 1)) > 0) { | |
// Split the string at the desired position | |
$Chunks = explode($Lock[$c], $Lock); | |
// If we have some chunks | |
if (is_array($Chunks)){ | |
// Then piece together the string | |
$Lock = $Chunks[0].$Lock[$c].$Char.$Chunks[1]; | |
} | |
} else { | |
// Put the lock back to the way it was | |
$Lock = $Char.$Lock; | |
} | |
// If we are not going right, reverse the string back | |
if ($direction != 'right') $Lock = strrev($Lock); | |
} | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will generate the original charset and character index | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function ResetLock($lockType = ''){ | |
// Get the base 64 compatible character set | |
$CharSet = $this->GetCharSet(); | |
// Loop through the keys we have | |
foreach ($this->Keys as $LockType => $Key){ | |
// If we were supplied a lock type to reset | |
if ($lockType){ | |
// If this is our lock | |
if ($LockType == $lockType){ | |
// Then reset the lock | |
$this->Locks[$LockType] = $CharSet; | |
// And we're done | |
return; | |
} | |
} else { | |
// Reset this lock | |
$this->Locks[$LockType] = $CharSet; | |
} | |
} | |
} | |
// Character Set Methods | |
/* | |
+------------------------------------------------------------------+ | |
| This will lookup the encrypted/decrypted version of a character | | |
| | | |
| @return string | | |
+------------------------------------------------------------------+ | |
*/ | |
function GetChar($char, $encrypt = FALSE){ | |
// If we are not encrypting, flip the locks | |
if (!$encrypt) $this->Locks = array_reverse($this->Locks); | |
// Initate the lock counter | |
$i = 0; | |
// Loop through each lock | |
foreach ($this->Locks as $LockType => $Lock){ | |
// If this is the first lock, set the initial position | |
if ($i == 0){ | |
// Get the initial position | |
$Position = strpos($Lock, $char); | |
} | |
// If the lock counter is odd, or this is the final iteration | |
if ($i % 2 > 0){ | |
// If we are encrypting | |
if ($encrypt){ | |
// Swap position | |
$Position = strpos($Lock, $char); | |
} else { | |
// Swap character | |
$char = $Lock[$Position]; | |
} | |
} else { | |
// If we are encrypting | |
if ($encrypt){ | |
// Swap character | |
$char = $Lock[$Position]; | |
} else { | |
// Swap position | |
$Position = strpos($Lock, $char); | |
} | |
} | |
// Increment the lock counter | |
$i++; | |
} | |
// If we are not encrypting, flip the locks | |
if (!$encrypt) $this->Locks = array_reverse($this->Locks); | |
// Return the character | |
return $char; | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will generate and return a base 64 compatible charset | | |
| | | |
| @return string | | |
+------------------------------------------------------------------+ | |
*/ | |
function GetCharSet(){ | |
$return = ''; | |
// These are forbidden characters that fall in the range of chars we iterate | |
$ForbiddenChars = array_merge(range(44, 46), range(58, 64), range(91, 96)); | |
// Loop through the base64 compatible range of characters | |
for ($i = 43; $i < 123; $i++){ | |
// If this is not a forbidden character | |
if (!in_array($i, $ForbiddenChars)){ | |
// Then add this to the final character set | |
$return .= chr($i); | |
} | |
} | |
// Return the final character set | |
return $return; | |
} | |
// Error Reporting Methods | |
/* | |
+------------------------------------------------------------------+ | |
| This will add an error message to the error message stack | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function Error($msg){ | |
// Add the error to the stack | |
$this->Errors[] = $msg; | |
} | |
/* | |
+------------------------------------------------------------------+ | |
| This will display the error messages specific to the current env | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function ShowErrors($returnVal = FALSE){ | |
// Loop through all the errors | |
foreach ($this->Errors as $Error){ | |
// If we are being called from the web | |
if (strlen($_SERVER['REQUEST_METHOD']) > 0){ | |
// Format the errors for the web | |
$return .= '<strong>Error:</strong> '.$Error.'<br />'; | |
} else { | |
// Format the error message for the command line | |
$return .= '[-] '.$Error."\n"; | |
} | |
} | |
// Now that we are showing the errors, we can clear them too | |
$this->Errors = array(); | |
// If we are supposed to the return the errors | |
if ($returnVal){ | |
// Then return them we shall | |
return $return; | |
} else { | |
// Output the errors directly | |
echo $return; | |
} | |
} | |
// Debug Methods | |
/* | |
+------------------------------------------------------------------+ | |
| This will output a message instantly for debugging purposes | | |
| | | |
| @return void | | |
+------------------------------------------------------------------+ | |
*/ | |
function Debug($msg){ | |
// Turn implicit output buffering on incase it is off | |
ob_implicit_flush(1); | |
// If we are being called from the web | |
if (strlen($_SERVER['REQUEST_METHOD'])){ | |
// Then format the message for the web | |
$msg = '<strong>Debug:</strong> '.$msg.'<br />'; | |
} else { | |
// Format the message for a CLI | |
$msg = '[i] '.$msg."\n"; | |
} | |
// Output the message | |
echo $msg; | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment