Bug #38895 MySQL Connector/Net Should Not Use Hashed Password for Mono
Submitted: 19 Aug 2008 18:20 Modified: 8 Sep 2008 12:26
Reporter: Joshua Martin
Status: Closed
Category:Connector/Net Severity:S2 (Serious)
Version:5.2.3.0 OS:Any (Running Mono)
Assigned to: Target Version:
Tags: get_hashed, Mono

[19 Aug 2008 18:20] Joshua Martin
Description:
On any box with Mono and the MySQL Connector/Net (Mono 2.0 Preview 2 and Connector/Net
5.2.3) the membership provider is incapable of use.

The resulting error is displayed whenever membership provider use is need (i.e. logging in
or creating a new user).

Method not found: 'System.Web.Security.Membership.get_HashAlgorithmType'

The flaw lies in the fact that Mono does not have the necessary methods in place to allow
for hashed passwords. However, even when specifying to use Clear or Encrypted passwords
with the Connector/Net, the Connector/Net still has code to call the absent method.

This one flaw is all that holds users back from using Mono and the full capabilities of
Connector/Net.

How to repeat:
Simply install Mono and the Connector/Net. Make the MySQL membership provider the default
one.

Then, try any membership tasks like logging in or creating a new user.

Suggested fix:
The problem can be resolved by changing a few lines of code in the MySQL.Web Membership
provider located at
mysql-connector-net-5.2.3-src\MySql.Web\Providers\Source\MembershipProvider.cs

One must comment out 2 lines of code and add a line to produce an supported password
format exception.

This is before:

        private string EncodePassword(string password, string passwordKey,
            MembershipPasswordFormat format)
        {
            if (password == null)
                return null;
            if (format == MembershipPasswordFormat.Clear)
                return password;

            byte[] passwordBytes = Encoding.Unicode.GetBytes(password);
            byte[] keyBytes = Convert.FromBase64String(passwordKey);
            byte[] keyedBytes = new byte[passwordBytes.Length + keyBytes.Length];
            Array.Copy(keyBytes, keyedBytes, keyBytes.Length);
            Array.Copy(passwordBytes, 0, keyedBytes, keyBytes.Length,
passwordBytes.Length);

            if (format == MembershipPasswordFormat.Encrypted)
            {
                byte[] encryptedBytes = EncryptPassword(passwordBytes);
                return Convert.ToBase64String(encryptedBytes);
            }
            else if (format == MembershipPasswordFormat.Hashed)
            {
                HashAlgorithm hash = HashAlgorithm.Create(Membership.HashAlgorithmType);
                return Convert.ToBase64String(hash.ComputeHash(keyedBytes));
            }
            else
                throw new ProviderException(Resources.UnsupportedPasswordFormat);
        }

This is after:

        private string EncodePassword(string password, string passwordKey,
            MembershipPasswordFormat format)
        {
            if (password == null)
                return null;
            if (format == MembershipPasswordFormat.Clear)
                return password;

            byte[] passwordBytes = Encoding.Unicode.GetBytes(password);
            byte[] keyBytes = Convert.FromBase64String(passwordKey);
            byte[] keyedBytes = new byte[passwordBytes.Length + keyBytes.Length];
            Array.Copy(keyBytes, keyedBytes, keyBytes.Length);
            Array.Copy(passwordBytes, 0, keyedBytes, keyBytes.Length,
passwordBytes.Length);

            if (format == MembershipPasswordFormat.Encrypted)
            {
                byte[] encryptedBytes = EncryptPassword(passwordBytes);
                return Convert.ToBase64String(encryptedBytes);
            }
            else if (format == MembershipPasswordFormat.Hashed)
            {
                throw new ProviderException(Resources.UnsupportedPasswordFormat);
                //HashAlgorithm hash =
HashAlgorithm.Create(Membership.HashAlgorithmType);
                //return Convert.ToBase64String(hash.ComputeHash(keyedBytes));
            }
            else
                throw new ProviderException(Resources.UnsupportedPasswordFormat);
        }

What I suggest is that two versions of the Connector/Net be compiled when a new release is
made (just until the necessary methods are implemented for Mono). One version for .NET and
the other for Mono.
[20 Aug 2008 1:05] Joshua Martin
After reporting the missing method as a bug to the Mono community, I have received
confirmation that the method has been added to the SVN and the Mono 2.0 builds.

The first release candidate for Mono 2.0 will be released on September 8, 2008. After
verifying that the patch is included and there is no issue between Mono and Connector/Net
in regards to this flaw, then I will close this bug report.
[20 Aug 2008 1:25] Reggie Burnett
Great.  Thanks for letting me know.  I'm marking this as verified for now so our support
crew won't grab it and waste time on it.
[5 Sep 2008 22:09] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/53396
[5 Sep 2008 22:10] Reggie Burnett
fixed in 5.2.4
[8 Sep 2008 12:26] Tony Bedford
An entry was added to the 5.2.4 changelog:

Connector/NET called hashed password methods not supported in Mono 2.0 Preview 2.
[12 Sep 2008 14:18] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/53972
[12 Sep 2008 23:56] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/54011