using System;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;

namespace daniweb
{
  public partial class frmLogin : Form
  {
    /// <summary>
    /// Key for the crypto provider
    /// </summary>
    private static readonly byte[] _key = { 0xA1, 0xF1, 0xA6, 0xBB, 0xA2, 0x5A, 0x37, 0x6F, 0x81, 0x2E, 0x17, 0x41, 0x72, 0x2C, 0x43, 0x27 };
    /// <summary>
    /// Initialization vector for the crypto provider
    /// </summary>
    private static readonly byte[] _initVector = { 0xE1, 0xF1, 0xA6, 0xBB, 0xA9, 0x5B, 0x31, 0x2F, 0x81, 0x2E, 0x17, 0x4C, 0xA2, 0x81, 0x53, 0x61 };

    public frmLogin()
    {
      InitializeComponent();
    }


#if (DEBUG) //Only compile this method for local debugging.
    /// <summary>
    /// Decrypt a string
    /// </summary>
    /// <param name="Value"></param>
    /// <returns></returns>
    private static string Decrypt(string Value)
    {
      SymmetricAlgorithm mCSP;
      ICryptoTransform ct = null;
      MemoryStream ms = null;
      CryptoStream cs = null;
      byte[] byt;
      byte[] _result;

      mCSP = new RijndaelManaged();

      try
      {
        mCSP.Key = _key;
        mCSP.IV = _initVector;
        ct = mCSP.CreateDecryptor(mCSP.Key, mCSP.IV);


        byt = Convert.FromBase64String(Value);

        ms = new MemoryStream();
        cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
        cs.Write(byt, 0, byt.Length);
        cs.FlushFinalBlock();

        cs.Close();
        _result = ms.ToArray();
      }
      catch
      {
        _result = null;
      }
      finally
      {
        if (ct != null)
          ct.Dispose();
        if (ms != null)
          ms.Dispose();
        if (cs != null)
          cs.Dispose();
      }

      return ASCIIEncoding.UTF8.GetString(_result);
    }
#endif

    /// <summary>
    /// Encrypt a string
    /// </summary>
    /// <param name="Password"></param>
    /// <returns></returns>
    private static string Encrypt(string Password)
    {
      if (string.IsNullOrEmpty(Password))
        return string.Empty;

      byte[] Value = Encoding.UTF8.GetBytes(Password);
      SymmetricAlgorithm mCSP = new RijndaelManaged();
      mCSP.Key = _key;
      mCSP.IV = _initVector;
      using (ICryptoTransform ct = mCSP.CreateEncryptor(mCSP.Key, mCSP.IV))
      {
        using (MemoryStream ms = new MemoryStream())
        {
          using (CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write))
          {
            cs.Write(Value, 0, Value.Length);
            cs.FlushFinalBlock();
            cs.Close();
            return Convert.ToBase64String(ms.ToArray());
          }
        }
      }
    }

    /// <summary>
    /// Looks up the users password crypto string in the database
    /// </summary>
    /// <param name="Username"></param>
    /// <returns></returns>
    private static DataTable LookupUser(string Username)
    {
      /*
       * The reason I return a datatable here is so you can also bring back the user's full
       * name, email address, security rights in the application, etc. I have a "User" class
       * where I defined meta information for users.
       */ 
      const string connStr = "Data Source=apex2006sql;Initial Catalog=Leather;Integrated Security=True;";
      const string query = "Select Password From UserTable (NOLOCK) Where UserName = @UserName";
      DataTable result = new DataTable();
      using (SqlConnection conn = new SqlConnection(connStr))
      {
        conn.Open();
        using (SqlCommand cmd = new SqlCommand(query, conn))
        {
          cmd.Parameters.Add("@UserName", SqlDbType.VarChar).Value = Username;
          using (SqlDataReader dr = cmd.ExecuteReader())
          {
            result.Load(dr);
          }
        }
      }
      return result;
    }

