473,394 Members | 1,811 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes and contribute your articles to a community of 473,394 developers and data experts.

Generate secure user passwords using the MD5 hash class module

topher23
234 Expert 100+
I've seen a lot of questions about how to make secure database passwords. I'm going to go over a method of encrypting a password using the MD5 encryption algorithm for maximum security.

First, you will need to download the attached class module (clsMD5.txt) and import it into your database. This class module is the core of what we're about to go over. Thanks to Robert Hubley for writing it - you're my hero!

Next, your database needs a users table. We'll use this one as an example.
Expand|Select|Wrap|Line Numbers
  1. tblUsers
  2.  
  3. Field           Type
  4. UserID          AutoNum  PK
  5. strLastName     Text
  6. strFirstName    Text
  7. strMI           Text
  8. strUserName     Text    (no duplicates)
  9. strPassword     Text    (encrypted)
  10. strPermissions  Text    (access permissions)    
  11.  
Now, you will need some type of "edit user options" form for a user to create a password in. Build your form, and add an UNBOUND text box control for the password. We'll call it txtTempPassword. Make sure you set the Input Mask to Password so no one can spy on the password.

So, we have the following:

Expand|Select|Wrap|Line Numbers
  1. Object      Name             Bound To
  2.  
  3. Form        frmUserOptions   tblUsers
  4. Text Box    txtTempPassword  Unbound    
  5.  
Now, on the AfterUpdate Event of txtTempPassword, use the following code:
Expand|Select|Wrap|Line Numbers
  1. strPassword = DigestStrToHexStr(Me.txtTempPassword)
  2.  
The DigestStrToHexStr() function does the work of turning your plain-text password into a secure, MD5 encrypted mess of hexadecimal gibbersih.

Now, what do you do when the user tries to log into your custom login form?

Your login form will probably follow this basic structure:

Expand|Select|Wrap|Line Numbers
  1. Object      Name             Bound To
  2. --------------------------------------------------- 
  3. Form        frmLogin         Unbound
  4.  
  5. Text Box    txtUsername      Unbound
  6. Text Box    txtPassword      Unbound
  7. Button      cmdLogin
  8.  
In the OnClick event of your button, you'll have the code that checks the text of the entered username and password against your table to see if there's a match. Obviously, with the password now encrypted, there won't be. The solution is to encrypt the search string using the same DigestStrToHexStr() function. Consider the following:

Expand|Select|Wrap|Line Numbers
  1. Private Sub cmdLogin_Click()
  2. Dim rs As DAO.Recordset
  3.     Set rs = CurrentDb.OpenRecordset("SELECT UserID, strUsername, strPassword FROM tblUsers", dbOpenSnapshot)
  4.     'first, see if the username is valid
  5.     rs.FindFirst "strUsername = '" & Me.txtUsername & "'"
  6.     If rs.NoMatch Then GoTo ErrorOut
  7.     'next, check the password
  8.     If rs!strPassword = DigestStrToHexStr(Me.txtPassword) Then
  9.         DoCmd.Close
  10.         'open switchboard and run any other code
  11.     End If
  12.     Exit Sub
  13.     'close the app if the login was incorrect
  14. ErrorOut:
  15.     MsgBox "Username/password combination is invalid." & _
  16.     vbCrLf & vbCrLf & "Exiting application.", vbCritical
  17.     Application.Quit
  18. End Sub
You will obviously need to personalize this code to your use, but that's the idea. Have fun making databases with secure MD5 encrypted passwords!
Attached Files
File Type: txt clsMD5.txt (18.1 KB, 2762 views)
Dec 2 '09 #1
5 12940
NeoPa
32,556 Expert Mod 16PB
For the checking code Topher, why not use a Domain Aggregate function instead? There is no need to loop then, and the interface is pretty straightforward.
Expand|Select|Wrap|Line Numbers
  1. Private Sub cmdLogin_Click()
  2.     Dim strPW As String, strMsg As String
  3.  
  4.     strPW = DigestStrToHexStr(Me.txtPassword)
  5.     strWhere = "[strUserName]='%U' AND [strPassword]='%P'"
  6.     strWhere = Replace(strWhere, "%U", .txtUserName)
  7.     strWhere = Replace(strWhere, "%P", DigestStrToHexStr(Me.txtPassword))
  8.     If DCount("*", "[tblUsers]", strWhere) = 0 Then
  9.         'Close the app if the login was incorrect
  10.         strMsg = "Username/password combination is invalid." & _
  11.                  vbCrLf & vbCrLf & "Exiting application."
  12.         Call MsgBox(strMsg, vbCritical)
  13.         Call Application.Quit
  14.     End If
  15.     Call DoCmd.Close
  16.     'Open switchboard and/or run any other code
  17. End Sub
Dec 9 '09 #2
topher23
234 Expert 100+
There is no need to loop then...
I looked over and over my code looking for a loop, and then realized you probably meant this:
Expand|Select|Wrap|Line Numbers
  1.     If rs.NoMatch Then GoTo ErrorOut
