score:2

Accepted answer

"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).

Read More

score:0

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

score:2

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.


More questions with similar tag