Invision Power Services, Inc. * @copyright (c) Invision Power Services, Inc. * @package Invision Community * @subpackage convert * @since 6 May 2016 */ namespace IPS\convert\Login; /* To prevent PHP errors (extending class does not exist) revealing path */ use function defined; use function ord; use function strlen; use function strpos; use function substr; if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) { header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' ); exit; } /** * Helper class to facilitate private crypt hashing */ class HashCryptPrivate { /** * Private crypt hashing * * @param string $password Password * @param string $setting Settings * @param string $itoa64 Hash-lookup * @return string password hash */ public function hashCryptPrivate( string $password, string $setting, string &$itoa64 ) : string { $output = '*'; // Check for correct hash if ( substr( $setting, 0, 3 ) != '$H$' ) { return $output; } $count_log2 = strpos( $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->_hashEncode64( $hash, 16, $itoa64 ); return $output; } /** * Private function to encode phpBB3 hash * * @param string $input Input * @param int $count Iteration * @param string $itoa64 Hash-lookup * @return string phpbb3 password hash encoded bit */ protected function _hashEncode64( string $input, int $count, string &$itoa64) : string { $output = ''; $i = 0; do { $value = ord( $input[$i++] ); $output .= $itoa64[$value & 0x3f]; if ( $i < $count ) { $value |= ord($input[$i]) << 8; } $output .= $itoa64[($value >> 6) & 0x3f]; if ( $i++ >= $count ) { break; } if ( $i < $count ) { $value |= ord($input[$i]) << 16; } $output .= $itoa64[($value >> 12) & 0x3f]; if ($i++ >= $count) { break; } $output .= $itoa64[($value >> 18) & 0x3f]; } while ( $i < $count ); return $output; } }