score:2
"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
- Correctly Salting a Hash in .NET
- Generate MD5 hash string with T-SQL
- How to check correctly if a temporary table exists in SQL Server 2005?
- hash a SQL row?
- Calculate Hash or Checksum for a table in SQL Server
- EF 6 - How to correctly perform parallel queries
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
- SQL How to correctly set a date variable value and use it?
- Microsoft SQL Server Data Tools package did not load correctly
- advantages in specifying HASH JOIN over just doing a JOIN?
- How to correctly and efficiently reuse a prepared statement in C# .NET (SQL Server)?
- Pros and cons of using MD5 Hash as the primary key vs. use a int identity as the primary key in SQL Server
- C# Hash SHA256Managed is not equal to TSQL SHA2_256
- Generate a hash for a set of rows in sql server
- Why generated MD5 hash in sql server are not equal?
- Microsoft.SqlServer.Types in ASP NET Core
- SSRS Not sorting correctly
- SQL Server Hash Indexes
- How can I store a hash in a SQL Server database using C#?
- Optimize SQL Query to avoid Hash Match (Aggregate)
- Storing a SHA512 Password Hash in Database
- SQL bigint hash to match c# int64 hash
- Cyrillic symbols in SQL code are not correctly after insert
- Decimal places not rounding correctly - is this a LINQ to SQL bug?
- CHAR(64) or BINARY(32) To Store SHA256 Hash in SQL SERVER
- How to correctly insert newline in nvarchar
- Compute MD5 hash of a UTF8 string
- How to correctly use Laravel with SQL Server instead on MySQL?
- Report dates not working correctly if date format is not mm/dd/yyyy
- Get hash values from SQL Server and Oracle and compare them?
- How to correctly setup the connection string to availability group for legacy app
More questions with similar tag
- SQL Query Get counts for everyday day of the month
- SQL Server -> Sybase
- SQL Server: Clustered index considerably slower than equivalent non-clustered index
- Get columns name from a table in database
- Sql query involving two tables
- How to select output of XML Path query in SQL?
- Error altering a table in SQL Server Management Studio
- Query to filter where value equals @param unless @param is other
- How to persist a calculated GEOMETRY or GEOGRAPHY column
- T-SQL: Round to nearest 15 minute interval
- SQL Server: Lead/Lag analytic function across groups (and not within groups)
- Proper use of @@Error in SQL Server 2000
- How can I use a table variable as a parameter for OPENQUERY
- SQl Server Query against Server Group
- How to install localdb separately?
- How To Show StoredProcedure Result in MVC View
- Could not obtain information about windows nt group/user sql server error
- DISTINCT is not working for SELECT query in MSSQL
- XML tag.value not working in SQL 2014
- Get a list of end of months dates between two months in SQL Server
- Computed Column Specification in SQL Server - Time Difference in hours or minutes
- Does NHibernate support MsSql2008? Can it convert SQL XML DataType to XElement properties?
- Subquery returned more than 1 value. This is not permitted when
- MSSQL 2017 - Inserting large data sets efficiently
- TSQL optimizing code for NOT IN
- Creating a SQL Server database from Python
- Updating values in SQL Server database with MVC
- Inserting data in snowflake using Copy into from stage files
- SQL CASE with WHILE loop in not working
- Communication link failure error message