Fixed salt generation based on input string - C# - c#

I have this simple class which has 2 methods:
private static byte[] PBKDF2(string field, byte[] salt, int iterations, int outputBytes)
{
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(field, salt);
pbkdf2.IterationCount = iterations;
return pbkdf2.GetBytes(outputBytes);
}
public static string CreateHash(string field, String salt)
{
//if (Array.TrueForAll(salt, x => x == 0))
//{
// RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
// csprng.GetBytes(salt);
// string s = Convert.ToBase64String(salt);
//}
byte[] salts = Encoding.ASCII.GetBytes(salt);
byte[] hash = PBKDF2(field, salts, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
return Convert.ToBase64String(hash);
}
I need to provide a front-end where user enters a simple string like "abc" and I need to generate a salt based on that. This is what I am going to store in the database and use it to pass to the above method (CreateHash) to de-identify
data. This salt/key needs to be able to get decrypted back, which I have to show in the front-end.
I can use other classes/library as well. It need not be Rfc2898DeriveBytes.
Please provide me some inputs on how I can achieve this salt/key generation functionality. This salt can't be a random value.
Thanks!

You mention that you need to decrypt the hashed string.
PBKDF2 is NOT an encryption algorithm, but a key derivation function, and you will not be able to calculate the original input from the resulting hash, with or without the salt.
What you should be looking for is encryption, not hashing.
Take a look at this link for some examples.

Related

Generate unique ID from string in C#

I need my app to handle a list of mods from a database and a list of locally downloaded mods that aren't.
Each mod of the database has a unique uint ID that I use to identify him but local mods don't have any ID.
At first I tried to generate an ID with string.GetHashCode() by using the mod's name but GetHashCode is still randomized at each run of the app.
Is there any other way to generate a persistent uint ID from the mod's name ?
Current code :
foreach(string mod in localMods)
{
//This way I get a number between 0 and 2147483648
uint newId = Convert.ToUInt32(Math.Abs(mod.GetHashCode());
ProfileMod newMod = new ProfileMod(newId);
}
The method GetHashCode() doesn't return the same value for the same string, especially if you re-run the application. It has a different purpose (like checking the equality during runtime, etc.).
So, it shouldn't be used as a unique identifier.
If you'd like to calculate the hash and get consistent results, you might consider using the standard hashing algorithms like MD5, SHA256, etc.
Here is a sample that calculates SHA256:
using System;
using System.Security.Cryptography;
using System.Text;
public class Program
{
public static void Main()
{
string input = "Hello World!";
// Using the SHA256 algorithm for the hash.
// NOTE: You can replace it with any other algorithm (e.g. MD5) if you need.
using (var hashAlgorithm = SHA256.Create())
{
// Convert the input string to a byte array and compute the hash.
byte[] data = hashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
var sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
var hash = sBuilder.ToString();
Console.WriteLine($"The SHA256 hash of {input} is: {hash}.");
}
}
}
Though SHA256 produces longer result than MD5, the risk of the collisions are much lower. But if you still want to have smaller hashes (with a higher risk of collisions), you can use MD5, or even CRC32.
P.S. The sample code is based on the one from the Microsoft's documentation.
So I ended up listening to your advises and found a good answer in another post by using SHA-1
private System.Security.Cryptography.SHA1 hash = new System.Security.Cryptography.SHA1CryptoServiceProvider();
private uint GetUInt32HashCode(string strText)
{
if (string.IsNullOrEmpty(strText)) return 0;
//Unicode Encode Covering all characterset
byte[] byteContents = Encoding.Unicode.GetBytes(strText);
byte[] hashText = hash.ComputeHash(byteContents);
uint hashCodeStart = BitConverter.ToUInt32(hashText, 0);
uint hashCodeMedium = BitConverter.ToUInt32(hashText, 8);
uint hashCodeEnd = BitConverter.ToUInt32(hashText, 16);
var hashCode = hashCodeStart ^ hashCodeMedium ^ hashCodeEnd;
return uint.MaxValue - hashCode;
}
Could probably be optimized but it's good enough for now.
I wouldn't trust any solution involving hashing or such. Eventually you will end-up having conflicts in the IDs especially if you have huge amount of records on your DB.
What I would prefer to do is to cast the int ID of the DB to a string when reading it and then use some function like Guid.NewGuid().ToString() to generate a string UID for the local ones.
This way you will not have any conflict at all.
I guess that you will have to employ some kind of such strategy.

How to hash and/or salt passwords in UWP c#? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
After lots of google searches I really cant seem to find out how to hash passwords in c# UWP, I've tried Bcrypt but that is not available for RT. Any ideas how I can hash my passwords in UWP? This is my first app in UWP so I thought everything would work like in WPF, seems like I was wrong. I have tried the BCRYPT from Nugetstore but nothing will run on UWP.
I just need a simple way to hash and/or salt a string and a simple way to validate the hash.
How about this approach(using System.Security.Cryptography):
To store user passwords in the database in a way that they cannot be extracted, the passwords need to be hashed using a one-way hashing algorithm such as SHA1
To do so, use the RNGCryptoServiceProvider to create a random salt, append the salt to the password, hash it using SHA1 CryptoServiceProvider class, and store the resulting string in the database along with the salt
The benefit provided by using a salted password is making a lookup table assisted dictionary attack against the stored values impractical, provided the salt is large enough
Sample Code:
// Create salted password to save in database.
private byte [] CreateDbPassword(byte[] unsaltedPassword)
{
//Create a salt value.
byte[] saltValue = new byte[saltLength];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(saltValue);
return CreateSaltedPassword(saltValue, unsaltedPassword);
}
// Create a salted password given the salt value.
private byte[] CreateSaltedPassword(byte[] saltValue, byte[] unsaltedPassword)
{
// Add the salt to the hash.
byte[] rawSalted = new byte[unsaltedPassword.Length + saltValue.Length];
unsaltedPassword.CopyTo(rawSalted,0);
saltValue.CopyTo(rawSalted,unsaltedPassword.Length);
//Create the salted hash.
SHA1 sha1 = SHA1.Create();
byte[] saltedPassword = sha1.ComputeHash(rawSalted);
// Add the salt value to the salted hash.
byte[] dbPassword = new byte[saltedPassword.Length + saltValue.Length];
saltedPassword.CopyTo(dbPassword,0);
saltValue.CopyTo(dbPassword,saltedPassword.Length);
return dbPassword;
}
// Compare the hashed password against the stored password.
private bool ComparePasswords(byte[] storedPassword, byte[] hashedPassword)
{
if (storedPassword == null || hashedPassword == null || hashedPassword.Length != storedPassword.Length - saltLength)
return false;
// Get the saved saltValue.
byte[] saltValue = new byte[saltLength];
int saltOffset = storedPassword.Length - saltLength;
for (int i = 0; i < saltLength; i++)
saltValue[i] = storedPassword[saltOffset + i];
byte[] saltedPassword = CreateSaltedPassword(saltValue, hashedPassword);
// Compare the values.
return CompareByteArray(storedPassword, saltedPassword);
}
// Compare the contents of two byte arrays.
private bool CompareByteArray(byte[] array1, byte[] array2)
{
if (array1.Length != array2.Length)
return false;
int mismatch = 0;
for (int i = 0; i < array1.Length; i++)
{
mismatch |= array1[i] ^ array2[i];
}
return mismatch == 0;
}
MSDN: https://msdn.microsoft.com/en-us/library/aa288534(v=vs.71).aspx
UPDATE
For UWP apps you need to use the namespace Windows.Security.Cryptography.Core:
public String SampleDeriveFromPbkdf(
String strAlgName,
UInt32 targetSize)
{
// Open the specified algorithm.
KeyDerivationAlgorithmProvider objKdfProv = KeyDerivationAlgorithmProvider.OpenAlgorithm(strAlgName);
// Create a buffer that contains the secret used during derivation.
String strSecret = "MyPassword";
IBuffer buffSecret = CryptographicBuffer.ConvertStringToBinary(strSecret, BinaryStringEncoding.Utf8);
// Create a random salt value.
IBuffer buffSalt = CryptographicBuffer.GenerateRandom(32);
// Specify the number of iterations to be used during derivation.
UInt32 iterationCount = 10000;
// Create the derivation parameters.
KeyDerivationParameters pbkdf2Params = KeyDerivationParameters.BuildForPbkdf2(buffSalt, iterationCount);
// Create a key from the secret value.
CryptographicKey keyOriginal = objKdfProv.CreateKey(buffSecret);
// Derive a key based on the original key and the derivation parameters.
IBuffer keyDerived = CryptographicEngine.DeriveKeyMaterial(
keyOriginal,
pbkdf2Params,
targetSize);
// Encode the key to a hexadecimal value (for display)
String strKeyHex = CryptographicBuffer.EncodeToHexString(keyDerived);
// Return the encoded string
return strKeyHex;
}
After trying all of the above answers ( thanks a lot for helping tho ) i desided to go with MD5 hashing even through i know its a really really weak hashing and have no salt its fine for my need. I hash my passwords in UWP with the following code:
private static string ComputeMD5(string str)
{
var alg = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
IBuffer buff = CryptographicBuffer.ConvertStringToBinary(str, BinaryStringEncoding.Utf8);
var hashed = alg.HashData(buff);
var res = CryptographicBuffer.EncodeToHexString(hashed);
return res;
}
I have a very simple library on GitHub to do just that which is much better than using SHA directly. It uses MS PBKDF2 inside via Rfc2898DeriveBytes (no fancy invented home-brew algorithms in there) and is as easy to use as BCrypt.
I have a nuget package as well, but I suppose you'll need to compile it yourself to use with UWP.
Example usage:
ISimpleHash simpleHash = new SimpleHash();
// Creating a user hash, hashedPassword can be stored in a database
// hashedPassword contains the number of iterations and salt inside it similar to bcrypt format
string hashedPassword = simpleHash.Compute("Password123");
// Validating user's password by first loading it from database by username
string storedHash = _repository.GetUserPasswordHash(username);
bool isPasswordValid = false;
if (storedHash != null)
{
isPasswordValid = simpleHash.Verify("Password123", storedHash);
}
P.S. I guess I can even compile it to use with UWP target for nuget if it works for you and I figure out how to do that :)

C# Hash with Collision Domain

I am working on a project that encrypts a string, which is the easy part. The hard part is finding a method to hash the string before encryption that returns a value with a collision domain. That hash will be stored along with the encrypted string in a database table.
The reason for doing this is to create a subset to decrypt when needing to search for a single record. How can this be accomplished using C#?
I assume you need help creating the collision domain, the easiest way to do it is write a function that transforms the string in to a new string that has a high collision chance then hash that new string for your lookup value.
private static int COLLISION_LENGTH = 5;
public static string CreateCollision(string oldValue)
{
var chars = new char[COLLISION_LENGTH];
for(int i = 0; i < oldValue.Length; i++)
{
chars[i % chars.Length] ^= oldValue[i];
}
return new String(chars);
}
You then just need to hash the output of CreateCollision with the hash algorithm of your choice, I recommend using a strong hash system like you would for a password like Rfc2898DeriveBytes and treat the hash like you would a password (you will need to use a fixed salt however) because this hash does leak information about the data you encrypted.
Adjust COLLISION_LENGTH as needed.

Create a hash from an id and sign it

Our user recieve emails with a prepared hyperlink.
This hyperlink has a parameter.
When the user clicks the hyperlink I need to make sure that the user did not tamper with the parameter.
The parameter is a simple integer.
I would like to create a hash from the integer.
I would like to sign the hash.
What are the current .NET classes I should use for this task?
The easiest way to do this is use a HMAC ("keyed-hash message authentication code").
public static string CreateHMAC(int data, byte[] key)
{
using(var hmac = new HMACSHA1(key))
{
var dataArray = BitConverter.GetBytes(data);
var resultArray = hmac.ComputeHash(dataArray);
return Convert.ToBase64String(resultArray);
}
}
You keep key secret on your server, and pass data and the result of CreateHMAC to the user in the URL. When the user clicks the link you verify that the data was not modified.
public static bool VerifyHMAC(int data, byte[] key, string verification)
{
using(var hmac = new HMACSHA1(key))
{
var dataArray = BitConverter.GetBytes(data);
var computedHash = hmac.ComputeHash(dataArray);
var verificationHash = Convert.FromBase64String(verification);
for (int i = 0; i < verificationHash.Length; i++)
{
if (computedHash[i] != verificationHash[i])
{
return false;
}
}
return true;
}
}
You can see here how to calculate the hash.
Since HASH functions accepts only ARRAYS, I advice you to create an array of ONE single item, with your integer there.
You may "sign" the input calculating the HASH of the calculated HASH above PLUS a constant of your application (or date and hour, for instance)

What is the .NET Equivalent of Java's SecretKeySpec class?

I was provided the following code sample in Java and I'm having trouble converting it to C#. How would I go about converting this so it'll work in .NET 4.5?
public static String constructOTP(final Long counter, final String key)
throws NoSuchAlgorithmException, DecoderException, InvalidKeyException
{
// setup the HMAC algorithm, setting the key to use
final Mac mac = Mac.getInstance("HmacSHA512");
// convert the key from a hex string to a byte array
final byte[] binaryKey = Hex.decodeHex(key.toCharArray());
// initialize the HMAC with a key spec created from the key
mac.init(new SecretKeySpec(binaryKey, "HmacSHA512"));
// compute the OTP using the bytes of the counter
byte[] computedOtp = mac.doFinal(
ByteBuffer.allocate(8).putLong(counter).array());
//
// increment the counter and store the new value
//
// return the value as a hex encoded string
return new String(Hex.encodeHex(computedOtp));
}
Here is the C# code that I've come up with thanks to Duncan pointing out the HMACSHA512 class, but I'm unable to verify the results match without installing java, which I can't do on this machine. Does this code match the above Java?
public string ConstructOTP(long counter, string key)
{
var mac = new HMACSHA512(ConvertHexStringToByteArray(key));
var buffer = BitConverter.GetBytes(counter);
Array.Resize(ref buffer, 8);
var computedOtp = mac.ComputeHash(buffer);
var hex = new StringBuilder(computedOtp.Length * 2);
foreach (var b in computedOtp)
hex.AppendFormat("{0:x2", b);
return hex.ToString();
}
A SecretKeySpec is used to convert binary input into something that is recognised by Java security providers as a key. It does little more than decorate the bytes with a little post-it note saying "Pssst, it's an HmacSHA512 key...".
You can basically ignore it as a Java-ism. For your .NET code, you just need to find a way of declaring what the HMAC key is. Looking at the HMACSHA512 class, this seems quite straight-forward. There is a constructor that takes a byte array containing your key value.

Categories