Hi all

I'm writing a wpf app that requires a user to log in. I thought this would be a pretty easy thing but it's hurting me. I can't find any error, I'm hoping someone can point out the silly mistake I made or the obscure gotcha I wasn't aware of. Anyway, here's a description of the issue:

I have a database (mysql) that stores user information, there are three columns here that interest us: username, password (the hashed value) and salt (just a normal string, I know it's bad form to store this in the same place as the hash, will put it somewhere better later).

I also have a class called Auditor that talks to the database. It can store and retrieve values from the table. I've tested this and all seems to be in good order.

I created an auditor with username 'test', passeword 'pass', and salt 'OYzADe' and used the following code to create the hash:

public static string GetMD5(string value)
{
// the problem doesn't seem to be here because I've tried a few differant ways do doing this
MD5 algorithm = MD5.Create();
byte[] data = algorithm.ComputeHash(Encoding.UTF8.GetBytes(value));
string md5 = "";
for (int i = 0; i < data.Length; i++)
{
md5 += data[i].ToString("x2").ToLowerInvariant();
}
return md5;
}

public void newPass(string password)
{
newSalt(); //this generated the salt i mentioned above as a random string and stored it in the private variable 'salt'
pass = GetMD5(password + salt); //this is a private variable
}

In other words I defined all the fields within the Auditor class then called newPass('pass'). Next I called a save method which stored everything in the db and all seems just dandy.

When an auditor tries to log in they input their username and password. An auditor object is created and all relevant info is retrieved based on the username. This also works fine.

Next I check to see if the password is ok with the following code:

public bool checkPass(string password)
{
string input=password+this.salt;
string inputhashed = GetMD5(input);
return (inputhashed == this.pass);
}

I call the function as follows:
checkPass(passwordBox1.password);
the hash I came up with before with the original salt string and 'pass' was f963d0c58c109...blah, when calling checkPass the hash of the retrieved salt and the password from the box is cd16f...blah. I think they should match.

As a test to see if the problem was with the db interface i altered checkPass as follows and entered the same data in the input boxes:

public bool checkPass(string password)
{
newPass("pass");
string input=password+this.salt;
string inputhashed = GetMD5(input);
return (inputhashed == this.pass);
}

Now authentication works fine so i think the problem lies in the db interface.

I save data to the db with this function:

public void save()
{
MySqlConnection conn = GlobalSettings.connection();
string sql;
MySqlCommand cmd;
MySqlDataReader rdr;
conn.Open();
if (id != 0)
{
//throw new Exception("id!=0");
sql = "SELECT * FROM auditor WHERE id=@id";
cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@id", id);
rdr = cmd.ExecuteReader();
if (rdr.Read())
{
//this entry exists
sql = "UPDATE auditor ";
sql += "SET first_name=@first,last_name=@last,address_line_1=@addr1,address_line_2=@addr2,address_line_3=@addr3,postal_code=@pcode,email_address=@email,landline_number=@landline,cellphone_number=@cell,fax_number=@fax,password=@pass,salt=@salt,username=@username ";
sql += "WHERE id = @id";
}
else
{

//save it
sql = "INSERT INTO auditor (first_name,last_name,address_line_1,address_line_2,address_line_3,postal_code,email_address,landline_number,cellphone_number,fax_number,username,password,salt) VALUES";
sql += "(@first,@last,@addr1,@addr2,@addr3,@pcode,@email,@landline,@cell,@fax,@username,@pass,@salt)";
}
rdr.Close();
}
else
{
//save it
//to do: fix this syntax right here
sql = "INSERT INTO auditor (first_name,last_name,address_line_1,address_line_2,address_line_3,postal_code,email_address,landline_number,cellphone_number,fax_number,username,password,salt) VALUES";
sql += "(@first,@last,@addr1,@addr2,@addr3,@pcode,@email,@landline,@cell,@fax,@username,@pass,@salt)";

}
cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@first", first_name);
cmd.Parameters.AddWithValue("@last", last_name);
cmd.Parameters.AddWithValue("@addr1", address_line_1);
cmd.Parameters.AddWithValue("@addr2", address_line_2);
cmd.Parameters.AddWithValue("@addr3", address_line_3);
cmd.Parameters.AddWithValue("@pcode", postal_code);
cmd.Parameters.AddWithValue("@email", email_address);
cmd.Parameters.AddWithValue("@landline", landline_number);
cmd.Parameters.AddWithValue("@cell", cellphone_number);
cmd.Parameters.AddWithValue("@fax", fax_number);
cmd.Parameters.AddWithValue("@username", username);
cmd.Parameters.AddWithValue("@pass", pass);
cmd.Parameters.AddWithValue("@salt", salt);
try
{
cmd.Parameters.AddWithValue("@id", id);
}
catch (Exception ex)
{
}
cmd.ExecuteNonQuery();
conn.Close();
//MessageBox.Show("salt= " + salt + " pass= " + pass);
}

And retrieve it with:

public Auditor(string username)
{
setUserName(username);
MySqlConnection conn = GlobalSettings.connection();
conn.Open();
string sql = "SELECT * FROM auditor WHERE username=@name";
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@name",username);
MySqlDataReader rdr = cmd.ExecuteReader();
if (rdr.Read())
{
setAddressLine1(rdr["address_line_1"].ToString());
setAddressLine2(rdr["address_line_2"].ToString());
setAddressLine3(rdr["address_line_3"].ToString());
setCellNumber(rdr["cellphone_number"].ToString());
setEmailAddress(rdr["email_address"].ToString());
setFaxNumber(rdr["fax_number"].ToString());
setFirstName(rdr["first_name"].ToString());
setLandlineNumber(rdr["landline_number"].ToString());
setLastName(rdr["last_name"].ToString());
setPostalCode(short.Parse(rdr["postal_code"].ToString()));
setPass(rdr["password"].ToString());
setSalt(rdr["salt"].ToString());
setId(short.Parse(rdr["id"].ToString()));
}
else
throw new Exception("No auditor with this username exists in the database");
conn.Close();
}

The data I get out looks suspiciously like exactly what I put in so I'm not too sure...
Also I'm using mysql-connector-net-6.3.5\v2\mysql.data.dll

Thanks in advance for the advice and constructive criticism, this thing really is driving me nuts

Sheena

And the exact problem is???

Do you have MySQL Workbench? Have you checked the data in the table? Does it look ok i.e. a row gets inserted and updated correctly? What's the declaration for the username, password and salt (long enough fields I mean)?

Can you put a breakpoint in the line return (inputhashed == this.pass); and check the values of inputhashed and this.pass

Just a few things that come in to my mind. I'm sure there's just a small glitch you haven't noticed :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.