Advertisement
Guest User

PHP Encryption class

a guest
Oct 17th, 2012
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 5.71 KB | None | 0 0
  1. <?php
  2. /**
  3.  * A class to handle secure encryption and decryption of arbitrary data
  4.  *
  5.  * Note that this is not just straight encryption.  It also has a few other
  6.  *  features in it to make the encrypted data far more secure.  Note that any
  7.  *  other implementations used to decrypt data will have to do the same exact
  8.  *  operations.  
  9.  *
  10.  * Security Benefits:
  11.  *
  12.  * - Uses Key stretching
  13.  * - Hides the Initialization Vector
  14.  * - Does HMAC verification of source data
  15.  *
  16.  */
  17. class Encryption {
  18.  
  19.     /**
  20.      * @var string $cipher The mcrypt cipher to use for this instance
  21.      */
  22.     protected $cipher = '';
  23.  
  24.     /**
  25.      * @var int $mode The mcrypt cipher mode to use
  26.      */
  27.     protected $mode = '';
  28.  
  29.     /**
  30.      * Constructor!
  31.      *
  32.      * @param string $cipher The MCRYPT_* cypher to use for this instance
  33.      * @param int    $mode   The MCRYPT_MODE_* mode to use for this instance
  34.      */
  35.     public function __construct($cipher = MCRYPT_BLOWFISH, $mode = MCRYPT_MODE_CBC) {
  36.         $this->cipher = $cipher;
  37.         $this->mode = $mode;
  38.     }
  39.  
  40.     /**
  41.      * Decrypt the data with the provided key
  42.      *
  43.      * @param string $data The encrypted datat to decrypt
  44.      * @param string $key  The key to use for decryption
  45.      *
  46.      * @returns string|false The returned string if decryption is successful
  47.      *                           false if it is not
  48.      */
  49.     public function decrypt($data, $key) {
  50.         $key = $this->stretch($key);
  51.         $iv = $this->getIv($data, $key);
  52.         if ($iv === false) {
  53.             return false; //Invalid IV, so we can't continue
  54.         }
  55.         $de = mcrypt_decrypt($this->cipher, $key, $data, $this->mode, $iv);
  56.         if (!$de || strpos($de, ':') === false) return false;
  57.  
  58.         list ($hmac, $data) = explode(':', $de, 2);
  59.         $data = rtrim($data, "\0");
  60.  
  61.         if ($hmac != hash_hmac('sha1', $data, $key)) {
  62.             return false;
  63.         }
  64.         return $data;
  65.     }
  66.  
  67.     /**
  68.      * Encrypt the supplied data using the supplied key
  69.      *
  70.      * @param string $data The data to encrypt
  71.      * @param string $key  The key to encrypt with
  72.      *
  73.      * @returns string The encrypted data
  74.      */
  75.     public function encrypt($data, $key) {
  76.         $key = $this->stretch($key);
  77.         $data = hash_hmac('sha1', $data, $key) . ':' . $data;
  78.  
  79.         $iv = $this->generateIv();
  80.         $enc = mcrypt_encrypt($this->cipher, $key, $data, $this->mode, $iv);
  81.  
  82.         return $this->storeIv($enc, $iv, $key);
  83.     }
  84.  
  85.     /**
  86.      * Generate an Initialization Vector based upon the class's cypher and mode
  87.      *
  88.      * @returns string The initialization vector
  89.      */
  90.     protected function generateIv() {
  91.         $size = mcrypt_get_iv_size($this->cipher, $this->mode);
  92.         return mcrypt_create_iv($size, MCRYPT_RAND);
  93.     }
  94.  
  95.     /**
  96.      * Extract a stored initialization vector from an encrypted string
  97.      *
  98.      * This will shorten the $data pramater by the removed vector length.
  99.      *
  100.      * @see Encryption::storeIv()
  101.      *
  102.      * @param string &$data The encrypted string to process.
  103.      * @param string $key   The supplied key to extract the IV with
  104.      *
  105.      * @returns string The initialization vector that was stored
  106.      */
  107.     protected function getIv(&$data, $key) {
  108.         $size = mcrypt_get_iv_size($this->cipher, $this->mode);
  109.         $iv = '';
  110.         for ($i = $size - 1; $i >= 0; $i--) {
  111.             $pos = hexdec($key[$i]);
  112.             $iv = substr($data, $pos, 1) . $iv;
  113.             $data = substr_replace($data, '', $pos, 1);
  114.         }
  115.         if (strlen($iv) != $size) {
  116.             return false;
  117.         }
  118.         return $iv;
  119.     }
  120.  
  121.     /**
  122.      * Store the Initialization Vector inside the encrypted string.
  123.      *
  124.      * We will need the IV later to decrypt the data, so we need to
  125.      * make it available.  We don't want to just append it, since that
  126.      * could open MITM style attacks on the data.  So we'll hide it
  127.      * using the key to determine exactly how to hide it.  That way,
  128.      * without knowing the key, it should be impossible to get the IV.
  129.      *
  130.      * @param string $data The data to hide the IV within
  131.      * @param string $iv   The IV to hide
  132.      * @param string $key  The key to use to hide the IV with
  133.      *
  134.      * @returns string The $data parameter with the hidden IV
  135.      */
  136.     protected function storeIv($data, $iv, $key) {
  137.         for ($i = 0; $i < strlen($iv); $i++) {
  138.             $offset = hexdec($key[$i]);
  139.             $data = substr_replace($data, $iv[$i], $offset, 0);
  140.         }
  141.         return $data;
  142.     }
  143.  
  144.     /**
  145.      * Stretch the key using a simple hmac based stretching algorythm
  146.      *
  147.      * We want to use sha1 here over something stronger since Blowfish
  148.      * expects a key between 4 and 56 bytes.  Sha1 produces a 40 byte
  149.      * hash, so it should be good for these purposes.  This also allows
  150.      * an arbitrary key of any length to be used for encryption.
  151.      *
  152.      * Another benefit of streching the kye is that it actually slows
  153.      * down any potential brute force attacks.
  154.      *
  155.      * We use 5000 runs for the stretching since it's a good balance
  156.      * between brute force protection and system load.  We could increase
  157.      * this if we were paranoid, but it shouldn't be necessary.
  158.      *
  159.      * @see http://en.wikipedia.org/wiki/Key_stretching
  160.      *
  161.      * @param string $key The key to stretch
  162.      *
  163.      * @returns string A 40 character hex string with the stretched key
  164.      */
  165.     protected function stretch($key) {
  166.         $hash = sha1($key);
  167.         $runs = 0;
  168.         do {
  169.             $hash = hash_hmac('sha1', $hash, $key);
  170.         } while ($runs++ < 5000);
  171.         return $hash;
  172.     }
  173.  
  174. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement