TehBoyan
TehBoyan

Reputation: 6890

Decrypting an encrypted password from ASP.NET Membership using RijndaelManaged

The bottom line is to create a custom FTP Authentication Provider. In order to do this one must inherit from IFtpAuthenticationProvider interface and then register that assembly in GAC. After that the assembly needs to be registered in IIS's FTP settings.

In order for this to be accomplished I have to use the database which holds my user information in the database from the custom Membership and Role providers we have developed previously. So, that means I have to use a local class library app.config file and read it with ConfigurationManager.OpenMappedExeConfiguration(). I read the connection strings from there and I'm even able to provide it to Linq-To-Sql classes dynamically. No problem there.

Next, I try to create a class that inherits from SqlMembershipProvider so that I can use it's own system to decrypt the password for a user. But, the problem is that it has to read machineKey values from configuration. The only way you can provide custom configuration to a SqlMembershipProvider is trough it's Initialize method (which is not intended for us to use it in our code anyway). But anyway I tried and failed. I've been able to provide it a custom membership settings but not machineKey settings.

So, I decided to go radical. I said: I have the decryptionKey from machineKey so I'll try to decrypt the password manually.

So far I've tried using RijndaelManaged:

    private string UnEncodePassword(string encodedPassword, string secretKey)
    {
        string password = encodedPassword;

        var keyBytes = new byte[16];
        var secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
        Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));

        RijndaelManaged rm = new RijndaelManaged
        {
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
            KeySize = 128,
            BlockSize = 128,
            Key = keyBytes,
            IV = keyBytes
        };

        var encryptedBytes = Convert.FromBase64String(encodedPassword);
        password = Encoding.UTF8.GetString(Decrypt(encryptedBytes, rm));

        return password;
    }

I'm kind of aware that I'm shooting blanks here since I'm not eve sure what kind of padding is used and most importantly even if I could I'm not hitting the right IV. The best I'v done so far is to get some junkish response like: �21l�<��(�\t��].

So I need some pointers. Even suggestions on how to tackle this whole issue from another perspective are welcome.

EDIT:

Just to make things a little bit more clear. I'm not trying to crack the password or anything. I have the password and I have the decryptionKey etc. I just want to find a way to Encrypt/Decrypt it so that I can make a user validation.
I am fully aware that encrypting/decrypting passwords are not the best approach in the first place, but there are reasons why that is being done that way.

Upvotes: 2

Views: 7237

Answers (3)

user645438
user645438

Reputation:

I do agree with the others that hashed passwords are generally more secure that enrypted ones.

But because you can't choose why do you have to use the Encryption or Decription methods from MembershipProvider (btw, I don't even think it's possible).

Why don't you create your own encryption methods and use them in the web application and your class library.

Upvotes: -1

Chris Marisic
Chris Marisic

Reputation: 33098

You should not be decrypting passwords. You should be comparing password hashes.

Passwords should not be stored with reversible encryption. Passwords are meant to be stored as hashes (not MD5 it's too weak).

Regarding your comment above, you do not need to decrypt passwords to compare them. You want to compare the hashes, not the original values. The system should not be able to get the original text of a password. Using the built in ASP.NET membership providers correctly stores passwords as hashes. This is likely why you can't decrypt them, they're meant to be impossible to decrypt.

Edit: In regards to the fact you use passwordFormat="Encrypted" for the SQL membership provider. With this fact you can either encrypt the password in the same format, with the same padding, cipherMode, and IV (you will need to query this from the SQL database) and then just compare the encrypted password values. This is likely unneeded work. You really just want to invoke the Membership's logon function in code with the username/password combination and verify whether it is successful or not. You will need to make sure the machine keys and relevant pieces match in both systems otherwise you won't be able to succeed.

You really want to plan to move to hashed passwords however, storing encrypted passwords as opposed to hashed passwords is nearly pointless. It is only just slightly better than storing them in plain text.

Upvotes: 5

Paul Turner
Paul Turner

Reputation: 39615

You don't typically need to store encrypted passwords, unless you want a form of password-recovery which lets the user see their current password. It's usually a bad idea and it does require a lot more work.

Conventionally, you should only store a salted hash of the password in your database. Hashing is a one-way operation (so nobody can ever decrypt the information to find out the passwords if your database is compromised).

To detect whether a user's password matches the one you have stored, you only need to hash their password with the same salt you used to hash the value in the database. If the two hashes match, the user has provided a correct password.

The authenticate algorithm should look something like this:

  1. Get salt for hashing (could be that you use a salt unique to each user, or a global one)
  2. Generate a hash of the user's password.
  3. Compare the hashed password to the one stored in your database for the username specified (if using LINQ-to-SQL, a simple Any statement can do this).
  4. Return a value to indicate success or failure.

Upvotes: 1

Related Questions