Reputation: 1500
I am implementing a new password stored procedure into my companies current product. It is a ASP.NET application with MS SQL Server.
Before they used 3DES encryption off the same common seed to encrypt, and to check a users authentication they just decrypted the password using the same seed.
I am implementing a SHA256 hash, with a salt that can not be decrypted.
Firstly, I understand that every salt should be different per user, but I don't understand where this salt would be stored? If its stored in the database, doesn't this void its purpose?
My idea was creating a salt by taking the first 4 letters of the username, the first 3 letters of the first name, and the first 3 letters of the last name, and converting it into a md5 hash and then using that as the salt without storing in the database.
This sequence would be server side so that no hacker could know the sequence without the source code.
Is there any issues with what I am doing here?
Also is SHA256 acceptable or should I be looking at SHA512.
Thanks
Upvotes: 0
Views: 828
Reputation: 1839
The salt is NOT supposed to be private. It is distributed along with the hash, usually prepended to it. The sole purpose of the salt is to make sure that if the same data is encrypted twice you never get the same output. By definition it has to be unique, but randomness or secrecy is not required.
You should also NOT create a random number per user. The salt needs to be different for every encryption, even for the same user. Just generate a random salt, use it to create your hash, prepend the salt to the hash, encode everything to base64, and store it. To verify the hash you decode to binary, extract the salt, use it to hash your input data and compare with the decoded hash.
Something that works well as a salt is a GUID. 128 bits, by definition unique, although not totally random, and available instantly without any additional code. Here is an example of an AES-256 encrypt and decrypt. Keep in mind in a real implementation you would want the plain text and key to be stored in SecureString objects...
Private blockSize = 128
Private keySize = 256
Private cipherMode = CipherMode.CBC
Protected Function AESEncryptStringToBase64(strPlainText As String, strKey As String) As String
Dim Algo As AesManaged = AesManaged.Create()
With Algo
.BlockSize = blockSize
.FeedbackSize = blockSize
.KeySize = keySize
.Mode = cipherMode
.IV = Guid.NewGuid().ToByteArray()
.Key = Encoding.ASCII.GetBytes(strKey)
End With
Using Encryptor As ICryptoTransform = Algo.CreateEncryptor()
Using MemStream As New MemoryStream
Using CryptStream As New CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write)
Using Writer As New StreamWriter(CryptStream)
Writer.Write(strPlainText)
End Using
AESEncryptStringToBase64 = Convert.ToBase64String(Algo.IV.Concat(MemStream.ToArray()).ToArray())
End Using
End Using
End Using
End Function
Protected Function AESDecryptBase64ToString(strCipherText As String, strKey As String) As String
Dim arrSaltAndCipherText As Byte() = Convert.FromBase64String(strCipherText)
Dim Algo As AesManaged = AesManaged.Create()
With Algo
.BlockSize = blockSize
.FeedbackSize = blockSize
.KeySize = keySize
.Mode = cipherMode
.IV = arrSaltAndCipherText.Take(16).ToArray()
.Key = Encoding.ASCII.GetBytes(strKey)
End With
Using Decryptor As ICryptoTransform = Algo.CreateDecryptor()
Using MemStream As New MemoryStream(arrSaltAndCipherText.Skip(16).ToArray())
Using CryptStream As New CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read)
Using Reader As New StreamReader(CryptStream)
AESDecryptBase64ToString = Reader.ReadToEnd()
End Using
End Using
End Using
End Using
End Function
Upvotes: 0
Reputation: 700700
"Is there any issues with what I am doing here?"
Yes, there is. Obscurity is not security. Just because the salt is hard to find out doesn't mean that it's very secure. Figuring out how you created the salt would be a piece of cake compared to forcing the hash.
There is no need to keep the salt secret, just create a random number for each user and store along with the password. The purpose of the salt is to elliminate the advantages of using rainbow tables to crack all the passwords in a table. The salt just have to be different for most users (preferably unique, but that's not crucial).
Upvotes: 2
Reputation: 14428
If you absolutely must implement this yourself (personally I'm a fan of MembershipReboot, then you should take a look at PBKDF2 for password storage.
Not only will it implement the salt properly, it also supports multiple iterations to help deter brute force attacks. You can find guidance for the number of iterations here.
Also worth noting, PBKDF2 is an acceptable NIST standard in case validation is a concern.
To answer your question about keeping the salt in the database, there's no need to keep it secret. The purpose of the salt is simply to prevent pre-computation of hashes, not obfuscate or 'encrypt' in any way.
Rainbow tables work by pre-computing passwords, and then when brute forcing, looking up the respective hash in the rainbow table. You can actually see how simple it is by googling MD5 hashes, and often in the search results you'll find the original input.
For example, if you google the string '5f4dcc3b5aa765d61d8327deb882cf99', you'll find it corresponds to 'password'.
By using a salt, the attacker must compute unique hashes for every possible password, instead of just a generalized list.
Upvotes: 2