Anheledir
Anheledir

Reputation: 4387

How to create a asp.net membership provider hashed password manually?

I'm using a website as a frontend and all users are authenticated with the standard ASP.NET Membership-Provider. Passwords are saved "hashed" within a SQL-Database.

Now I want to write a desktop-client with administrative functions. Among other things there should be a method to reset a users password. I can access the database with the saved membership-data, but how can I manually create the password-salt and -hash? Using the System.Web.Membership Namespace seems to be inappropriate so I need to know how to create the salt and hash of the new password manually.

Experts step up! :)

Upvotes: 14

Views: 19493

Answers (4)

Forgotten Semicolon
Forgotten Semicolon

Reputation: 14100

You can absolutely use System.Web.Security within a console or winforms app.

Here's a simple console application:

static void Main(string[] args)
{
    MembershipProvider provider = Membership.Provider;

    MembershipUser myUser = provider.GetUser("myUser", false);

    if( myUser != null ) provider.DeleteUser("myUser", true);

    MembershipCreateStatus status;

    myUser = provider.CreateUser("myUser", "password", "[email protected]", null, null, true, null, out status);

    if (status != MembershipCreateStatus.Success)
    {
        Console.WriteLine("Could not create user.  Reason: " + status.ToString());
        Console.ReadLine();
        return;
    }

    Console.WriteLine("Authenticating with \"password\": " + provider.ValidateUser("myUser", "password").ToString());

    string newPassword = myUser.ResetPassword();

    Console.WriteLine("Authenticating with \"password\": " + provider.ValidateUser("myUser", "password").ToString());
    Console.WriteLine("Authenticating with new password: " + provider.ValidateUser("myUser", newPassword).ToString());

    Console.ReadLine();
}

And the app.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <connectionStrings>
        <add name="MyConnectionString" connectionString="Data Source=localhost;Initial Catalog=MyDatabase;Integrated Security=True" providerName="System.Data.SqlClient" />
    </connectionStrings>
    <system.web>
        <membership defaultProvider="MyMembershipProvider">
            <providers>
                <clear />
                <add name="MyMembershipProvider"
                     type="System.Web.Security.SqlMembershipProvider"
                     connectionStringName="MyConnectionString"
                     applicationName="MyApplication"
                     minRequiredPasswordLength="5"
                     minRequiredNonalphanumericCharacters="0"
                     requiresQuestionAndAnswer="false" />
            </providers>
        </membership>
    </system.web>
</configuration>

Upvotes: 13

Anheledir
Anheledir

Reputation: 4387

I used reflector to take a look at those methods the .NET-Framework is using internal. Maybe there are public methods available for this but I did not find them - if you know how to query those internal methods as a user please left a comment! :)

Here is the simplified source-code without unnecessary conditions because I only want to encode the password as a SHA1-Hash:

private string GenerateSalt() {
  var buf = new byte[16];
  (new RNGCryptoServiceProvider()).GetBytes(buf);
  return Convert.ToBase64String(buf);
}

private string EncodePassword(string pass, string salt) {
    byte[] bytes = Encoding.Unicode.GetBytes(pass);
    byte[] src = Convert.FromBase64String(salt);
    byte[] dst = new byte[src.Length + bytes.Length];
    byte[] inArray = null;
    Buffer.BlockCopy(src, 0, dst, 0, src.Length);
    Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
    HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
    inArray = algorithm.ComputeHash(dst);
    return Convert.ToBase64String(inArray);
}

Upvotes: 18

EdSF
EdSF

Reputation: 12351

It's been some time since I've tinkered with ASP.Net membership, but do remember dealing with something a bit related to it (needed to customize things due to an existing database of users). In that effort I overrode the methods (the existing user db had md5 hashed pwds).

So in the same "line of thought":

Expose the Membership API via a web service that your desktop app can reference. This way, you're not "re-creating" things, you're re-using them. You don't have to override anything, you're just exposing the existing methods via a web service for your desktop app.

Goes without saying that you'd have to secure this endpoint....

If the above is too sketchy for your taste, here's a link to the asp.net forums regarding some attempts to recreate the hashing....I can't confirm the accuracy, but it should be easy to test it out:

http://forums.asp.net/p/1336657/2899172.aspx

Upvotes: 1

Charlie Brown
Charlie Brown

Reputation: 2825

Quick dirty method

Public Shared Function GetSaltKey() As String
            Dim saltBytes() As Byte
            Dim minSaltSize As Integer = 4
            Dim maxSaltSize As Integer = 8

            ' Generate a random number for the size of the salt.
            Dim random As Random
            random = New Random()

            Dim saltSize As Integer
            saltSize = random.Next(minSaltSize, maxSaltSize)

            ' Allocate a byte array, which will hold the salt.
            saltBytes = New Byte(saltSize - 1) {}

            ' Initialize a random number generator.
            Dim rng As RNGCryptoServiceProvider
            rng = New RNGCryptoServiceProvider()

            ' Fill the salt with cryptographically strong byte values.
            rng.GetNonZeroBytes(saltBytes)

            ' Convert plain text into a byte array.
            Return Convert.ToBase64String(saltBytes)
        End Function

        Public Shared Function ComputeHash(ByVal password As String, ByVal salt As String) As String

            Return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(salt & password, _
                System.Web.Configuration.FormsAuthPasswordFormat.SHA1.ToString)
        End Function

Although, the membership namespace has stuff built in for this as well, as stated by Forgotten Semicolon

Upvotes: 1

Related Questions