Hopefully I have driven home the facts that salts are an important part of keeping a hash secure. We have done this using the strong random number generator of RNGCryptoServiceProvider. Now just because we applied a salt does not mean that our hash is rock solid. The hash and salt usually sit next to each other in the database/file they are stored in like so:

UserId UserName Hash Salt Creation
100 John eiqkluw9vbj3qw4io4hytrweg35 asdt234l;jt62lj652q346 6/7/2002
101 Sam 34723lkdsgoqep78t31jgto326 w46kjlqaklrejh3234l6j3 2/5/2004

If I were to steal this database I know that you have salted your passwords and a rainbow table type of attack will not be easy (as I would need a massive rainbow table to crack a hash). Instead I would be looking at a brute force attack using the known salt by using this method:

dim computedHash as string =  ComputeHash(randomWord & "asdt234l;jt62lj652q346")
if computedHash = "eiqkluw9vbj3qw4io4hytrweg35" then 
      alert("Johns Password Is: " & randomWord)
end if


Unique Salt Placement
In the last example I made the assumption that the salt was added to the end of the word to create the hash. There is no reason that as a developer I could use any one of these methods to create a hash:

String hash = ComputeHash(password + salt)
String hash = ComputeHash(salt + password)
String hash = ComputeHash(salt + password+ salt)
String hash = ComputeHash(pass + salt + word)
... etc.

All of the above examples will result in a different hash of course but by joining the salt and the password in a unique way adds some security.

Salt In Another Table
One technique is to separate the salt and hash from being in the same table. This might fool an attacker if they don't know anything about databases or just don't look around to see if their is salt data related to the password record. To me additional programming effort is not worth it to add this trivial defence in (but every bit can help)

Salt Not Obviously Stored
A technique I like is to not store a salt in a salt column. Instead I generate it off some fixed data that is associated with the user. In the above table we have a creation date. This date will never change so to generate a salt we can take a hash of the creation date!

dim Salt as string = ComputeHash(user.creationDate)
dim hash as string = (user.password + Salt)

So if we were to use this technique we would no longer have a salt column as it is now generated based on the users creation date. One thing to watch out for in this technique is to ensure the data is non-changing. If we used the users phone number to generate our salts and the user changed their phone number they could no longer log in (try explaining that one).

For this technique you could also use a GUID that you may have for a user. I would shy away from using an auto incrementing ID as that would be fairly trivial to predict.

Add Fixed Salt Data
One thing that can also be done is adding in a hardcoded bit of random data in addition to a per user salt like so:

String hash = ComputeHash(password + salt + "DRASFH%$!CJ^R##$^ADFH")

If an attacker were to steal the database they would know that the password is salted but would have a hard time brute forcing the password as they are missing the hard coded application data that was injected into the hash.

Conclusion
All of the techniques I have shown are about obfuscating the techniques used to generate salts and hashes. If an attacker were to gain access to more than just the data (i.e. source code or even the binaries) they could determine the technique used and start cracking.

By adding another layer though we have reduced our attack surface. Our attacker now needs not only database/file access but access to the code (either source or binaries). Our attacker also needs to have more knowledge. They now need to know about cracking hashes, database systems (if we are using a database as storage), how to gain access to the code, and how to decompile/read code.

Just remember to balance the time/complexity of your hash generation technique with your security requirements. You could easily spend a lot of time making a super solid mechanism for salt/hash generation but is that really worth it when all you are protecting is a users list of favourite movies?