Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What to do when you can not save a password as a hash

I have a program that uses System.DirectoryServices.AccountManagement.PrincipalContext to verify that the information a user entered in a setup screen is a valid user on the domain (the computer itself is not on the domain) and do some operations on the users of the domain. The issue is I do not want the user to need to enter his or her password every time they run the program so I want to save it, but I do not feel comfortable storing the password as plain-text in their app.config file. PrincipalContext needs a plain-text password so I can not do a salted hash as everyone recommends for password storing.

This is what I did

const byte[] mySalt = //It's a secret to everybody.
[global::System.Configuration.UserScopedSettingAttribute()]
public global::System.Net.NetworkCredential ServerLogin
{
    get
    {
        var tmp = ((global::System.Net.NetworkCredential)(this["ServerLogin"]));
        if(tmp != null)
            tmp.Password = new System.Text.ASCIIEncoding().GetString(ProtectedData.Unprotect(Convert.FromBase64String(tmp.Password), mySalt, DataProtectionScope.CurrentUser));
        return tmp;
    }
    set
    {
        var tmp = value;
        tmp.Password = Convert.ToBase64String(ProtectedData.Protect(new System.Text.ASCIIEncoding().GetBytes(tmp.Password), mySalt, DataProtectionScope.CurrentUser));
        this["ServerLogin"] = value;
    }
}

Was this the right thing to do or is there a better way?

EDIT -- Here is a updated version based on everyone's suggestions

private MD5 md5 = MD5.Create();

[global::System.Configuration.UserScopedSettingAttribute()]
public global::System.Net.NetworkCredential ServerLogin
{
    get
    {
        var tmp = ((global::System.Net.NetworkCredential)(this["ServerLogin"]));
        if(tmp != null)
            tmp.Password = System.Text.Encoding.UTF8.GetString(ProtectedData.Unprotect(Convert.FromBase64String(tmp.Password), md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(tmp.UserName.ToUpper())), DataProtectionScope.CurrentUser));
        return tmp;
    }
    set
    {
        var tmp = value;
        tmp.Password = Convert.ToBase64String(ProtectedData.Protect(System.Text.Encoding.UTF8.GetBytes(tmp.Password), md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(tmp.UserName.ToUpper())), DataProtectionScope.CurrentUser));
        this["ServerLogin"] = tmp;
    }
}
like image 201
Scott Chamberlain Avatar asked Feb 16 '10 14:02

Scott Chamberlain


1 Answers

For the salt, I'd do a transformation on the username (hash it) rather than share the same salt for everyone.

For something like this, I'd also look for a way to keep the existing session alive longer rather than saving the password to create new sessions.

like image 78
Joel Coehoorn Avatar answered Nov 14 '22 23:11

Joel Coehoorn