Return to Click to read this topic4/13/2008 5:51:00 PM - appleberry9
HomePage
Hash a Password Using a Random Salt (VB)
Applies to
- ASP.NET 2.0
- VB
- Server-side
Summary
The purpose of this code snippet is to demonstrate how to implement secure password persistence using a cryptographic hashing algorithm with a randomly generated "salt" (or "nonce") value. Cryptographic hashing algorithms are one-way encryption algorithms used to store sensitive data in a non-readable format. A salt can be used in conjunction with cryptographic hashing to add additional entropy to encrypted values and to protect against pre-computed hash or dictionary attacks on a compromised hash value.
Objectives
- Protect user credentials
- Avoid storing user passwords
- Protect against certain brute-force attacks on a compromised hash value
- Generate a cryptographically random value for the salt that cannot be predicted
- Add enough entropy to the password hash to increase the difficulty of a cracking attempt exponentially
Solution Example
Function CreatePasswordHash(password As String) As Byte()
' Convert the string password value to a byte array
Dim passwordData As Byte() = UnicodeEncoding.ASCII.GetBytes(password)
' Create a 4-byte salt using a cryptographically secure random number generator
Dim saltData(4) As Byte
Dim rng As New RNGCryptoServiceProvider()
rng.GetNonZeroBytes(saltData)
' Append the salt to the end of the password
Dim saltedPasswordData(passwordData.Length + saltData.Length) As Byte
Array.Copy(passwordData, 0, saltedPasswordData, 0, passwordData.Length)
Array.Copy(saltData, 0, saltedPasswordData, passwordData.Length, saltData.Length)
' Create a new SHA-1 instance and compute the hash
Dim sha As New SHA1Managed()
Dim hashData As Byte() = sha.ComputeHash(saltedPasswordData)
' Optional - add salt bytes onto end of the password hash for storage
Dim APPEND_SALT_TO_HASH As Boolean = True
If APPEND_SALT_TO_HASH Then
Dim hashSaltData(hashData.Length + saltData.Length) As Byte
Array.Copy(hashData, 0, hashSaltData, 0, hashData.Length)
Array.Copy(saltData, 0, hashSaltData, hashData.Length, saltData.Length)
Return hashSaltData
Else
Return hashData
End If
End Function
Problem Example
The following code snippet shows password hashing without the use of a salt and using a weaker hashing algorithm.
' password is obtained from the user as a VB string
Dim password As String = Request.Form("password")
' Convert the string password value to a byte array
Dim passwordData As Byte() = UnicodeEncoding.ASCII.GetBytes(password)
' Create a new MD5 instance and compute the hash
Dim md5 As New MD5CryptoServiceProvider()
Dim hashData As Byte() = md5.ComputeHash(passwordData)
- Hash values are vulnerable to pre-computed hash attacks
- Depending on password value, password hash may also be vulnerable to a dictionary attack
- MD5 offers less encryption strengtgh than SHA-1 and has recently been "broken" by cryptography researchers
Test Case
The following classes must be included in any project making use of the sample code provided above:
Imports System.Security.Cryptography
Imports System.Text
Execute a test encryption and comparison of a salted password hash
using the following test case methods:
Sub Main(ByVal args() As String)
' Create a Hash and compare to two subsequent hashes
Dim hash() As Byte = CreatePasswordHash("foobar")
Console.WriteLine("Created new salted hash for 'foobar'")
Console.WriteLine("foobar produces same hash:" + ComparePasswordToHash("foobar", hash).ToString())
Console.WriteLine("fo0bar produces same hash:" + ComparePasswordToHash("f0obar", hash).ToString())
End Sub
Function ComparePasswordToHash(ByVal password As String, ByVal hashData() As Byte) As Boolean
' First, pluck the four-byte salt off of the end of the hash
Dim saltData() As Byte = New Byte(4) {}
Array.Copy(hashData, hashData.Length - saltData.Length, saltData, 0, saltData.Length)
' Convert Password to bytes
Dim passwordData() As Byte = UnicodeEncoding.ASCII.GetBytes(password)
' Append the salt to the end of the password
Dim saltedPasswordData() As Byte = New Byte(passwordData.Length + saltData.Length) {}
Array.Copy(passwordData, 0, saltedPasswordData, 0, passwordData.Length)
Array.Copy(saltData, 0, saltedPasswordData, passwordData.Length, saltData.Length)
' Create a new SHA-1 instance and compute the hash
Dim sha As SHA1Managed = New SHA1Managed()
Dim NewHashData() As Byte = sha.ComputeHash(saltedPasswordData)
' Add salt bytes onto end of the password hash for storage
Dim NewHashSaltData() As Byte = New Byte(NewHashData.Length + saltData.Length) {}
Array.Copy(NewHashData, 0, NewHashSaltData, 0, NewHashData.Length)
Array.Copy(saltData, 0, NewHashSaltData, NewHashData.Length, saltData.Length)
' Compare and return
Return (Convert.ToBase64String(hashData).Equals(Convert.ToBase64String(NewHashSaltData)))
End Function
Expected Result
Created new salted hash for 'foobar'
foobar produces same hash: True
fo0bar produces same hash: False
Scenarios
- Application makes use of a dedicated user account management system and stores passwords
- Application stores a "Secret Question/Answer" credential for password reset operations
- Application requires storage of highly sensitive data (social security number, credit card number, etc) but does not need to retrieve that data
More Information
Password hash and salt values should always be securely protected in storage. An attacker able to compromise a specific hash and salt value from a database may succeed in using other types of brute-force attacks against the compromised hash.
In the example given, the four-byte salt would require an attacker to maintain 4.3 trillion values for every given plaintext value. Assuming the victim required passwords of only 4 alphabetical characters in length with no other complexity requirements (a very weak password policy by our standards), defeating a four-byte salt would require the attacker to have a database of 2 x 10^15 precomputed hashes handy. Assuming each of these hashes only required one byte to store, this would require 2 petabytes of storage.
Additional Resources
Attributes
- Applies To: .NET Framework 2.0, VB
- Category: Cryptography
- Author: Jonathan Bailey