Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6121413
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 23, 20262026-05-23T15:46:52+00:00 2026-05-23T15:46:52+00:00

Recently I have started implementing a solution which will use a PhPbb database for

  • 0

Recently I have started implementing a solution which will use a PhPbb database for forms authorization, I have used the class from this below thread:

PhPbb C# Authentication Port

So i wrote a membership provider using this class in the ‘ValidateUser’ function:

public override bool ValidateUser(string username, string password)
    {
        ForumsDataContext db = Root.ForumsDataContext;
        PhPbbCryptoServiceProvider phpbbCrypt = new PhPbbCryptoServiceProvider();
        string remoteHash = db.Users.Where(u => u.UserName == username).FirstOrDefault().UserPassword;
        if (String.IsNullOrEmpty(remoteHash))
            return false;
        return phpbbCrypt.phpbbCheckHash(password, remoteHash);
    }

However this always returns false as the ‘phpbbCrypt.phpbbCheckHash’ returns false and I do not know enough about PhPbb to determine why the hashes are not matching up.

Any sugestions?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-23T15:46:53+00:00Added an answer on May 23, 2026 at 3:46 pm

    If you upgraded your phpbb install from 2.0 the password hashing function is different. I took this snippet from functions.php in phpbb (See: GitHub) this is the entire password checking and hashing functions with a little bit at the end to output a phpbb hashed password.

    <?php
      function _hash_encode64($input, $count, &$itoa64)
      {
          $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;
      }
      function _hash_crypt_private($password, $setting, &$itoa64)
      {
          $output = '*';
    
          // Check for correct hash
          if (substr($setting, 0, 3) != '$H$' && substr($setting, 0, 3) != '$P$') {
              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).
           */
          $hash = md5($salt . $password, true);
          do {
              $hash = md5($hash . $password, true);
          } while (--$count);
    
          $output = substr($setting, 0, 12);
          $output .= _hash_encode64($hash, 16, $itoa64);
    
          return $output;
      }
    
      function phpbb_hash($password)
      {
          $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    
          $random_state = unique_id();
          $random = '';
          $count = 6;
    
          if (($fh = @fopen('/dev/urandom', 'rb'))) {
              $random = fread($fh, $count);
              fclose($fh);
          }
    
          if (strlen($random) < $count) {
              $random = '';
    
              for ($i = 0; $i < $count; $i += 16) {
                  $random_state = md5(unique_id() . $random_state);
                  $random .= pack('H*', md5($random_state));
              }
              $random = substr($random, 0, $count);
          }
    
          $hash = _hash_crypt_private($password, _hash_gensalt_private($random, $itoa64), $itoa64);
    
          if (strlen($hash) == 34) {
              return $hash;
          }
    
          return md5($password);
      }
      /**
       * * Generate salt for hash generation
       * */
      function _hash_gensalt_private($input, &$itoa64, $iteration_count_log2 = 6)
      {
          if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) {
              $iteration_count_log2 = 8;
          }
    
          $output = '$H$';
          $output .= $itoa64[min($iteration_count_log2 + 5, 30)];
          $output .= _hash_encode64($input, 6, $itoa64);
    
          return $output;
      }
      /**
       * * Return unique id
       * * @param string $extra additional entropy
       * */
      function unique_id($extra = 'c')
      {
          static $dss_seeded = false;
          global $config;
    
          $val = $config['rand_seed'] . microtime();
          $val = md5($val);
          $config['rand_seed'] = md5($config['rand_seed'] . $val . $extra);
          return substr($val, 4, 16);
      }
      function phpbb_check_hash($password, $hash)
      {
          $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
          if (strlen($hash) == 34) {
              return(_hash_crypt_private($password, $hash, $itoa64) === $hash) ? true : false;
          }
    
          return(md5($password) === $hash) ? true : false;
      }
      $toHash = "";
      if (!empty($argc) && $argc >= 2) {
          $toHash = $argv[1];
      }
      $hashed = phpbb_hash("a");
      //To Check: $checked2 = phpbb_check_hash("q1w2e3", '$H$9uAiKWrdcDomn7FEqujoPLYuBXvkzV0');
      echo "Hashing password '" . $toHash . "'\n";
      echo "Hash: " . $hashed . "\n";
      echo "Hash (MD5): " . md5($toHash) . "\n";
    ?>
    

    Important part here is that it isn’t a straight MD5. I took the C# class from the link the OP provided and made this test class.

    [TestFixture]
    public class phpBBHashTestFixture
    {
        [Test]
        public void TestCanVerifyPhpBBPassword()
        {
            var cryptoService = new phpBBCryptoServiceProvider();
            Assert.That(cryptoService.phpbbCheckHash("a", "$H$9AE1X.4z5hqGj/RVdvzuYjxsJdMeFs."), Is.True);
            Assert.That(cryptoService.phpbbCheckHash("q1w2e3", "$H$9uAiKWrdcDomn7FEqujoPLYuBXvkzV0"), Is.True);
        }
    }
    

    This is a modified copy of the class in the OP question. This will check older passwords which were just an MD5 hash of the plaintext password without a salt and i also added in the prefix “$P$” to be allowed.

    /// <summary>
    ///   Computes the phpBB/SubMD5 hash value for the input data using the implementation provided by http://openwall.com/phpass/ modified by http://www.phpbb.com/.
    /// </summary>
    /// <remarks>
    ///   Ported by Ryan Irecki
    ///   Website: http://www.digilitepc.net/
    ///   E-mail: razchek@gmail.com
    /// </remarks>
    public class phpBBCryptoServiceProvider
    {
        /// <summary>
        ///   The encryption string base.
        /// </summary>
        private string itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    
        /// <summary>
        ///   Compares the password string given with the hash retrieved from your database.
        /// </summary>
        /// <param name = "password">Plaintext password.</param>
        /// <param name = "hash">Hash from a SQL database</param>
        /// <returns>True if the password is correct, False otherwise.</returns>
        public bool phpbbCheckHash(string password, string hash)
        {
            if (hash.Length == 34)
            {
                return (this.hashCryptPrivate(Encoding.ASCII.GetBytes(password), hash, this.itoa64) == hash);
            }
    
            return this.sMD5(password, false) == hash.ToUpper();
        }
    
        /// <summary>
        ///   This function will return the resulting hash from the password string you specify.
        /// </summary>
        /// <param name = "password">String to hash.</param>
        /// <returns>Encrypted hash.</returns>
        /// <remarks>
        ///   Although this will return the md5 for an older password, I have not added
        ///   support for older passwords, so they will not work with this class unless
        ///   I or someone else updates it.
        /// </remarks>
        public string phpbb_hash(string password)
        {
            // Generate a random string from a random number with the length of 6.
            // You could use a static string instead, doesn't matter. E.g.
            // byte[] random = ASCIIEncoding.ASCII.GetBytes("abc123");
            var random = Encoding.ASCII.GetBytes(new Random().Next(100000, 999999).ToString());
    
            var hash = this.hashCryptPrivate(Encoding.ASCII.GetBytes(password), this.hashGensaltPrivate(random, this.itoa64), this.itoa64);
    
            if (hash.Length == 34)
            {
                return hash;
            }
    
            return this.sMD5(password);
        }
    
        /// <summary>
        ///   The workhorse that encrypts your hash.
        /// </summary>
        /// <param name = "password">String to be encrypted. Use: ASCIIEncoding.ASCII.GetBytes();</param>
        /// <param name = "genSalt">Generated salt.</param>
        /// <param name = "itoa64">The itoa64 string.</param>
        /// <returns>The encrypted hash ready to be compared.</returns>
        /// <remarks>
        ///   password:  Saves conversion inside the function, lazy coding really.
        ///   genSalt:   Returns from hashGensaltPrivate(random, itoa64);
        ///   return:    Compare with phpbbCheckHash(password, hash)
        /// </remarks>
        private string hashCryptPrivate(byte[] password, string genSalt, string itoa64)
        {
            var output = "*";
            var md5 = new MD5CryptoServiceProvider();
            if (!(genSalt.StartsWith("$H$") || genSalt.StartsWith("$P$")))
            {
                return output;
            }
            //   $count_log2 = strpos($itoa64, $setting[3]);
            var count_log2 = itoa64.IndexOf(genSalt[3]);
            if (count_log2 < 7 || count_log2 > 30)
            {
                return output;
            }
    
            var count = 1 << count_log2;
            var salt = Encoding.ASCII.GetBytes(genSalt.Substring(4, 8));
    
            if (salt.Length != 8)
            {
                return output;
            }
    
            var hash = md5.ComputeHash(this.Combine(salt, password));
    
            do
            {
                hash = md5.ComputeHash(this.Combine(hash, password));
            } while (count-- > 1);
    
            output = genSalt.Substring(0, 12);
            output += this.hashEncode64(hash, 16, itoa64);
    
            return output;
        }
    
        /// <summary>
        ///   Private function to concat byte arrays.
        /// </summary>
        /// <param name = "b1">Source array.</param>
        /// <param name = "b2">Array to add to the source array.</param>
        /// <returns>Combined byte array.</returns>
        private byte[] Combine(byte[] b1, byte[] b2)
        {
            var retVal = new byte[b1.Length + b2.Length];
            Array.Copy(b1, 0, retVal, 0, b1.Length);
            Array.Copy(b2, 0, retVal, b1.Length, b2.Length);
            return retVal;
        }
    
        /// <summary>
        ///   Encode the hash.
        /// </summary>
        /// <param name = "input">The hash to encode.</param>
        /// <param name = "count">[This parameter needs documentation].</param>
        /// <param name = "itoa64">The itoa64 string.</param>
        /// <returns>Encoded hash.</returns>
        private string hashEncode64(byte[] input, int count, string itoa64)
        {
            var output = "";
            var i = 0;
            var value = 0;
    
            do
            {
                value = input[i++];
                output += itoa64[value & 0x3f];
    
                if (i < count)
                {
                    value |= input[i] << 8;
                }
                output += itoa64[(value >> 6) & 0x3f];
                if (i++ >= count)
                {
                    break;
                }
    
                if (i < count)
                {
                    value |= input[i] << 16;
                }
                output += itoa64[(value >> 12) & 0x3f];
                if (i++ >= count)
                {
                    break;
                }
    
                output += itoa64[(value >> 18) & 0x3f];
            } while (i < count);
    
            return output;
        }
    
        /// <summary>
        ///   Generate salt for hash generation.
        /// </summary>
        /// <param name = "input">Any random information.</param>
        /// <param name = "itoa64">The itoa64 string.</param>
        /// <returns>Generated salt string</returns>
        private string hashGensaltPrivate(byte[] input, string itoa64)
        {
            var iteration_count_log2 = 6;
    
            var output = "$H$";
            output += itoa64[Math.Min(iteration_count_log2 + 5, 30)];
            output += this.hashEncode64(input, 6, itoa64);
    
            return output;
        }
    
        /// <summary>
        ///   Returns a hexadecimal string representation for the encrypted MD5 parameter.
        /// </summary>
        /// <param name = "password">String to be encrypted.</param>
        /// <returns>String</returns>
        private string sMD5(string password)
        {
            return this.sMD5(password, false);
        }
    
        /// <summary>
        ///   Returns a hexadecimal string representation for the encrypted MD5 parameter.
        /// </summary>
        /// <param name = "password">String to be encrypted.</param>
        /// <param name = "raw">Whether or not to produce a raw string.</param>
        /// <returns>String</returns>
        private string sMD5(string password, bool raw)
        {
            var md5 = new MD5CryptoServiceProvider();
            if (raw)
            {
                return Encoding.ASCII.GetString(md5.ComputeHash(Encoding.ASCII.GetBytes(password)));
            }
            else
            {
                return BitConverter.ToString(md5.ComputeHash(Encoding.ASCII.GetBytes(password))).Replace("-", "");
            }
        }
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have recently started looking into Google Charts API for possible use within the
I have recently started using the Rackspace Cloudfiles CDN (Limelight), about which I have
I have recently started learning C++ and coming from a Ruby environment I have
Recently I have started working on a program that will monitor the packets of
I have recently started to use the code cell function in MATLAB's editor and
I have recently started to use Web Expression 4. I was under the impression
I have recently started working on some open source project which I found relevant
Here is a matrix template I recently started implementing. It doesn't have many functions
I have recently started to use Eclipse after using IntelliJ for a few years.
I have recently started using SQLALCHEMY to query a my-sql database. I want to

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.