diff options
| author | Silvio Rhatto <rhatto@riseup.net> | 2014-03-14 21:25:01 -0300 | 
|---|---|---|
| committer | Silvio Rhatto <rhatto@riseup.net> | 2014-03-14 21:25:01 -0300 | 
| commit | 3651c99a195685f3a868e159e72c4daf8cb371d3 (patch) | |
| tree | cb004dd7b6ca55215a2c20112fe0c5209d98c18e /engine/classes/ElggCrypto.php | |
| parent | 97e689213ff4e829f251af526ed4e796a3cc2b71 (diff) | |
| parent | c2707bb867ddb285af85d7a0e75db26ef692d68c (diff) | |
| download | elgg-3651c99a195685f3a868e159e72c4daf8cb371d3.tar.gz elgg-3651c99a195685f3a868e159e72c4daf8cb371d3.tar.bz2 | |
Merge branch 'master' into saravea
Conflicts:
	mod/blog/views/default/blog/sidebar/archives.php
Diffstat (limited to 'engine/classes/ElggCrypto.php')
| -rw-r--r-- | engine/classes/ElggCrypto.php | 208 | 
1 files changed, 208 insertions, 0 deletions
| diff --git a/engine/classes/ElggCrypto.php b/engine/classes/ElggCrypto.php new file mode 100644 index 000000000..317d371e4 --- /dev/null +++ b/engine/classes/ElggCrypto.php @@ -0,0 +1,208 @@ +<?php +/** + * ElggCrypto + * + * @package    Elgg.Core + * @subpackage Crypto + * + * @access private + */ +class ElggCrypto { + +	/** +	 * Character set for temp passwords (no risk of embedded profanity/glyphs that look similar) +	 */ +	const CHARS_PASSWORD = 'bcdfghjklmnpqrstvwxyz2346789'; + +	/** +	 * Generate a string of highly randomized bytes (over the full 8-bit range). +	 * +	 * @param int $length Number of bytes needed +	 * @return string Random bytes +	 * +	 * @author George Argyros <argyros.george@gmail.com> +	 * @copyright 2012, George Argyros. All rights reserved. +	 * @license Modified BSD +	 * @link https://github.com/GeorgeArgyros/Secure-random-bytes-in-PHP/blob/master/srand.php Original +	 * +	 * Redistribution and use in source and binary forms, with or without +	 * modification, are permitted provided that the following conditions are met: +	 *    * Redistributions of source code must retain the above copyright +	 *      notice, this list of conditions and the following disclaimer. +	 *    * Redistributions in binary form must reproduce the above copyright +	 *      notice, this list of conditions and the following disclaimer in the +	 *      documentation and/or other materials provided with the distribution. +	 *    * Neither the name of the <organization> nor the +	 *      names of its contributors may be used to endorse or promote products +	 *      derived from this software without specific prior written permission. +	 * +	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +	 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +	 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +	 * DISCLAIMED. IN NO EVENT SHALL GEORGE ARGYROS BE LIABLE FOR ANY +	 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +	 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +	 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +	 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +	 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +	 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +	 */ +	public function getRandomBytes($length) { +		/** +		 * Our primary choice for a cryptographic strong randomness function is +		 * openssl_random_pseudo_bytes. +		 */ +		$SSLstr = '4'; // http://xkcd.com/221/ +		if (function_exists('openssl_random_pseudo_bytes') +				&& (version_compare(PHP_VERSION, '5.3.4') >= 0 || substr(PHP_OS, 0, 3) !== 'WIN')) { +			$SSLstr = openssl_random_pseudo_bytes($length, $strong); +			if ($strong) { +				return $SSLstr; +			} +		} + +		/** +		 * If mcrypt extension is available then we use it to gather entropy from +		 * the operating system's PRNG. This is better than reading /dev/urandom +		 * directly since it avoids reading larger blocks of data than needed. +		 * Older versions of mcrypt_create_iv may be broken or take too much time +		 * to finish so we only use this function with PHP 5.3.7 and above. +		 * @see https://bugs.php.net/bug.php?id=55169 +		 */ +		if (function_exists('mcrypt_create_iv') +				&& (version_compare(PHP_VERSION, '5.3.7') >= 0 || substr(PHP_OS, 0, 3) !== 'WIN')) { +			$str = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); +			if ($str !== false) { +				return $str; +			} +		} + +		/** +		 * No build-in crypto randomness function found. We collect any entropy +		 * available in the PHP core PRNGs along with some filesystem info and memory +		 * stats. To make this data cryptographically strong we add data either from +		 * /dev/urandom or if its unavailable, we gather entropy by measuring the +		 * time needed to compute a number of SHA-1 hashes. +		 */ +		$str = ''; +		$bits_per_round = 2; // bits of entropy collected in each clock drift round +		$msec_per_round = 400; // expected running time of each round in microseconds +		$hash_len = 20; // SHA-1 Hash length +		$total = $length; // total bytes of entropy to collect + +		$handle = @fopen('/dev/urandom', 'rb'); +		if ($handle && function_exists('stream_set_read_buffer')) { +			@stream_set_read_buffer($handle, 0); +		} + +		do { +			$bytes = ($total > $hash_len) ? $hash_len : $total; +			$total -= $bytes; + +			//collect any entropy available from the PHP system and filesystem +			$entropy = rand() . uniqid(mt_rand(), true) . $SSLstr; +			$entropy .= implode('', @fstat(@fopen(__FILE__, 'r'))); +			$entropy .= memory_get_usage() . getmypid(); +			$entropy .= serialize($_ENV) . serialize($_SERVER); +			if (function_exists('posix_times')) { +				$entropy .= serialize(posix_times()); +			} +			if (function_exists('zend_thread_id')) { +				$entropy .= zend_thread_id(); +			} + +			if ($handle) { +				$entropy .= @fread($handle, $bytes); +			} else { +				// Measure the time that the operations will take on average +				for ($i = 0; $i < 3; $i++) { +					$c1 = microtime(true); +					$var = sha1(mt_rand()); +					for ($j = 0; $j < 50; $j++) { +						$var = sha1($var); +					} +					$c2 = microtime(true); +					$entropy .= $c1 . $c2; +				} + +				// Based on the above measurement determine the total rounds +				// in order to bound the total running time. +				$rounds = (int) ($msec_per_round * 50 / (int) (($c2 - $c1) * 1000000)); + +				// Take the additional measurements. On average we can expect +				// at least $bits_per_round bits of entropy from each measurement. +				$iter = $bytes * (int) (ceil(8 / $bits_per_round)); + +				for ($i = 0; $i < $iter; $i++) { +					$c1 = microtime(); +					$var = sha1(mt_rand()); +					for ($j = 0; $j < $rounds; $j++) { +						$var = sha1($var); +					} +					$c2 = microtime(); +					$entropy .= $c1 . $c2; +				} +			} + +			// We assume sha1 is a deterministic extractor for the $entropy variable. +			$str .= sha1($entropy, true); + +		} while ($length > strlen($str)); + +		if ($handle) { +			@fclose($handle); +		} + +		return substr($str, 0, $length); +	} + +	/** +	 * Generate a random string of specified length. +	 * +	 * Uses supplied character list for generating the new string. +	 * If no character list provided - uses Base64 URL character set. +	 * +	 * @param int         $length Desired length of the string +	 * @param string|null $chars  Characters to be chosen from randomly. If not given, the Base64 URL +	 *                            charset will be used. +	 * +	 * @return string The random string +	 * +	 * @throws InvalidArgumentException +	 * +	 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) +	 * @license   http://framework.zend.com/license/new-bsd New BSD License +	 * +	 * @see https://github.com/zendframework/zf2/blob/master/library/Zend/Math/Rand.php#L179 +	 */ +	public static function getRandomString($length, $chars = null) { +		if ($length < 1) { +			throw new InvalidArgumentException('Length should be >= 1'); +		} + +		if (empty($chars)) { +			$numBytes = ceil($length * 0.75); +			$bytes    = self::getRandomBytes($numBytes); +			$string = substr(rtrim(base64_encode($bytes), '='), 0, $length); + +			// Base64 URL +			return strtr($string, '+/', '-_'); +		} + +		$listLen = strlen($chars); + +		if ($listLen == 1) { +			return str_repeat($chars, $length); +		} + +		$bytes  = self::getRandomBytes($length); +		$pos    = 0; +		$result = ''; +		for ($i = 0; $i < $length; $i++) { +			$pos     = ($pos + ord($bytes[$i])) % $listLen; +			$result .= $chars[$pos]; +		} + +		return $result; +	} +} | 
