Source for file crypt.php

Documentation is available at crypt.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Platform
  4.  * @subpackage  Crypt
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE
  8.  */
  9.  
  10. defined('JPATH_PLATFORM'or die;
  11.  
  12. /**
  13.  * JCrypt is a Joomla Platform class for handling basic encryption/decryption of data.
  14.  *
  15.  * @package     Joomla.Platform
  16.  * @subpackage  Crypt
  17.  * @since       12.1
  18.  */
  19. class JCrypt
  20. {
  21.     /**
  22.      * @var    JCryptCipher  The encryption cipher object.
  23.      * @since  12.1
  24.      */
  25.     private $_cipher;
  26.  
  27.     /**
  28.      * @var    JCryptKey  The encryption key[/pair)].
  29.      * @since  12.1
  30.      */
  31.     private $_key;
  32.  
  33.     /**
  34.      * Object Constructor takes an optional key to be used for encryption/decryption. If no key is given then the
  35.      * secret word from the configuration object is used.
  36.      *
  37.      * @param   JCryptCipher  $cipher  The encryption cipher object.
  38.      * @param   JCryptKey     $key     The encryption key[/pair)].
  39.      *
  40.      * @since   12.1
  41.      */
  42.     public function __construct(JCryptCipher $cipher nullJCryptKey $key null)
  43.     {
  44.         // Set the encryption key[/pair)].
  45.         $this->_key $key;
  46.  
  47.         // Set the encryption cipher.
  48.         $this->_cipher = isset($cipher$cipher new JCryptCipherSimple;
  49.     }
  50.  
  51.     /**
  52.      * Method to decrypt a data string.
  53.      *
  54.      * @param   string  $data  The encrypted string to decrypt.
  55.      *
  56.      * @return  string  The decrypted data string.
  57.      *
  58.      * @since   12.1
  59.      * @throws  InvalidArgumentException
  60.      */
  61.     public function decrypt($data)
  62.     {
  63.         try
  64.         {
  65.             return $this->_cipher->decrypt($data$this->_key);
  66.         }
  67.         catch (InvalidArgumentException $e)
  68.         {
  69.             return false;
  70.         }
  71.     }
  72.  
  73.     /**
  74.      * Method to encrypt a data string.
  75.      *
  76.      * @param   string  $data  The data string to encrypt.
  77.      *
  78.      * @return  string  The encrypted data string.
  79.      *
  80.      * @since   12.1
  81.      */
  82.     public function encrypt($data)
  83.     {
  84.         return $this->_cipher->encrypt($data$this->_key);
  85.     }
  86.  
  87.     /**
  88.      * Method to generate a new encryption key[/pair] object.
  89.      *
  90.      * @param   array  $options  Key generation options.
  91.      *
  92.      * @return  JCryptKey 
  93.      *
  94.      * @since   12.1
  95.      */
  96.     public function generateKey(array $options array())
  97.     {
  98.         return $this->_cipher->generateKey($options);
  99.     }
  100.  
  101.     /**
  102.      * Method to set the encryption key[/pair] object.
  103.      *
  104.      * @param   JCryptKey  $key  The key object to set.
  105.      *
  106.      * @return  JCrypt 
  107.      *
  108.      * @since   12.1
  109.      */
  110.     public function setKey(JCryptKey $key)
  111.     {
  112.         $this->_key $key;
  113.  
  114.         return $this;
  115.     }
  116.  
  117.     /**
  118.      * Generate random bytes.
  119.      *
  120.      * @param   integer  $length  Length of the random data to generate
  121.      *
  122.      * @return  string  Random binary data
  123.      *
  124.      * @since  12.1
  125.      */
  126.     public static function genRandomBytes($length 16)
  127.     {
  128.         $length = (int) $length;
  129.         $sslStr '';
  130.  
  131.         /*
  132.          * If a secure randomness generator exists and we don't
  133.          * have a buggy PHP version use it.
  134.          */
  135.         if (function_exists('openssl_random_pseudo_bytes')
  136.             && (version_compare(PHP_VERSION'5.3.4'>= || IS_WIN))
  137.         {
  138.             $sslStr openssl_random_pseudo_bytes($length$strong);
  139.  
  140.             if ($strong)
  141.             {
  142.                 return $sslStr;
  143.             }
  144.         }
  145.  
  146.         /*
  147.          * Collect any entropy available in the system along with a number
  148.          * of time measurements of operating system randomness.
  149.          */
  150.         $bitsPerRound 2;
  151.         $maxTimeMicro 400;
  152.         $shaHashLength 20;
  153.         $randomStr '';
  154.         $total $length;
  155.  
  156.         // Check if we can use /dev/urandom.
  157.         $urandom false;
  158.         $handle null;
  159.  
  160.         // This is PHP 5.3.3 and up
  161.         if (function_exists('stream_set_read_buffer'&& @is_readable('/dev/urandom'))
  162.         {
  163.             $handle @fopen('/dev/urandom''rb');
  164.  
  165.             if ($handle)
  166.             {
  167.                 $urandom true;
  168.             }
  169.         }
  170.  
  171.         while ($length strlen($randomStr))
  172.         {
  173.             $bytes ($total $shaHashLength)$shaHashLength $total;
  174.             $total -= $bytes;
  175.  
  176.             /*
  177.              * Collect any entropy available from the PHP system and filesystem.
  178.              * If we have ssl data that isn't strong, we use it once.
  179.              */
  180.             $entropy rand(uniqid(mt_rand()true$sslStr;
  181.             $entropy .= implode(''@fstat(fopen(__FILE__'r')));
  182.             $entropy .= memory_get_usage();
  183.             $sslStr '';
  184.  
  185.             if ($urandom)
  186.             {
  187.                 stream_set_read_buffer($handle0);
  188.                 $entropy .= @fread($handle$bytes);
  189.             }
  190.             else
  191.             {
  192.                 /*
  193.                  * There is no external source of entropy so we repeat calls
  194.                  * to mt_rand until we are assured there's real randomness in
  195.                  * the result.
  196.                  *
  197.                  * Measure the time that the operations will take on average.
  198.                  */
  199.                 $samples 3;
  200.                 $duration 0;
  201.  
  202.                 for ($pass 0$pass $samples++$pass)
  203.                 {
  204.                     $microStart microtime(true1000000;
  205.                     $hash sha1(mt_rand()true);
  206.  
  207.                     for ($count 0$count 50++$count)
  208.                     {
  209.                         $hash sha1($hashtrue);
  210.                     }
  211.  
  212.                     $microEnd microtime(true1000000;
  213.                     $entropy .= $microStart $microEnd;
  214.  
  215.                     if ($microStart >= $microEnd)
  216.                     {
  217.                         $microEnd += 1000000;
  218.                     }
  219.  
  220.                     $duration += $microEnd $microStart;
  221.                 }
  222.  
  223.                 $duration $duration $samples;
  224.  
  225.                 /*
  226.                  * Based on the average time, determine the total rounds so that
  227.                  * the total running time is bounded to a reasonable number.
  228.                  */
  229.                 $rounds = (int) (($maxTimeMicro $duration50);
  230.  
  231.                 /*
  232.                  * Take additional measurements. On average we can expect
  233.                  * at least $bitsPerRound bits of entropy from each measurement.
  234.                  */
  235.                 $iter $bytes * (int) ceil($bitsPerRound);
  236.  
  237.                 for ($pass 0$pass $iter++$pass)
  238.                 {
  239.                     $microStart microtime(true);
  240.                     $hash sha1(mt_rand()true);
  241.  
  242.                     for ($count 0$count $rounds++$count)
  243.                     {
  244.                         $hash sha1($hashtrue);
  245.                     }
  246.  
  247.                     $entropy .= $microStart microtime(true);
  248.                 }
  249.             }
  250.  
  251.             $randomStr .= sha1($entropytrue);
  252.         }
  253.  
  254.         if ($urandom)
  255.         {
  256.             @fclose($handle);
  257.         }
  258.  
  259.         return substr($randomStr0$length);
  260.     }
  261.  
  262.     /**
  263.      * A timing safe comparison method. This defeats hacking
  264.      * attempts that use timing based attack vectors.
  265.      *
  266.      * @param   string  $known    A known string to check against.
  267.      * @param   string  $unknown  An unknown string to check.
  268.      *
  269.      * @return  boolean  True if the two strings are exactly the same.
  270.      *
  271.      * @since   3.2
  272.      */
  273.     public static function timingSafeCompare($known$unknown)
  274.     {
  275.         // Prevent issues if string length is 0
  276.         $known .= chr(0);
  277.         $unknown .= chr(0);
  278.  
  279.         $knownLength strlen($known);
  280.         $unknownLength strlen($unknown);
  281.  
  282.         // Set the result to the difference between the lengths
  283.         $result $knownLength $unknownLength;
  284.  
  285.         // Note that we ALWAYS iterate over the user-supplied length to prevent leaking length info.
  286.         for ($i 0$i $unknownLength$i++)
  287.         {
  288.             // Using % here is a trick to prevent notices. It's safe, since if the lengths are different, $result is already non-0
  289.             $result |= (ord($known[$i $knownLength]ord($unknown[$i]));
  290.         }
  291.  
  292.         // They are only identical strings if $result is exactly 0...
  293.         return $result === 0;
  294.     }
  295.  
  296.     /**
  297.      * Tests for the availability of updated crypt().
  298.      * Based on a method by Anthony Ferrera
  299.      *
  300.      * @return  boolean  True if updated crypt() is available.
  301.      *
  302.      * @note    To be removed when PHP 5.3.7 or higher is the minimum supported version.
  303.      * @see     https://github.com/ircmaxell/password_compat/blob/master/version-test.php
  304.      * @since   3.2
  305.      */
  306.     public static function hasStrongPasswordSupport()
  307.     {
  308.         static $pass null;
  309.  
  310.         if (is_null($pass))
  311.         {
  312.             // Check to see whether crypt() is supported.
  313.             if (version_compare(PHP_VERSION'5.3.7''>='=== true)
  314.             {
  315.                 // We have safe PHP version.
  316.                 $pass true;
  317.             }
  318.             else
  319.             {
  320.                 // We need to test if we have patched PHP version.
  321.                 jimport('compat.password.lib.version_test');
  322.                 $test new version_test;
  323.                 $pass $test->version_test();
  324.             }
  325.  
  326.             if ($pass && !defined('PASSWORD_DEFAULT'))
  327.             {
  328.                 // Always make sure that the password hashing API has been defined.
  329.                 include_once JPATH_ROOT '/libraries/compat/password/lib/password.php';
  330.             }
  331.         }
  332.  
  333.         return $pass;
  334.     }
  335. }

Documentation generated on Tue, 19 Nov 2013 14:57:39 +0100 by phpDocumentor 1.4.3