Index: branches/2.8.x/CHANGELOG
===================================================================
--- branches/2.8.x/CHANGELOG	(revision 1505)
+++ branches/2.8.x/CHANGELOG	(revision 1506)
@@ -12,6 +12,9 @@
 
 =============================== FEATURES FREEZE ================================
 ----------------------------------- Fixes 2.8.2 --------------------------------
+26 Aug-2011 Build 1506 Werner v.d.Decken(DarkViper)
++ new class PasswordHash
++ new Password-/Hash-generator
 19 Aug-2011 Build 1505 Dietmar Woellbrink (Luisehahne)
 # syntaxfix order::clean()
 19 Aug-2011 Build 1504 Werner v.d.Decken(DarkViper)
Index: branches/2.8.x/wb/admin/interface/version.php
===================================================================
--- branches/2.8.x/wb/admin/interface/version.php	(revision 1505)
+++ branches/2.8.x/wb/admin/interface/version.php	(revision 1506)
@@ -52,4 +52,4 @@
 
 // check if defined to avoid errors during installation (redirect to admin panel fails if PHP error/warnings are enabled)
 if(!defined('VERSION')) define('VERSION', '2.8.2');
-if(!defined('REVISION')) define('REVISION', '1505');
+if(!defined('REVISION')) define('REVISION', '1506');
Index: branches/2.8.x/wb/framework/PasswordHash.php
===================================================================
--- branches/2.8.x/wb/framework/PasswordHash.php	(nonexistent)
+++ branches/2.8.x/wb/framework/PasswordHash.php	(revision 1506)
@@ -0,0 +1,219 @@
+<?php
+/**
+ * @category     Core
+ * @package      Core_security
+ * @author       Werner v.d.Decken
+ * @copyright    ISTeasy-project(http://isteasy.de/)
+ * @license      Creative Commons BY-SA 3.0 http://creativecommons.org/licenses/by-sa/3.0/
+ * @version      $Id$
+ * @filesource   $HeadURL:$
+ * @since        Datei vorhanden seit Release 2.8.2
+ * @lastmodified $Date:$
+ *
+ * this class works with salted md5-hashes with several rounds. 
+ * For backward compatibility it can compare normal md5-hashes also.
+ *
+ * *****************************************************************************
+ * This class is based on the Portable PHP password hashing framework.
+ * Version 0.3 / genuine. Written by Solar Designer <solar at openwall.com>
+ * in 2004-2006 and placed in the public domain. Revised in subsequent years,
+ * still public domain. There's absolutely no warranty.
+ * The homepage URL for this framework is: http://www.openwall.com/phpass/
+ * *****************************************************************************
+ */
+class PasswordHash {
+
+
+	private $_itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+	private $_iterationCountLog2 = 8;
+	private $_portableHashes = true;
+	private $_randomState = '';
+	
+	/**
+	 * @param int $iterationCountLog2 number of iterations as exponent of 2
+	 * @param bool $portableHashes TRUE = use MD5 only | FALSE = automatic
+	 */
+	public function __construct($iterationCountLog2, $portableHashes = true)
+	{
+
+		if ($iterationCountLog2 < 4 || $iterationCountLog2 > 31) {
+			$iterationCountLog2 = 8;
+		}
+		$this->_iterationCountLog2 = $iterationCountLog2;
+		$this->_portableHashes = $portableHashes;
+		$this->_randomState = microtime();
+		if (function_exists('getmypid')) {
+			$this->_randomState .= getmypid();
+		}
+	}
+
+
+	private function _getRandomBytes($count)
+	{
+		$output = '';
+		if (is_readable('/dev/urandom') && ($fh = @fopen('/dev/urandom', 'rb'))) {
+			$output = fread($fh, $count);
+			fclose($fh);
+		}
+		if (strlen($output) < $count) {
+			$output = '';
+			for ($i = 0; $i < $count; $i += 16) {
+				$this->_randomState = md5(microtime() . $this->_randomState);
+				$output .= pack('H*', md5($this->_randomState));
+			}
+			$output = substr($output, 0, $count);
+		}
+		return $output;
+	}
+
+	private function _Encode64($input, $count)
+	{
+		$output = '';
+		$i = 0;
+		do {
+			$value = ord($input[$i++]);
+			$output .= $this->_itoa64[$value & 0x3f];
+			if ($i < $count) {
+				$value |= ord($input[$i]) << 8;
+			}
+			$output .= $this->_itoa64[($value >> 6) & 0x3f];
+			if ($i++ >= $count) { break; }
+			if ($i < $count) {
+				$value |= ord($input[$i]) << 16;
+			}
+			$output .= $this->_itoa64[($value >> 12) & 0x3f];
+			if ($i++ >= $count) { break; }
+			$output .= $this->_itoa64[($value >> 18) & 0x3f];
+		} while ($i < $count);
+		return $output;
+	}
+
+	private function _GenSaltPrivate($input)
+	{
+		$output = '$P$';
+		$output .= $this->_itoa64[min($this->_iterationCountLog2 +
+		                          ((PHP_VERSION >= '5') ? 5 : 3), 30)];
+		$output .= $this->_Encode64($input, 6);
+		return $output;
+	}
+
+	private function _CryptPrivate($password, $setting)
+	{
+		$output = '*0';
+		if (substr($setting, 0, 2) == $output) {
+			$output = '*1';
+		}
+		$id = substr($setting, 0, 3);
+		# We use "$P$", phpBB3 uses "$H$" for the same thing
+		if ($id != '$P$' && $id != '$H$') {
+			return $output;
+		}
+		$count_log2 = strpos($this->_itoa64, $setting[3]);
+		if ($count_log2 < 7 || $count_log2 > 30) {
+			return $output;
+		}
+		$count = 1 << $count_log2;
+		$salt = substr($setting, 4, 8);
+		if (strlen($salt) != 8) {
+			return $output;
+		}
+		# We're kind of forced to use MD5 here since it's the only
+		# cryptographic primitive available in all versions of PHP
+		# currently in use.  To implement our own low-level crypto
+		# in PHP would result in much worse performance and
+		# consequently in lower iteration counts and hashes that are
+		# quicker to crack (by non-PHP code).
+		if (PHP_VERSION >= '5') {
+			$hash = md5($salt . $password, TRUE);
+			do {
+				$hash = md5($hash . $password, TRUE);
+			} while (--$count);
+		} else {
+			$hash = pack('H*', md5($salt . $password));
+			do {
+				$hash = pack('H*', md5($hash . $password));
+			} while (--$count);
+		}
+		$output = substr($setting, 0, 12);
+		$output .= $this->_Encode64($hash, 16);
+		return $output;
+	}
+
+	/**
+	 * calculate the hash from a given password
+	 * @param string $password password as original string
+	 * @return string generated hash | '*' on error
+	 */
+	public function HashPassword($password)
+	{
+		$random = '';
+		if (strlen($random) < 6) {
+			$random = $this->_getRandomBytes(6);
+		}
+		$hash = $this->_CryptPrivate($password, $this->_GenSaltPrivate($random));
+		if (strlen($hash) == 34) {
+			return $hash;
+		}
+		# Returning '*' on error is safe here, but would _not_ be safe
+		# in a crypt(3)-like function used _both_ for generating new
+		# hashes and for validating passwords against existing hashes.
+		return '*';
+	}
+
+	/**
+	 * encodes the password and compare it against the given hash
+	 * @param string $password clear password
+	 * @param string $stored_hash the hash to compare against
+	 * @return bool
+	 */
+	public function CheckPassword($password, $stored_hash)
+	{
+	// compare against a normal, simple md5-hash
+		if(preg_match('/^[0-9a-f]{32}$/i', $stored_hash)) {
+			return md5($password) == $stored_hash;
+		}
+	// compare against a rounded, salted md5-hash
+		$hash = $this->_CryptPrivate($password, $stored_hash);
+		if ($hash[0] == '*') {
+			$hash = crypt($password, $stored_hash);
+		}
+		return $hash == $stored_hash;
+	}
+	/**
+	 * generate a case sensitive mnemonic password including numbers and special chars
+	 * makes no use of lowercase 'l', uppercase 'I', 'O' or number '0'
+	 * @param int $length length of the generated password. default = 8
+	 * @return string
+	 */
+	public static function NewPassword($length = 8)
+	{
+		$chars = array(
+			array('b','c','d','f','g','h','j','k','l','m','n','p','r','s','t','v','w','x','y','z'),
+			array('a','e','i','o','u'),
+			array('!','-','@','_',':','.','+','%','/','*')
+		);
+		$length = ceil($length / 2);
+		$Password = array();
+	// at first fill array alternating with vowels and consonants
+		for($x = 0; $x < $length; $x++) {
+			$char = $chars[0][rand(1000, 10000) % sizeof($chars[0])];
+			$Password[] = $char == 'l' ? 'L' : $char;
+			$Password[] = $chars[1][rand(1000, 10000) % sizeof($chars[1])];
+		}
+	// transform 2 random chars into uppercase
+		for($x = 0; $x < 2; $x++) {
+			$pos = rand(1000, 10000) % sizeof($Password);
+			$Password[$pos] = ($Password[$pos] == 'i' || $Password[$pos] == 'o')
+			                  ? $Password[$pos] : strtoupper($Password[$pos]);
+		}
+	// randomly insert one special char, but not at position 0 or as last char
+		$pos = (rand(1000, 10000) % (sizeof($Password)-2))+1;
+		$Password[$pos] = $chars[2][rand(1000, 10000) % sizeof($chars[2])];
+	// randomly insert a numeric char, between 1 and 9
+		$pos = rand(1000, 10000) % sizeof($Password);
+		$Password[$pos] = (rand(1000, 10000) % 9) + 1;
+
+		return implode($Password);
+	}
+
+} // end of class
Index: branches/2.8.x/wb/pwgen.php
===================================================================
--- branches/2.8.x/wb/pwgen.php	(nonexistent)
+++ branches/2.8.x/wb/pwgen.php	(revision 1506)
@@ -0,0 +1,118 @@
+<?php
+/**
+ * @category     Core
+ * @package      Core_security
+ * @author       Werner v.d.Decken
+ * @copyright    ISTeasy-project(http://isteasy.de/)
+ * @license      Creative Commons BY-SA 3.0 http://creativecommons.org/licenses/by-sa/3.0/
+ * @version      $Id$
+ * @filesource   $HeadURL:$
+ * @since        Datei vorhanden seit Release 2.8.2
+ * @lastmodified $Date:$
+ *
+ * this class works with salted md5-hashes with several rounds. 
+ * For backward compatibility it can compare normal md5-hashes also.
+ *
+ */
+ $path2class = './framework/PasswordHash.php';
+	$newpass = '';
+	$pass    = '';
+	$hash    = '';
+
+	include $path2class;
+	if(!isset($_POST['action']) ) { $_POST['action'] = 'pass'; }
+	if($_POST['action'] == 'hash') {
+		if(isset($_POST['pass']) && trim($_POST['pass']) != '') {
+			$pass = trim($_POST['pass']);
+			$newpass = $pass;
+			$ph = new PasswordHash(12);
+			$hash = $ph->HashPassword($pass);
+		}
+	}else {
+		if(!isset($_POST['length']) ) { $_POST['length'] = 8; }
+		$length = intval($_POST['length']);
+		$newpass = PasswordHash::NewPassword($length);
+		$pass = $newpass;
+	}
+
+?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
+	<head>
+		<title>PWH-Generator v.0.1</title>
+		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+		<meta name="author" content="Werner von der Decken" />
+		<meta name="copyright" content="ISTeasy, W.v.d.Decken" />
+		<meta name="generator" content="ISTeasy - PWH-Generator v.0.1" />
+		<style type="text/css">
+			html { /* Schrifteinstellung für das ganze Dokument */
+				font-family: "Trebuchet MS",Verdana, Arial, Helvetica, sans-serif;
+				font-size: 78%;
+				font-weight: normal;
+				color: #303030;
+				min-height: 100.2%;
+			}
+			body {
+				text-align: center;
+				padding-top: 4em;
+			}
+			.body {
+				width: 40em;
+				margin: auto;
+			}
+			fieldset {
+				padding: 1em 0;
+			}
+			legend {
+				font-size: 1.3em;
+			}
+			input {
+				width: 90%;
+				margin: 0.5em 0;
+				padding: 3px;
+				font-size: 1.2em;
+			}
+			#hash { font-size: 1em; }
+		</style>
+		<script type="text/javascript">
+			function clearHash() {
+				document.genhash.hash.value = "";
+			}
+
+		</script>
+	</head>
+	<body>
+		<div class="body">
+			<h1>PWH-Generator v.0.1</h1>
+			<fieldset>
+				<legend>&nbsp;Password-Generator&nbsp;</legend>
+				<form  method="post" name="genpass" action="">
+					<input type="hidden" name="action" value="pass" />
+					<label for="length">length of password </label>&nbsp;&nbsp;
+					<input type="radio" name="length" value="6">06</input>&nbsp;
+					<input type="radio" name="length" value="8" checked="checked">08</input>&nbsp;
+					<input type="radio" name="length" value="10">10</input>&nbsp;
+					<input type="radio" name="length" value="12">12</input>&nbsp;
+					<input type="radio" name="length" value="14">14</input>&nbsp;
+					<input type="radio" name="length" value="16">16</input>&nbsp;
+					<input type="radio" name="length" value="18">18</input>&nbsp;
+					<input type="radio" name="length" value="20">20</input>&nbsp;<br /><br />
+					<label for="pass">Our password suggestion</label><br />
+					<input type="text" id="pass" name="pass" value="<?php echo $newpass; ?>" readonly="readonly" /><br /><br />
+					<input name="submit" id="submit1" type="submit" value="suggest password" />
+				</form>
+			</fieldset><br /><br />
+			<fieldset>
+				<legend>&nbsp;Hash-Generator&nbsp;</legend>
+				<form  method="post" name="genhash" action="">
+					<input type="hidden" name="action" value="hash" />
+					<label for="pass">Enter Text to hash</label><br />
+					<input type="text" id="pass" name="pass" value="<?php echo $pass; ?>" onkeypress="clearHash();" /><br />
+					<label for="hash">Hash to copy</label><br />
+					<input type="text" id="hash" name="hash" value="<?php echo $hash; ?>" readonly="readonly" /><br /><br />
+					<input name="submit" id="submit0" type="submit" value="calculate hash" />
+				</form>
+			</fieldset>
+		</div>
+	</body>
+</html>
+
