Easy Smeasy Slightly Cheesy Encryption in PHP with Base64 Encoding of the Initialization Vector, Cipher Text, and an MD5 Hashed Sentinel, and the Decryption of Same, with Example Code

Love and miss ya, Douglas.
I bet you were shocked.

This isn’t a tutorial.

If you’ve found this post then I’m guessing you’ve already been trying to use mcrypt in php, and you’re on your fourth cup of coffee, ready to trade up for something stronger.

The code below should output the original text, the encoded cipher text, and then the decrypted text, as follows:

The Hitch-Hiker’s Guide to the Galaxy also mentions alcohol. It says that the best drink in existence is the Pan Galactic Gargle Blaster, the effect of which is like having your brains smashed out with a slice of lemon wrapped round a large gold brick. 

ntpxSD3GoDMISWoNBiYq6w=COcq_Q0daVEx9z6qyHmZefrfBbhSIp-lg9_E76eloLw4S1yjf5SAh-eXd2zXe3N6YQQPI4QDSD4St2J8GVkvAyyj3BdkRI2CUg8OeFXr7CwmEe-up7g9ju8F7uFAUQiOluyptjXikVyplTh0QAV4g08MrNnr0dVwhU6e5hGSxxkJD90FEICgFpHtkKmMwkShaC7v7dAM4QyZUI2NGxLdIRjxe_FHLWrHeX-GsIB7rdCTvJFNkRVeYasvtl8SWVlLqJfP93JcDJGhptWO1mZ0bovQE-m3PQv6E9u0dCLVN_nRgIclX4BnC-EiV45mf397PDFXPksKA_CdNGhFnfFzZw=9f19e23e02ad7abd246e866c1d8d2f0a 

The Hitch-Hiker’s Guide to the Galaxy also mentions alcohol. It says that the best drink in existence is the Pan Galactic Gargle Blaster, the effect of which is like having your brains smashed out with a slice of lemon wrapped round a large gold brick.

The string returned by CRYPT::encrypt() is encoded properly for a URL (if you really want to go that way) and includes the initialization vector and a hash of the original plaintext.

Of course, the original IV is required to decrypt in ECB mode.  It’s safe to send it anywhere, but if you want to be really sneaky you could store the IV in a database and send an identifier for the database row.  Or you could use the hash as a key in the database to find the IV.  OR OR OR you could write the IVs on sticky notes.  There’s plenty of help out there on these web things about encryption and initialization vectors.

The MD5 hash of the key plus the original plaintext is sent along as a fingerprint so the decrypt function can be sure what was decrypted is valid.  Someone can send just a bunch of crap back, or a character could be lost.  Who knows?  No matter what happens, if the text sent to decrypt isn’t exactly what came out of encrypt then the hash will not match (except for one chance in a zillion… look up MD5 sometime).

I hope this helps you!  You can click on function names to bring up the php.net documentation.

<?php
  
// base64url encode/decode from
  // http://www.php.net/manual/en/function.base64-encode.php#103849
  //
  // These are good to have in case you want to put some binary data into
  // a uri.  Thay also remove and return the base64 padding characters (=)

  function base64url_encode($data)
  {
      return 
rtrim(strtr(base64_encode($data), ‘+/’‘-_’), ‘=’);
  }

  function base64url_decode($data)
  {
      return 
base64_decode(str_pad(strtr($data‘-_’‘+/’), strlen($data) % 4‘=’STR_PAD_RIGHT));
  }

  // I wrote this class.  Of course, the mcrypt stuff is from examples
  // on php.net.

  class CRYPT
  
{
      
// TWOFISH accepts a 256-bit key — that’s 32 characters
      
protected static $key ‘ThisisaREALLYSECRETKEY..hi.ho…’;

      public static function encrypt($plaintext)
      {
          
$td mcrypt_module_open(MCRYPT_TWOFISH“”MCRYPT_MODE_ECB“”);
          
$iv mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
          
mcrypt_generic_init($tdCRYPT::$key$iv);
          
$ciphertext mcrypt_generic($td$plaintext);
          
mcrypt_generic_deinit($td);
 
          
// Encode the iv and cipher text, compute an md5 hash
          // Return a string concatenating them between =’s
          
return base64url_encode($iv) . ‘=’ base64url_encode($ciphertext) . ‘=’ md5(CRYPT::$key . $plaintext);
      }

      // Split the string up, decrypt, and then compute the hash on the plaintext
      // the hash has to match what was in the string or the cipher text was not
      // right.
      
public static function decrypt($encodedCiphertext)
      {
          
$parts preg_split(‘/=/’$encodedCiphertext);
          if (
count($parts) != 3) {
              
debug_str(“INVALID encodedCipher in CRYPT::decrypt”);
              return 
null;
          }
          
$iv base64url_decode($parts[0]);
          
$ciphertext base64url_decode($parts[1]);
          
$hash $parts[2];
 
          
$td mcrypt_module_open(MCRYPT_TWOFISH“”MCRYPT_MODE_ECB“”);
          
mcrypt_generic_init($tdCRYPT::$key$iv);
          
$plaintext trim(mdecrypt_generic($td$ciphertext), “”);
          
mcrypt_generic_deinit($td);
 
          if (
$hash !== md5(CRYPT::$key . $plaintext)) {
              debug_str(“Corrupted ciphertext in CRYPT::decrypt”);
              return 
null;
          }
 
          return 
$plaintext;
      }
  }

  $original “The Hitch-Hiker’s Guide to the Galaxy also mentions alcohol. It says that the best drink in existence is the Pan Galactic Gargle Blaster, the effect of which is like having your brains smashed out with a slice of lemon wrapped round a large gold brick.”;
  
$ciphertext CRYPT::encrypt($original);
  
$plaintext CRYPT::decrypt($ciphertext);

  echo “<p>$original</p><p>$ciphertext</p><p>$plaintext</p>”;?>

I used http://www.phpformatter.com/ to create the formatted text.

Here is the above code in plain text.

If this helped you out, or you have a suggestion or correction, would you please comment?


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.