    /// <summary>
    /// Obviously the .Focus() code doesn't apply to ASP.NET
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void buttonLogin_Click(object sender, EventArgs e)
    {
      if (string.IsNullOrEmpty(textBoxUsername.Text))
      {
        //Focus box before showing a message
        textBoxUsername.Focus();
        MessageBox.Show("Enter your username", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
        //Focus again afterwards, sometimes people double click message boxes and select another control accidentally
        textBoxUsername.Focus();
        return;
      }
      else if (string.IsNullOrEmpty(textBoxPassword.Text))
      {
        textBoxPassword.Focus();
        MessageBox.Show("Enter your password", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
        textBoxPassword.Focus();
        return;
      }

      //OK they enter a user and pass, lets see if they can authenticate
      using (DataTable dt = LookupUser(textBoxUsername.Text))
      {
        if (dt.Rows.Count == 0)
        {
          textBoxUsername.Focus();
          MessageBox.Show("Invalid username.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
          textBoxUsername.Focus();
          return;
        }
        else
        {
          //Always compare the resulting crypto string or hash value, never the decrypted value
          //By doing that you never make a call to Decrypt() and the application is harder to
          //reverse engineer. I included the Decrypt() method here for informational purposes
          //only. I do not recommend shipping an assembly with Decrypt() methods.

          string dbPassword = Convert.ToString(dt.Rows[0]["Password"]);
          string appPassword = Encrypt(textBoxPassword.Text); //we store the password as encrypted in the DB
          if (string.Compare(dbPassword, appPassword) == 0)
          {
            //Logged in
          }
          else
          {
            //You may want to use the same error message so they can't tell which field they got wrong
            textBoxPassword.Focus();
            MessageBox.Show("Invalid Password", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
            textBoxPassword.Focus();
            return; 
          }
        }
      }
    }
  }
}

Very instructive for a C# learner like me.
I have already seen it pays off! You reffered to this snippet in another thread. Keep up the good spirit!

Very instructive! But I'm using the ASP.Net What we should use instead of .Focus()?

And when using built-in Login and CreateUserWizard controls where/in which databse, table does it store all the information? Can Access that table and add some fields manually? If yes, how can I access.

thanks in advance!

thanks for this code.......i willing to use it......can you please upload a simple MD5 encrypted login form with logout function.....i'm creating a software that needs user authentication to enter....using C#2008.....thank you again!!

You don't need to call .Focus() on ASP.NET or win forms applications, it just aesthetic. It won't kill the user to click ;)
You should be fine if you just put a red label with "Invalid username or password" and let them fix it. I included code to tell them which field they have wrong but I personally use the same error and focus the username field regardless so they can't guess at which fields are right or wrong.

Regarding the built in login controls and create wizard -- I don't know. I don't use them.

For md5 just swap out my encryption functions (and remove the decrypt function since md5 hashes, not encrypts). You can find an md5 haser at:

http://blog.stevex.net/index.php/c-code-snippet-creating-an-md5-hash-string/

just now 1ly i stared studying c# i dont know the basic commands so tell me how to run the code..?

Uhm.. maybe, but why would you want to inflict that pain on yourself? Just use the designer.

i did slap the code in the visual studio click F5 but it can't work.
jeez i feel like a dummy. trying to figure out how the code work. haas.
and i still don't get it.

Sorry.. i have got problem to make it work..... need help..

It seem that, value that i entered into the textBoxPassword field doesn't pass the comparison done (string.Compare()) againt the value stored in the DB. (It keep on skip to the action in 'else if' statement. For instance, i have my Password in DB as 'abc', of course, to make match, i have then input the value in textBoxPassword field as 'abc' as well, However, it do keep on say 'invalid password'!!

I have got the Data Type for UserName and Password as nchar(10) in MSSQL DB.

Anything tht i had miss out?

Edited 7 Years Ago by eURe: n/a

Quite helpful ! :)
There is one suggestion. You can add a functionality to check whether the same login is used by another user currently.

I'm new to c# and this forum. your work is great, wondering if you can help with filling a combobox using OOP approach with storedProcedures,this were you have a form with events class and a data access object which is directly interacting with the database then feeding the form. thanx

hi sir
I am creating website in asp.net. so i am creating the login window and one master page.
my problem is that i want to access this user name display in master page i am creating session or access it but when i am direct access master page then Run time error occur

SqlConnection con = new SqlConnection(strConn);
            string strCmd = "select UserName, Password from Login where UserName='" + txtUserName.Text + "' and Password ='" + txtPassword.Text + "'";
            SqlCommand cmd = new SqlCommand(strCmd, con);
            SqlDataAdapter da = new SqlDataAdapter(strCmd, con);
            DataSet ds = new DataSet();
            con.Open();
            cmd.ExecuteNonQuery();
            da.Fill(ds);
            con.Close();
            MessageBox.Show("Login successful", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
            frmLogin login = new frmLogin();
            login.Close();
            frmBill bills = new frmBill();
            bills.Show();

Edited 3 Years Ago by Dani: Formatting fixed

This is really fantastic Sknake. It is a ready to use login code.
Thanks for this and I would like to rate it 5/5. Keep it up.

I have used your code and can get it to work without encrypt. However I am have a hard time setting database up to encrypt Password field with same encryption that matches the code

Can someone help Thanks

Open up visual studio, slap that code in to a form, and hit F5.

There's no designer code so it won't be that simple...

There's no designer code so it won't be that simple...

True -- but only 3 controls are referenced. Two textboxes and a button. Shouldn't be that difficult.

That's true, hopefully if you are delving into security you have at least a decent grasp on winforms.

One problem I have with this - since the connection is in plain text could a user not simply find that string in the .exe file and run a query against that connection similar to SELECT Username, Password FROM Usertable to get all of the login info? The passwords would still be encrypted but that doesn't stop anyone from just using the encrypted password to log in.

Edit: I take that back - just because the user knows the encrypted password doesn't mean they can login with it in your application (since it would just get double encrypted then compared)

Assuming anyone is allowed to make an account, you could pretty easily figure out the encryption keys by making several accounts and comparing the encrypted passwords with the known passwords.

(I really don't mean to shit on your parade I just find security interesting lol)

Edited 4 Years Ago by skatamatic: n/a

>> One problem I have with this - since the connection is in plain text could a user not simply find that string in the .exe file and run a query against that connection similar to SELECT Username, Password FROM Usertable to get all of the login info?

Maybe -- dont you run a string/code obfuscator before you release code to production? My guess is since you're asking the answer is no.

They could also use an SQL profiler, or set up an ODBC connection with logging (if the app permitted ODBC conns), or they could wireshark, or 908232350 other things. They could also unplug the computers LAN connection, put it in to a hub then MITM the entire session! Or if they had a managed switch in between they could break in to they could configure monitor ports and mirror the traffic off without having to disrupt the physical connections. Or they could put a key logger on the computer and wait for someone to log in -- they obviously have physical access to the machine with the app and connectivity to the database.

>> The passwords would still be encrypted but that doesn't stop anyone from just using the encrypted password to log in.

Really? Explain to me how that would work. Look at the code:

string dbPassword = Convert.ToString(dt.Rows[0]["Password"]);
          string appPassword = Encrypt(textBoxPassword.Text); //we store the password as encrypted in the DB
          if (string.Compare(dbPassword, appPassword) == 0)
          {
            //Logged in

If you slap the encrypted password in the password textbox it would re-encrypt it, resulting in a different value.

>> And assuming anyone is allowed to make an account, you could pretty easily figure out the encryption keys by making several accounts and comparing the encrypted passwords with the known passwords
True but that assumption is outside the scope of this thread and you would also need unfettered access to the DB table hosting the passwords. Then you would need a great deal of CPU time to finally crack the password.

>> (I really don't mean to shit on your parade I just find security interesting lol)
No thats fine .. you're showing you are still learning about security. You have to start somewhere :)
If md5 encryption were being used (unsalted) you could consult rainbox tables but unfortunately that is not the case here.

The whole point of the SQL query looking up by username and returning the password is so the passwords are compared in the machine's memory. Now this can go one of two ways (yes there are technically many other ways):
#1 - The user has access to a profiler on the SQL server and can intercept the hashed password, run an update query on an existing user record replacing his hashed password, and then log in.
#2 - The user has access and skill enough to grab the hashed password out of the computer's memory at login time.

There is a tool for #1 that gives you the output plain as day.
There is a tool for #2 that makes it possible but you have to _really_ know what you're doing.

Then you could argue that #1 would be more secure since the comparison is done on another trusted machine, but, if you have the skill to do #2 then #1 is really a moot point.

Bottom line is you're taking a short and sweet code example of basic "logging in" code and trying to say its not ready for production by the FBI/CIA/NSA/etc. I would agree.

Feel free to join my parade :) The sun is shining!

>> One problem I have with this - since the connection is in plain text could a user not simply find that string in the .exe file and run a query against that connection similar to SELECT Username, Password FROM Usertable to get all of the login info?

Maybe -- dont you run a string/code obfuscator before you release code to production? My guess is since you're asking the answer is no.

They could also use an SQL profiler, or set up an ODBC connection with logging (if the app permitted ODBC conns), or they could wireshark, or 908232350 other things. They could also unplug the computers LAN connection, put it in to a hub then MITM the entire session! Or if they had a managed switch in between they could break in to they could configure monitor ports and mirror the traffic off without having to disrupt the physical connections. Or they could put a key logger on the computer and wait for someone to log in -- they obviously have physical access to the machine with the app and connectivity to the database.

>> The passwords would still be encrypted but that doesn't stop anyone from just using the encrypted password to log in.

Really? Explain to me how that would work. Look at the code:

string dbPassword = Convert.ToString(dt.Rows[0]["Password"]);
          string appPassword = Encrypt(textBoxPassword.Text); //we store the password as encrypted in the DB
          if (string.Compare(dbPassword, appPassword) == 0)
          {
            //Logged in

If you slap the encrypted password in the password textbox it would re-encrypt it, resulting in a different value.

>> And assuming anyone is allowed to make an account, you could pretty easily figure out the encryption keys by making several accounts and comparing the encrypted passwords with the known passwords
True but that assumption is outside the scope of this thread and you would also need unfettered access to the DB table hosting the passwords. Then you would need a great deal of CPU time to finally crack the password.

>> (I really don't mean to shit on your parade I just find security interesting lol)
No thats fine .. you're showing you are still learning about security. You have to start somewhere :)
If md5 encryption were being used (unsalted) you could consult rainbox tables but unfortunately that is not the case here.

The whole point of the SQL query looking up by username and returning the password is so the passwords are compared in the machine's memory. Now this can go one of two ways (yes there are technically many other ways):
#1 - The user has access to a profiler on the SQL server and can intercept the hashed password, run an update query on an existing user record replacing his hashed password, and then log in.
#2 - The user has access and skill enough to grab the hashed password out of the computer's memory at login time.

There is a tool for #1 that gives you the output plain as day.
There is a tool for #2 that makes it possible but you have to _really_ know what you're doing.

Then you could argue that #1 would be more secure since the comparison is done on another trusted machine, but, if you have the skill to do #2 then #1 is really a moot point.

Bottom line is you're taking a short and sweet code example of basic "logging in" code and trying to say its not ready for production by the FBI/CIA/NSA/etc. I would agree.

Feel free to join my parade :) The sun is shining!

I editted my last post and admitted I was wrong, but must have done that while you where in the middle of writing this post...

But really, since the return value of the Encrypt() function will always be the same length, the memory could be directly editted in something like OllyDebug (or some other debugging tool) with the queried password hash for a given username (but with that being said, the Is_Logged_In flag could simply be set to true :P as well). Obfuscation might slow this process down, but not prevent it. I guess realistically it is very hard to completely secure an application where authentication is done client side.

PS You don't need to get defensive or mean; I wasn't saying your code/method was garbage. I just think it can be improved - like most things! And I understand that this is a basic example and I respect your efforts to share it with us.

Edited 4 Years Ago by skatamatic: n/a

Impressive. My apologies -- bad day.

OllyDebug is what I was referring to for tool #2 but I have never used it with managed code. Normally with managed code I just decompile it or use a .NET binary editor to change the lines of code I want to get around. I've yet to run in to an application where I needed to circumvent something that has been obfuscated.

Also regarding the length of Encrypt() -- I don't think it always be the same length. I believe there is a blocksize, say 1024, and once your password exceeds the length it well have to roll over another +1024 resulting in a longer string when encoded. Regardless though your point is still valid -- just go after the memory and it doesn't matter.

>> I guess realistically it is very hard to completely secure an application where authentication is done client side.

Its really hard to secure an application -- take a look at all the pirated software out there. If a smart enough feller wants your application he can probably get it, unless you implement enough security to prevent it which actually irritates 99% of your legitimate users causing you to lose business in the long run. Is it more business lost due to security than would have been lost due to piracy? Its a tough call.

Most people's security issues are trying to keep Bob from accounting to get access to Jane's section of the application, and neither one of them know much more than how to click their way around a computer.

..and when you want to separate Bob & Jane, here is your code snippet!

Impressive. My apologies -- bad day.

OllyDebug is what I was referring to for tool #2 but I have never used it with managed code. Normally with managed code I just decompile it or use a .NET binary editor to change the lines of code I want to get around. I've yet to run in to an application where I needed to circumvent something that has been obfuscated.

Also regarding the length of Encrypt() -- I don't think it always be the same length. I believe there is a blocksize, say 1024, and once your password exceeds the length it well have to roll over another +1024 resulting in a longer string when encoded. Regardless though your point is still valid -- just go after the memory and it doesn't matter.

>> I guess realistically it is very hard to completely secure an application where authentication is done client side.

Its really hard to secure an application -- take a look at all the pirated software out there. If a smart enough feller wants your application he can probably get it, unless you implement enough security to prevent it which actually irritates 99% of your legitimate users causing you to lose business in the long run. Is it more business lost due to security than would have been lost due to piracy? Its a tough call.

Most people's security issues are trying to keep Bob from accounting to get access to Jane's section of the application, and neither one of them know much more than how to click their way around a computer.

..and when you want to separate Bob & Jane, here is your code snippet!

Very true. Web authentication seems to be getting more popular these days, but unless the actual content is being loaded from a server this can be circumvented just the same by tricking your app into thinking it's been web-authenticated. And in the case of online games, somehow server code tends to get leaked and private servers start popping up - essentially nullifying this anti-piracy tactic altogether. I guess it's just the world we live in!

Companies like facebook and google seem to know this all to well - traffic generation by offering free services and advertising will likely be the best method to generate profit without the threat of piracy for the forseeable future. Although this methodology isn't very easy to apply to Bob's accounting software :P

Edited 4 Years Ago by skatamatic: n/a

i need this C#.NET file . can u send it ??? my email id is sundarrajan001@gmail.com

hi! i've tried the code above and it worked, but everytime i input my password it keeps on telling me that the password is invalid eventhough it is correct. can you please tell me what's wrong? thanks!

The article starter has earned a lot of community kudos, and such articles offer a bounty for quality replies.