Of course, the GoTo could easily be eliminated by rewriting the code to put the ErrorOut block into an If-Then-Else Statement.

Regarding why I choose to use recordsets over domain aggregate functions; preference more than anything. I find them to be more intuitive to use and, at least on older systems, they tend to run faster than domain aggregate functions.

The major problem with the code I posted is that there is no error-handling. If the code breaks, the recordset stays in memory, which is the only thing I dislike about recordsets. Rewriting the code, then, to add error-checking and eliminate the GoTo, I'd do something like this:

Expand|Select|Wrap|Line Numbers
  1. Private Sub cmdLogin_Click() 
  2. Dim rs As DAO.Recordset 
  3.     Set rs = CurrentDb.OpenRecordset("SELECT UserID, strUsername, strPassword FROM tblUsers", dbOpenSnapshot) 
  4.     'first, see if the username is valid 
  5.     rs.FindFirst "strUsername = '" & Me.txtUsername & "'" 
  6.     If Not rs.NoMatch Then
  7.         'next, check the password 
  8.         If rs!strPassword = DigestStrToHexStr(Me.txtPassword) Then 
  9.             DoCmd.Close 
  10.             'open switchboard and run any other code 
  11.             Exit Sub        
  12.         End If 
  13.     End If
  14.     'close the app if the login was incorrect 
  15.     MsgBox "Username/password combination is invalid." & _ 
  16.     vbCrLf & vbCrLf & "Exiting application.", vbCritical 
  17.     Application.Quit 
  18.  
  19.  
  20. ErrorTrap:
  21.     MsgBox "Error #" & Err & ", " & Err.Description & _
  22.     vbCrLf & vbCrLf & "Please report error code to your System Administrator."
  23.     'in a normal case, we'd just put in the following lines:
  24.     rs.Close
  25.     Set rs = Nothing
  26.     'However, since we don't want anyone sneaking into our system 
  27.     'by forcing an error, we'll quit the application, which will
  28.     'clear the memory buffer anyway
  29.     Application.Quit
  30. End Sub 
Dec 9 '09 #3
topher23
234 Expert 100+
Also by way of clarification, I generally have different messages display for when the username is incorrect and when the password is incorrect, which is why they're evaluated separately. The single message about the username/password combination in this example was for simplicity's sake.

I also allow users three chances before I log the failed login into a table and kick them off. But again, that increases the complexity of the code for the example. I just wanted to show the MD5 hash in action, not do a full article on securing databases.
Dec 9 '09 #4
NeoPa
32,556 Expert Mod 16PB
There is no need to loop then...
I looked over and over my code looking for a loop, and then realized you probably meant this:
Expand|Select|Wrap|Line Numbers
  1.     If rs.NoMatch Then GoTo ErrorOut
You're absolutely right there. I did misread your code. As you say, this simply comes down to preference, and while mine may be different from yours, I certainly wouldn't see your choice as wrong in any way whatsoever.

I think my brain wasn't properly kicked in at the time (Not that it should be kicked in in a literal sense of course).
Dec 10 '09 #5
patjones
931 Expert 512MB
I just want to vouch for the concept. I have used the MD5 algorithm in a number of projects for password protection and once for encryption of Social Security numbers. Generally I don't like to put Social Security numbers in my databases but on one occasion it was called for, and the MD5 hash really helped out.

Thanks for posting this!
Dec 11 '09 #6

Sign in to post your reply or Sign up for a free account.

Similar topics

1
by: Stephen | last post by:
Hi, is there a way to email users their forgotten passwords using ASP.NET? Stephen
2
by: Matt | last post by:
Hello, I would like to generate what I call an "overall class hierarchy" in UML automatically derived from my C++ code source. An example of what I seek: ...
42
by: WindAndWaves | last post by:
Dear All Can you tell me why you use a class module??? Thank you Nicolaas ---
4
by: Brad Parks | last post by:
Are there any performance or memory-usage benefits of placing public functions and subroutines in a Class Module rather than a standard module?
0
by: redowl | last post by:
Hi, I am trying to generate a User Control using XSLT but can't work out how to declare a valid namespace for it. I have included the @Control directive within the aspx page but still get the...
1
by: c2015 | last post by:
I need help with some VB code. I will keep it generic and clear as possible. I have two forms lets call Form1 and Form2 I have a class module (CM) and a sub class module (SCM) instantiated in...
6
by: =?Utf-8?B?TmFt?= | last post by:
Using Response.Redirect(“error.htm”) in the catch block of a try-catch statement, I am redirecting a page to a generic page if an error occurs in code-behind of the page. Since...
1
by: Fred | last post by:
****This message has been posted in microsoft.public.dotnet.framework several days before and received no reply, so I post it here, sorry if you get duplicate messages**** Hi, all: I'm new to...
0
by: vanijampani | last post by:
Hi, I tried to generate text to audio using JMF. This is my sample code: import java.io.*; import java.util.*; import java.awt.Dimension;
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.