<?php
/**
* Data Shield Class
*
* Data Shield for protecting and validating data when transmitting
* between pages and forms.
*
* Copyright (C) 2005 Oliver Lillie
*
* 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
*
* @link http://www.buggedcom.co.uk/
* @author Oliver Lillie, buggedcom <publicmail at buggedcom dot co dot uk>
* @history -----------------------------------------------------------------
* 0.71 30/09/2005 - Added option to add slashes to form strings
* 0.7 30/09/2005 - Added javascript > php encrypt and decryption protocols for
* protecting data sent via none https forms (compatabile with the
* des module only)
* - Added various new methods for detecting if data is transmitted
* - Added mcrypt debug table
* 0.64 26/09/2005 - Renamed encrypted vars for slightly shorter encrypted strings
* 0.63 25/09/2005 - Added fatal error triggers to validation and excecution methods
* - Added defined vars for the error type
* 0.62 15/09/2005 - Fixed improper reference to _stripslashes_r
* 0.61 11/09/2005 - Fixed intermitent bug with encoding and decoding
* 0.6 07/07/2005 - Added timeout param so link is only valid for a certain
* amount of time after which it fails.
* - Added zlib checking so not used if not available
* 0.5 04/07/2005 - Added private function for removing globals and magic
* quotes. set in the constructor
* 0.4 01/07/2005 - Added expunge and make_secure functions
* 0.3 29/06/2005 - Marc Wöhlken has made suggestions and improved some stuff
* - Added new shield type - PURE_GET
* - removed random seeding
* - added filename safe rfc3548 encoding and decoding
* - changed default algorithm to twofish, apparently it is 30%
* faster
* 0.2 28/06/2005 - Typos corrected thanks to Greg Winterstein
* 0.1 26/06/2005 - Created
*/
/**
* Defined variables for on error handling
* @access public
*/
define('SHIELD_VERBOSE', 'SHIELD_VERBOSE');
define('SHIELD_QUIET', 'SHIELD_QUIET');
define('SHIELD_FATAL', 'SHIELD_FATAL');
/**
* Defined variables for error returning (SHIELD_QUIET)
* @access public
*/
define('SHIELD_OK', 'SHIELD_OK');
define('SHIELD_EMPTY', 'SHIELD_EMPTY');
define('SHIELD_SIG404', 'SHIELD_SIG404');
define('SHIELD_TIMEOUT', 'SHIELD_TIMEOUT');
define('SHIELD_DATA_FAULT', 'SHIELD_DATA_FAULT');
define('SHIELD_POST_ENCRYPT_ALGORITHM_ERROR', 'SHIELD_POST_ENCRYPT_ALGORITHM_ERROR');
define('SHIELD_POST_INVALID_CAPTCHA', 'SHIELD_POST_INVALID_CAPTCHA');
/**
* Defined params for different return types used in shield::protect()
* @access public
*/
define('SHIELD_PURE_GET', 'SHIELD_PURE_GET');
define('SHIELD_PURE_GET_MULTI', 'SHIELD_PURE_GET_MULTI');
define('SHIELD_PURE_GET_MULTI_RANDOM', 'SHIELD_PURE_GET_MULTI_RANDOM');
define('SHIELD_GET', 'SHIELD_GET');
define('SHIELD_GET_MULTI', 'SHIELD_GET_MULTI');
define('SHIELD_GET_MULTI_RANDOM', 'SHIELD_GET_MULTI_RANDOM');
define('SHIELD_PLAIN', 'SHIELD_PLAIN');
define('SHIELD_INPUT', 'SHIELD_INPUT');
define('SHIELD_INPUT_MULTI', 'SHIELD_INPUT_MULTI');
define('SHIELD_INPUT_MULTI_RANDOM', 'SHIELD_INPUT_MULTI_RANDOM');
class shield {
/**
* PUBLIC VARS
**/
/**
* hash key used to encrypt the url data.
* @access public
* @var string
*/
var $HASH_KEY = 'vr1Akqw28HIpqwTlm1o4AqQe6roAf85vnDwcc9vYSmx2cDmo6wrb8gSpDwa60VwsU86YNiur3DgnBiw4ec1d';
/**
* Digital signature md5'd into the var for validation
* @access public
* @var string
*/
var $DIGITAL_SIG = 'h0PsC0Tch';
/**
* The algorithm to be used by mcrypt. Marc Wöhlken believes that twofish
* is a faster and lighter algorithm.
* @access public
* @var string
*/
var $ALGORITHM = 'twofish';
/**
* The mode to be used by mcrypt. default = 'ecb'
* @access public
* @var string
*/
var $MODE = 'ecb';
/**
* The name of the var that the encoded data will take, default = '@c'
* @access public
* @var string
*/
var $VAR_NAME = '@c';
/**
* The algorithm to be used by javascript and mcrypt to enable POST data encryption, currently only supports one encryption module, des (default)
* @access public
* @var string
*/
var $POST_ALGORITHM = 'des';
/**
* The mode to be used by javascript and mcrypt to enable POST data encryption, currently only supports one encryption mode, default = 'ecb'
* @access public
* @var string
*/
var $POST_MODE = 'ecb';
/**
* The name of the var that the encoded data will take, default = '@c'
* @access public
* @var string
*/
var $POST_VAR_NAME = 'SHIELD';
/**
* Determines if errors are returned or false values, SHIELD_VERBOSE (default), SHIELD_QUIET, SHIELD_FATAL
* @access public
* @var defined var
*/
var $ON_ERROR = SHIELD_FATAL;
/**
* PRIVATE VARS
**/
/**
* Init the var used to store the directory of the script
* @access private
*/
var $_DIR;
/**
* Init the var used to store if the server is zlib compatible
* @access private
*/
var $_ZLIB;
/**
* Init the expunge data array, used to collect merge var names
* @access private
*/
var $_VAR_NAMES;
/**
* Determines if the mycrypt module has been opened and inited
* @access private
*/
var $_OPEN = false;
/**
* Stores a reference to the open mcrypt module
* @access private
*/
var $_MODULE_REF;
/**
* PUBLIC FUNCTIONS
**/
/**
* Constructor
*
* @access public
* @param $remove_register_globals bool Removes defined globals if register_globals is active
* @param $remove_magic_quotes bool Removes magic quotes if magic quotes are active
* @return void
**/
function shield($remove_register_globals=true, $remove_magic_quotes=false)
{
# start the session
session_start();
# check to see if class is secure
$this->_check_secure();
# check for valid mycrypt stuff
$this->_validate_algorithm();
# create the _DIR value
$this->_DIR = dirname(__FILE__);
# check for zip compat
$this->_ZLIB = function_exists('gzdeflate');
# run the clean up funcs if required
if($remove_register_globals) $this->_remove_globals();
if($remove_magic_quotes) $this->_remove_magic_quotes();
# open the shield
$this->_open_shield();
}
/**
* protect
*
* Protects data by converting the data into a string that contains the encrypted information.
* The returned value can take several formats depending on what is required by the script.
*
* @access public
* @param mixed $data Variables you want to encrypt for transfering to another page
* @param string $shield_type The type of return string
* SHIELD_PLAIN - returns a plain string for input into a form value for submission
* ie vreinvg3rihviv234rv23vjmosvfe
* => <input type="hidden" name="shield" value="vreinvg3rihviv234rv23vjmosvfe" />
* SHIELD_GET - returns a string for an url sending data
* ie ?shield=vreinvg3rihviv234rv23vjmosvfe
* => http://www.myhost.com/submit.php?shield=vreinvg3rihviv234rv23vjmosvfe
* SHIELD_PURE_GET - returns a string for in the form var_name=encrypted_value
* ie shield=vreinvg3rihviv234rv23vjmosvfe
* Added by Marc Wöhlken
* SHIELD_INPUT - returns a ready made form input string
* ie <input type="hidden" name="shield" value="vreinvg3rihviv234rv23vjmosvfe" />
* @param string $var_name The name of the value of the return string
* @param string|boolean $digital_sig If you want to use a different digital signature
* other than the default class one, make this the sig string, otherwise
* if false the default signature is used.
* @param integer $time If you wish to create a timeout period for this var then set this to
* the number of milliseconds you want the var to be valid for. If left at '0' then
* no timeout setting will be used.
* @return string
**/
function protect($data, $shield_type=SHIELD_PLAIN, $time=0, $var_name=false, $digital_sig=false)
{
# check to see if class is secure
$this->_check_secure();
# process the data and return
$_d = $this->_process_data($data, $digital_sig, $time, $var_name);
# switch through the shield types
switch($shield_type)
{
# Marc Wöhlken - Added PURE_GET to make it more easy to submit
# encoded and not encoded simultaneously
case SHIELD_PURE_GET :
return $_d['var_name'] . '=' . $_d['data'];
case SHIELD_GET :
# process the data and return
return '?' . $_d['var_name'] . '=' . $_d['data'];
case SHIELD_INPUT :
return '<input type="hidden" name="' . $_d['var_name'] . '" value="' . $_d['data'] . '" />';
case SHIELD_PLAIN :
return $_d['data'];
}
}
/**
* expose
*
* This exposes the data that has been encrypted by the shield class. If required
* it modifies the super global arrays, ie $_GET, $_POST & $_REQUEST. If the data
* is contains the appropriate signature or if a valid time period has been set
* the data is also returned as and array. If the data does not contain a valid
* signature returns SIG_404. If the data contains a validity period and the value
* is being accessed past that period then it returns TIMEOUT
*
* @access public
* @param string|boolean $str The encrypted string to decrypt and validate, or false
* to get it from the $_REQUEST global array.
* @param string $var_name The name of the value of the return string
* @param string $digital_sig If you want to use a different digital signature
* other than the default class one, make this the sig string, otherwise
* if false the default signature is used.
* @param boolean $modify If true, modifies the Super Global Arrays so you can reference
* any data how you would of in the first place, ie $_GET['nextpage'];
* @return array|string
*/
function expose($str=false, $var_name=false, $digital_sig=false, $modify=true)
{
# check to see if class is secure
$this->_check_secure();
# get the var name
$var_name = !$var_name ? $this->VAR_NAME : $var_name;
# check to see if the var exists
if($str === false && !isset($_REQUEST[$var_name])) return $this->ON_ERROR == SHIELD_VERBOSE ? SHIELD_EMPTY : ($this->ON_ERROR == SHIELD_QUIET ? false : $this->_trigger_error('The string to be exposed by the Data Transmission Class contains no data.', true));
# get the data
if($str === false) $_s = $_REQUEST[$var_name];
else $_s = $str;
# run the decryption
$data = $this->_decrypt($_s);
# check for valid digital signature
if($data['_ds'] != (!$digital_sig ? md5($this->_DIR).md5($this->DIGITAL_SIG) : md5($digital_sig)))
{
if($str !== false)
{
unset($_REQUEST[$var_name]);
unset($_POST[$var_name]);
unset($_GET[$var_name]);
}
return $this->ON_ERROR == SHIELD_VERBOSE ? SHIELD_SIG404 : ($this->ON_ERROR == SHIELD_QUIET ? false : $this->_trigger_error('The Data Transmission Shield has not detected a correct digital signature.', true));
}
# check for timeout
if($data['_to'] != -1 && isset($data['_to']) && $data['_to'] < time())
{
if($str !== false)
{
unset($_REQUEST[$var_name]);
unset($_POST[$var_name]);
unset($_GET[$var_name]);
}
return $this->ON_ERROR == SHIELD_VERBOSE ? SHIELD_TIMEOUT : ($this->ON_ERROR == SHIELD_QUIET ? false : $this->_trigger_error('The string protected by the Data Transmission Shield has timed out.', true));
}
# delete the validation data
unset($data['_ds']);
unset($data['_to']);
# check for none array flag
if(isset($data['_f']))
{
# note if data has been flagged then that means the data encrypted was not an array
# thus the data is not returned to the _GET of _POST array but just returned as the value
$data = $data['_d'];
}
else
{
# if the modify is true then it will modify the GET or POST
# super globals
if($modify && $str === false)
{
# modify the global properties
if(isset($_GET[$var_name]))
{
unset($_GET[$var_name]);
$_GET = array_merge($_GET, $data);
}
if(isset($_POST[$var_name]))
{
unset($_POST[$var_name]);
$_POST = array_merge($_POST, $data);
}
# modify the request data
unset($_REQUEST[$var_name]);
$_REQUEST = array_merge($_REQUEST, $data);
# loop through the names for the expunge data
foreach($data as $key=>$value)
{
$this->_VAR_NAMES[] = $key;
}
}
}
# return the data
return $str !== false ? $data : ($this->ON_ERROR == SHIELD_VERBOSE ? SHIELD_OK : true);
}
/**
* expunge
*
* removes the data from the super global arrays
*
* @access public
* @return void
**/
function expunge($make_secure=false)
{
# check there are vars names to delete so no errors are thrown
if(count($this->_VAR_NAMES) > 0)
{
# loop through the properties and remove from global arrays
foreach($this->_VAR_NAMES as $key=>$var_name)
{
if(isset($_GET[$var_name])) unset($_GET[$var_name]);
if(isset($_POST[$var_name])) unset($_POST[$var_name]);
if(isset($_REQUEST[$var_name])) unset($_REQUEST[$var_name]);
}
}
# remove the varnames
unset($this->_VAR_NAMES);
# make the class secure
if($make_secure) $this->make_secure();
}
/**
* create_key_image
*
* Creates the image used by the javascript to enter the correct key for encryption.
* It should be used in a seperate file from the main class as it outputs a png file.
*
* @param integer $character_num The number of charactes the key should have
* @param string $font The path to the font used by the CAPTCHA
* @param integer $fontsize The size of the font used
* @param array $font_rgb The color of the font in the format array('r'=>255,'g'=>0,'b'=>0)
* @param integer $padding The padding between the edge of the image and the text
* @param array $back_rgb The color of the background in the format array('r'=>255,'g'=>0,'b'=>0)
* @param boolean $transparent If the background is transparent or not
*/
function create_key_image($character_num, $font, $fontsize=30, $font_rgb=array('r'=>255,'g'=>0,'b'=>0), $padding=10, $back_rgb=array('r'=>255,'g'=>255,'b'=>255), $transparent=false)
{
# init the vars
$width = 0;
$height = 0;
$offset_x = 0;
$offset_y = 0;
$bounds = array();
$image = "";
# missing 0 and O because they are inditinguishable in some fonts
$str = $this->_generate_random_string($character_num, 'ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789123456789');
# determine font height.
$bounds = ImageTTFBBox($fontsize, 0, $font, "W");
$font_height= abs($bounds[7]-$bounds[1]);
# determine bounding box.
$bounds = ImageTTFBBox($fontsize, 0, $font, $str);
$width = abs($bounds[4]-$bounds[6]);
$height = abs($bounds[7]-$bounds[1]);
$offset_y = $font_height;
$offset_x = 0;
# create the image base
$image = imagecreate($width+($padding*2)+1,$height+($padding*2)+1);
# create the back and fore grounds
$background = ImageColorAllocate($image, $back_rgb['r'], $back_rgb['g'], $back_rgb['b']);
$foreground = ImageColorAllocate($image, $font_rgb['r'], $font_rgb['g'], $font_rgb['b']);
# make transparent if required
if ($transparent) ImageColorTransparent($image, $background);
# compile image
ImageInterlace($image, false);
ImageTTFText($image, $fontsize, 0, $padding, $padding+$font_height, $foreground, $font, $str);
# output key
header('Content-type: image/png');
imagePNG($image);
# init the session vars
$_SESSION['SHIELD_CAPTCHA_KEY'] = $str;
$_SESSION['SHIELD_CAPTCHA_KEY_LENGTH'] = $character_num;
# exit the building
exit;
}
/**
* create_html_elements
*
* Creates html form elements and the includes the nessecary javascript files
*
* @access public
* @param string $form_name The name of the form the elements are residing in
* @param array $form_elements_to_protect An array of element names that require protection
* @param string $form_onsubmit_callback The name of the function to callback on submit if the form
* @return void
*/
function create_html_elements($form_name, $form_elements_to_protect, $form_onsubmit_callback=false)
{
# check for correct algorithm
if($this->POST_ALGORITHM != 'des') $this->ON_ERROR == SHIELD_VERBOSE ? SHIELD_POST_ENCRYPT_ALGORITHM_ERROR : ($this->ON_ERROR == SHIELD_QUIET ? false : $this->_trigger_error('The algorithm used by the Data Transmition Shields Post Encrypt methods must be either set to \'des\'.', true));
# write out the include
echo '<script type="text/javascript" src="shield_js/'.$this->POST_ALGORITHM.'.js"></script>'."\r\n";
echo '<script type="text/javascript" src="shield_js/base64.js"></script>'."\r\n";
# write out the html elements
echo '<input type="text" id="SHIELD_CAPTCHA_KEY" name="SHIELD_CAPTCHA_KEY" value="" maxchars="'.$_SESSION['SHIELD_CAPTCHA_LENGTH'].'" />'."\r\n";
# loop through the elements you want to encrypt
# and add hidden elements
foreach ($form_elements_to_protect as $key=>$name)
{
echo '<input type="hidden" id="'.$this->POST_VAR_NAME.'['.$name.']" name="'.$this->POST_VAR_NAME.'['.$name.']" value="" />'."\r\n";
}
# write out the processing javascript functions
echo '<script type="text/javascript">'."\r\n";
echo ' function hide_from_prying_eyes()'."\r\n";
echo ' {'."\r\n";
# check for a callback and handle appropriatley
if($form_onsubmit_callback == false) echo ' var callback_result = true'."\r\n";
else echo ' var callback_result = '.$form_onsubmit_callback.'()'."\r\n";
# if js callback went ok do the encryption
echo ' if(callback_result)'."\r\n";
echo ' {'."\r\n";
# loop through the elements you want to encrypt
foreach ($form_elements_to_protect as $key=>$name)
{
echo ' // ------------------------'."\r\n";
echo ' var key = document.forms.'.$form_name.'.SHIELD_CAPTCHA_KEY.value;'."\r\n";
echo ' var val = document.forms.'.$form_name.'.'.$name.'.value;'."\r\n";
if($this->POST_ALGORITHM == 'des')
echo ' var enc_val = rfc3548_encode(des (key, serialize({value:val}), 1, 0));'."\r\n";
echo ' document.forms.'.$form_name.'["'.$this->POST_VAR_NAME.'['.$name.']"].value = enc_val;'."\r\n";
echo ' document.forms.'.$form_name.'.'.$name.'.disabled = true;'."\r\n";
}
echo ' document.forms.'.$form_name.'.SHIELD_CAPTCHA_KEY.disabled = true;'."\r\n";
echo ' }'."\r\n";
echo ' else return false;'."\r\n";
echo ' return callback_result && result;'."\r\n";
echo ' }'."\r\n";
echo ' document.forms.'.$form_name.'.onsubmit = hide_from_prying_eyes;';
echo '</script>'."\r\n";
}
/**
* is_form_shielded
*
* Returns true if the $_REQUEST data has data that has been shielded from a form
*
* @return boolean
*/
function is_form_shielded()
{
return isset($_REQUEST[$this->POST_VAR_NAME]);
}
/**
* is_data_shielded
*
* Returns true if the $_REQUEST data has data that has been shielded in the SHIELD_GET format
*
* @return boolean
*/
function is_data_shielded()
{
return isset($_REQUEST[$this->VAR_NAME]);
}
/**
* expose_form
*
* Acts similar to the normal expose function except it exposes data that has been encrypted by javascript
* from inside a form
*
* @param boolean $modify If you wish the GLOBALS to be modified for easy use then true it is.
* @return mixed returns array on success or boolean or defined var on fault
*/
function expose_form($escape=false, $modify=true)
{
# check to see if class is secure
$this->_check_secure();
# check to see if the var exists
if(!isset($_REQUEST[$this->POST_VAR_NAME])) return $this->ON_ERROR == SHIELD_VERBOSE ? SHIELD_EMPTY : ($this->ON_ERROR == SHIELD_QUIET ? false : $this->_trigger_error('The form protected by the Data Transmission Shield sent no data.', true));
# get the data
$_s = $_REQUEST[$this->POST_VAR_NAME];
# close the current mcrypt as it is likely to be the main method of encryption
# don't need to open it up as one will open up when used
$this->_close_shield();
$_data = array();
foreach ($_s as $name=>$value)
{
$data = $this->_decrypt($value, $_SESSION['SHIELD_CAPTCHA_KEY']);
$data[$name] = empty($data) ? SHIELD_POST_INVALID_CAPTCHA : ($escape ? addslashes($data['value']) : $data['value']);
unset($data['value']);
# if the modify is true then it will modify the GET or POST
# super globals
if($modify)
{
# modify the global properties
if(isset($_GET[$name]))
{
unset($_GET[$name]);
$_GET = array_merge($_GET, $data);
}
if(isset($_POST[$name]))
{
unset($_POST[$name]);
$_POST = array_merge($_POST, $data);
}
# modify the request data
unset($_REQUEST[$name]);
$_REQUEST = array_merge($_REQUEST, $data);
# loop through the names for the expunge data
foreach($data as $key=>$value)
{
$this->_VAR_NAMES[] = $key;
}
}
}
# unset session data
unset($_SESSION['SHIELD_CAPTCHA_KEY']);
unset($_SESSION['SHIELD_CAPTCHA_KEY_LENGTH']);
# unset the shield var
unset($_GET[$this->POST_VAR_NAME]);
unset($_POST[$this->POST_VAR_NAME]);
unset($_REQUEST[$this->POST_VAR_NAME]);
# close the post vars
$this->_close_shield();
# return the data
return $str !== false ? $_data : ($this->ON_ERROR == SHIELD_VERBOSE ? SHIELD_OK : true);
}
/**
* make_secure
*
* deletes all class values and makes class void to prevent re-writing of
* a key;
*
* @access public
* @return void
**/
function make_secure()
{
# walkthrough and delete the class vars
foreach(array_keys(get_object_vars($this)) as $value)
{
unset($this->$value);
}
# define that class is secure
define('_SECURE_', 1);
}
/**
* close
*
* public shortcut for closing the mcrypt module
*
* @access public
* @return void
**/
function close()
{
$this->_close_shield();
}
/**
* debug_mcrypt
*
* Displays a table of mycrypt compatability. lifted from http://www.php.net/mcrypt
*
* @access public
* @return void
**/
function debug_mcrypt()
{
$modes = mcrypt_list_modes();
$algorithms = mcrypt_list_algorithms();
echo "<table border=1>";
echo "<tr><td align=center><strong>Algorithm</strong></td align=center><td><strong>Status</strong></td>";
foreach ($modes as $mode) echo "<td align=center><strong>".strtoupper($mode)."</strong></td>";
echo "</tr>";
foreach ($algorithms as $cipher)
{
echo "<tr><td bgcolor=f0f0ff align=left>".strtoupper($cipher)."</td>";
if(mcrypt_module_self_test($cipher)) print "<td bgcolor=green align=center>OK</td>";
else print "<td bgcolor=red align=center>NOT OK</td>";
foreach ($modes as $mode)
{
if($mode == 'stream') $result = "<td bgcolor=gray align=center>NOT TESTED</td>";
else if($this->_mcrypt_test_module_mode($cipher, $mode)) $result = "<td bgcolor=green align=center><strong>OK</strong></td>";
else $result = "<td bgcolor=red align=center>NOT OK</td>";
print $result;
}
echo "</tr>";
}
echo "</table>";
}
/**
* PRIVATE FUNCTIONS
**/
/**
* _mcrypt_test_module_mode
*
* a variant on the example posted in mdecrypt_generic
*
* @access private
* @return void
**/
function _mcrypt_test_module_mode($module, $mode)
{
/* Data */
$plain_text = 'Hello World, Nice Day Today Isn\'t It. '.date('d/M/Y');
/* Open module, and create IV */
$td = @mcrypt_module_open($module, '', $mode, '');
if($td)
{
$key = substr($this->HASH_KEY, 0, mcrypt_enc_get_key_size($td));
$iv_size = @mcrypt_enc_get_iv_size($td);
$iv = @mcrypt_create_iv($iv_size, MCRYPT_RAND);
/* Initialize encryption handle */
if (mcrypt_generic_init($td, $key, $iv) != -1)
{
/* Encrypt data */
$c_t = mcrypt_generic($td, $plain_text);
mcrypt_generic_deinit($td);
// close the module
mcrypt_module_close($td);
/* Reinitialize buffers for decryption */
/* Open module */
$td = mcrypt_module_open($module, '', $mode, '');
$key = substr($key, 0, mcrypt_enc_get_key_size($td));
mcrypt_generic_init($td, $key, $iv);
$p_t = trim(mdecrypt_generic($td, $c_t)); //trim to remove padding
/* Clean up */
mcrypt_generic_end($td);
mcrypt_module_close($td);
}
}
else return false;
return (strncmp($p_t, $plain_text, strlen($plain_text)) == 0);
}
/**
* _open_shield
*
* Opens the Mycrypt module for use and registers a shutdown function to autoclose the module
*
* @access private
* @return void
**/
function _open_shield($form_key=false)
{
if(!$this->_OPEN)
{
$algorithm = $form_key !== false ? $this->POST_ALGORITHM : $this->ALGORITHM;
$mode = $form_key !== false ? $this->POST_MODE : $this->MODE;
$key = $form_key !== false ? $form_key : $this->HASH_KEY;
# typo corrected < thanks to Greg Winterstein
# openup mcrypt
$this->_MODULE_REF = @mcrypt_module_open($algorithm, '', $mode, '');
$iv = @mcrypt_create_iv (@mcrypt_enc_get_iv_size($this->_MODULE_REF), MCRYPT_RAND);
# process the key
$key = substr($key, 0, @mcrypt_enc_get_key_size($this->_MODULE_REF));
# init mcrypt
@mcrypt_generic_init($this->_MODULE_REF, $key, $iv);
# mark as open
$this->_OPEN = true;
}
}
/**
* _close_shield
*
* Closes the Mycrypt open module
*
* @access private
* @return void
**/
function _close_shield()
{
if($this->_OPEN)
{
# mark as closed
$this->_OPEN = false;
# shutdown mcrypt
@mcrypt_generic_deinit($this->_MODULE_REF);
@mcrypt_module_close($this->_MODULE_REF);
}
}
/**
* _process_data
*
* Process the raw data and returns the appropriate var name and encrypted data
*
* @param mixed $data
* @param string $digital_sig
* @param integer $time
* @param mixed $var_name
* @return array
*/
function _process_data($data, $digital_sig, $time, $var_name=false)
{
# process the varname
$_vn = $var_name === false ? $this->VAR_NAME : $var_name;
# do the data retrieval
$data = is_array($data) ? $data : array('_d'=>$data, '_f'=>1);
# add the digital sig
$data['_ds'] = !$digital_sig ? md5($this->_DIR).md5($this->DIGITAL_SIG) : md5($digital_sig);
# add the timeout
$data['_to'] = $time > 0 ? time()+$time : -1;
# return the data
return array('data'=>$this->_encrypt($data), 'var_name'=>$_vn);
}
/**
* _encrypt
*
* encrypts the key
*
* @access private
* @param $src_array array The data array that contains the key data
* @return string Returns the encrypted string
**/
function _encrypt($src_array, $form_key=false)
{
# check to see if class is secure
$this->_check_secure();
# make sure that mcrypt is open
$this->_open_shield($form_key);
# encrypt data
# Use gzip to reduce URL size introduced by Marc Wöhlken
# lib checking added later
$data = $this->_ZLIB && $form_key===false ? gzdeflate(serialize($src_array), 9) : serialize($src_array);
$crypt = @mcrypt_generic($this->_MODULE_REF, $data);
# return the key
# MW. Use RFC 3548 "Base 64 Encoding with URL and Filename
# Safe Alphabet"introduced by Marc Wöhlken
return $this->_rfc3548_encode($crypt);
}
/**
* _decrypt
*
* decrypts the key
*
* @access private
* @param $enc_string string The key string that contains the data
* @return array Returns decrypted array
**/
function _decrypt($enc_string, $form_key=false)
{
# check to see if class is secure
$this->_check_secure();
# make sure that mcrypt is open
$this->_open_shield($form_key);
# Use RFC 3548 "Base 64 Encoding with URL and Filename
# Safe Alphabet" introduced by Marc Wöhlken
$enc_string = $this->_rfc3548_decode($enc_string);
# decrypt the data and return
$decrypt = @mdecrypt_generic($this->_MODULE_REF, $enc_string);
# return the key
# gzip compression added by Marc Wöhlken
# lib checking added later
$decrypt = $this->_ZLIB && $form_key===false ? gzinflate($decrypt) : $decrypt;
return unserialize($decrypt);
}
/**
* _generate_random_string
*
* creates a random string
*
* @access private
* @param integer
* @param string
* @return string
**/
function _generate_random_string($length=10, $seeds=false)
{
$str = '';
$seeds = $seeds == false ? 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789' : $seeds;
$seeds_count = strlen($seeds);
list($usec, $sec) = explode(' ', microtime());
$seed = (float) $sec + ((float) $usec * 100000);
mt_srand($seed);
for ($i = 0; $length > $i; $i++) {
$str .= $seeds{mt_rand(0, $seeds_count - 1)};
}
return $str;
}
/**
* _remove_globals
*
* remove globals if register_globals is on
* borrowed from http://www.phpguru.org/#58
*
* @access private
* @return void
**/
function _remove_globals()
{
if (ini_get('register_globals'))
{
foreach ($_REQUEST as $k => $v)
{
unset($GLOBALS[$k]);
}
}
}
/**
* _remove_magic_quotes
*
* remove magic quotes if magic_quotes_gpc is on
* borrowed from http://www.phpguru.org/#58
*
* @access private
* @return void
**/
function _remove_magic_quotes()
{
if (ini_get('magic_quotes_gpc'))
{
foreach (array('_GET', '_POST', '_COOKIE') as $super)
{
foreach ($GLOBALS[$super] as $k => $v)
{
$GLOBALS[$super][$k] = $this->_stripslashes_r($v);
}
}
}
}
/**
* _stripslashes_r
*
* Recursive stripslashes. array_walk_recursive seems to have great
* trouble with stripslashes().
* borrowed from http://www.phpguru.org/#58
*
* @access private
* @param mixed $str String or array
* @return mixed String or array with slashes removed
**/
function _stripslashes_r($str)
{
if (is_array($str))
{
foreach ($str as $k => $v)
{
$str[$k] = $this->_stripslashes_r($v);
}
return $str;
}
else
{
return stripslashes($str);
}
}
/**
* _trigger_error
*
* triggers an error
*
* @access private
* @param $message string The string to read in the error.
* @param $fatal boolean If true script termination occurs.
* @return void
**/
function _trigger_error($message, $fatal=true)
{
trigger_error("<br /><br /><span style='color: #F00;font-weight: bold;'>".$message."<br /><br /></span>", E_USER_ERROR);
if($fatal) exit;
}
/**
* _validate_algorithm
*
* validates the mcrypt settings
*
* @access private
* @return void
**/
function _validate_algorithm()
{
if(!function_exists('mcrypt_module_open')) $this->_trigger_error("In order to function this script needs to use the PHP Library '<a href='http://www.php.net/mcrypt' target='_blank'>Mcrypt<a/>'. Unfortunately Mcrypt is not present on your PHP installation. Please contact your server administrator for further advice.", true);
if(!in_array($this->ALGORITHM, mcrypt_list_algorithms())) $this->_trigger_error("In order to function this script uses the PHP Library '<a href='http://www.php.net/mcrypt' target='_blank'>Mcrypt<a/>'. Unfortunately Mcrypt whilst present on your PHP installation does not have access to the '".$this->ALGORITHM."' algorithm. Please contact your server administrator for further advice.", true);
if(!in_array($this->MODE, mcrypt_list_modes())) $this->_trigger_error("In order to function this script uses the PHP Library '<a href='http://www.php.net/mcrypt' target='_blank'>Mcrypt<a/>'. Unfortunately Mcrypt whilst present on your PHP installation does not have access to the '".$this->MODE."' mode. Please contact your server administrator for further advice.", true);
}
/**
* _rfc3548_encode
*
* replaces double base64_encoding
* credits to Marc Wöhlken
*
* @access private
* @return void
**/
function _rfc3548_encode($str)
{
return str_replace(array('/', '+'), array('_', '-'), base64_encode($str));
}
/**
* _rfc3548_decode
*
* replaces double base64_decoding
* credits to Marc Wöhlken
*
* @access private
* @return void
**/
function _rfc3548_decode($str)
{
return base64_decode(str_replace(array('_', '-'), array('/', '+'), $str));
}
/**
* _check_secure
*
* checks to see if the class has been made secure
*
* @access private
**/
function _check_secure()
{
if(defined('_SECURE_')) $this->_trigger_error('The Data Transmission Shield has been made secure. This script has been terminated.', true);
}
}
?>