Wednesday, June 3, 2009

How to retrieve Membership's PasswordAnswer

in .net's membership framework, as long as the provider's password format is set to "Encrypted" or "Clear" then developers will be able to retrieve and decode the password. that's ok. but, interestingly, membership does not provide a method to retrieve the "Password Answer" (the answer to the security question when resetting a user's password). one thing to note is that, the PasswordAnswer is encoded using the same algorithm used for the password encryption, thus, if we can decrypt the password then we could probably decrypt the PassswordAnswer using the same function that is being used to decrypt the password(i hope i still make sense). with this, a visit to your friendly reflector will show you MembershipProvider's DecryptPassword and UnEncodePassword methods. This will be all you'll be needing to be able to create your own method of retrieving the PasswordAnswer. The trick is to create a class that derives from the MembershipProvider class to be able to use the DecryptPassword(protected) and check out the implementation of the UnEncodePassword to be able to decode the byte[] returned by DecryptPassword. below is a sample implementation:




public class FalseMembershipProvider : MembershipProvider
{
#region Required Override Properties/Methods
...implement required properties/methods here
#endregion

///
/// Retrieves the Password Answer - wfp june 04 2009
///
///
///
public string GetPasswordAnswer(Guid providerUserKey)
{
Microsoft.Practices.EnterpriseLibrary.Data.Database db = Microsoft.Practices.EnterpriseLibrary.Data.DatabaseFactory.CreateDatabase();
using (System.Data.Common.DbCommand cmd = db.GetSqlStringCommand("SELECT PasswordAnswer FROM aspnet_Membership WHERE UserID=@UserID"))
{
db.AddInParameter(cmd, "@UserId", DbType.Guid, providerUserKey);

object answer = db.ExecuteScalar(cmd);
if (answer != null)
return ProviderDecryptor(answer.ToString());
else
return null;
}
db = null;
}

///
/// Generic Decryptor function. Can be used to decrypt Password and Password Answer.
/// Only works if passwordFormat is set to "Encrypted" - wfp june 04 2009
///
///
///
internal string ProviderDecryptor(string encryptedText)
{
string decrypted = null;

if (!string.IsNullOrEmpty(encryptedText))
{
byte[] encodedbytes = Convert.FromBase64String(encryptedText);
byte[] decryptedbytes = base.DecryptPassword(encodedbytes);

if (decryptedbytes != null)
decrypted = System.Text.Encoding.Unicode.GetString(decryptedbytes, 16, decryptedbytes.Length - 16);
}

return decrypted;
}
}



Share/Save/Bookmark

2 comments:

  1. Hello. I am trying to Change passwordFormat from Encrypted to Hashed.
    Is it possible to show me how to connect this with the code I have pasted below? Thank you!!!
    Using this code below:

    public class FalseMembershipProvider: MembershipProvider
    {
    public string GetPasswordAnswer(Guid providerUserKey)
    {
    Microsoft.Practices.EnterpriseLibrary.Data.Database db = Microsoft.Practices.EnterpriseLibrary.Data.DatabaseFactory.CreateDatabase();
    using (System.Data.Common.DbCommand cmd = db.GetSqlStringCommand("SELECT PasswordAnswer FROM aspnet_Membership WHERE UserID=@UserID"))
    {
    db.AddInParameter(cmd, "@UserId", DbType.Guid, providerUserKey);
    object answer = db.ExecuteScalar(cmd); if (answer != null)
    return ProviderDecryptor(answer.ToString());
    else
    return null;
    }
    db = null;
    }
    internal string ProviderDecryptor(string encryptedText)
    {
    string decrypted = null;
    if (!string.IsNullOrEmpty(encryptedText))
    {
    byte[] encodedbytes = Convert.FromBase64String(encryptedText);
    byte[] decryptedbytes = base.DecryptPassword(encodedbytes);
    if (decryptedbytes != null)
    decrypted = System.Text.Encoding.Unicode.GetString(decryptedbytes, 16, decryptedbytes.Length - 16);
    }
    return decrypted;
    }
    }

    ReplyDelete
  2. Great article, thanks very much! :)

    ReplyDelete