Create a hash from an id and sign it - c#

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)

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.

c# Generate Random number passing long as seed instead of int32

c# Generate Random number passing long as a seed instead of int32, but l need to pass phone numbers or accounts number
https://learn.microsoft.com/en-us/dotnet/api/system.random.-ctor?view=netframework-4.8#System_Random__ctor_System_Int32_
Please suggest any reliable NuGet package which does this or any implementation who has already done something like this.
I need to pass the complete PhoneNumber as the seed which I'm able to do in python but not with C# and my code stack is all in C#
using System;
public class Program
{
public static void Main()
{
int seed = 0123456789;
Random random = new Random(seed);
double result = random.NextDouble();
Console.WriteLine(result);
}
}
Some insights on my requirements and what I'm trying to achieve:
1)We're doing this for A/B testing and todo data analysis on the
experience of two services.
2)When a request comes with
phoneNumber based on random.NextDouble() there is a preset percentage
which we use to determine whether to send a request to service A or
service B
3)For example, let's says the request comes and falls
under >0.5 then we direct the request to service A and the next time
the request with the same phone number comes in it will be >0.5 and
goes service A since the seed is a unique hash of phoneNumber.
The method GetHashCode() belongs to Object class, it has nothing to do with random number generation. Please read here (https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netframework-4.8). The documentation clearly states that it is possible to get collisions specially if input is consistent.
The method HashAlgorithm.ComputeHash (documented here - https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.hashalgorithm.computehash?view=netframework-4.8) calculates the hash for a given value, but it is consistent in nature, i.e. if input is same, generated output is also same. Obviously this is not the desired output (I assume). I have attached the sample code I tried to generate this.
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
while (true)
{
Console.WriteLine("Enter a 9 digit+ number to calculate hash");
var val = Console.ReadLine();
long target = 0;
bool result = long.TryParse(val,out target);
if (result)
{
var calculatedHash = OutputHash(target);
Console.WriteLine("Calculated hash is : " + calculatedHash);
}
else
{
Console.WriteLine("Incorrect input. Please try again.");
}
}
}
public static string OutputHash(long number)
{
string source = Convert.ToString(number);
string hash;
using (SHA256 sha256Hash = SHA256.Create())
{
hash = GetHash(sha256Hash, source);
Console.WriteLine($"The SHA256 hash of {source} is: {hash}.");
Console.WriteLine("Verifying the hash...");
if (VerifyHash(sha256Hash, source, hash))
{
Console.WriteLine("The hashes are the same.");
}
else
{
Console.WriteLine("The hashes are not same.");
}
}
return hash;
}
private static string GetHash(HashAlgorithm hashAlgorithm, string input)
{
// 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.
return sBuilder.ToString();
}
// Verify a hash against a string.
private static bool VerifyHash(HashAlgorithm hashAlgorithm, string input, string hash)
{
// Hash the input.
var hashOfInput = GetHash(hashAlgorithm, input);
// Create a StringComparer an compare the hashes.
StringComparer comparer = StringComparer.OrdinalIgnoreCase;
return comparer.Compare(hashOfInput, hash) == 0;
}
I agree with #Knoop 's comment above that you might end up with same integer mapping to multiple long number input values.
If you are looking for a 'pure' random number generator with long value as seed, you don't have a choice but to go for third party libraries (or implementing your own custom algorithm). However, rather than getting into such complexities, simple
Guid g = Guid.NewGuid();
should do the trick (https://learn.microsoft.com/en-us/dotnet/api/system.guid.newguid?view=netframework-4.8).
Documentation (https://learn.microsoft.com/en-gb/windows/win32/api/combaseapi/nf-combaseapi-cocreateguid?redirectedfrom=MSDN )says that even this can end up having collisions but chances are very minimal.
Finally, this sounds like potential duplicate of .NET unique object identifier
take the hash of the phone number, eg:
var phoneNumber = 123456789L;
var seed = phoneNumber.GetHashCode();
This means that for the same phoneNumber you will get the same sequence. It also means that for some phone numbers you will get identical sequences, but that is going to be slim. And it might be different on different .net runtimes as commented, but you might not care.
Not sure why you want to, but I there are reasons, e.g. test code

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 :)

Fixed salt generation based on input string - 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.

GUID must be 16 bytes long

I am trying to overload a method which uses a Guid as its parameter with another method that has a string as its parameter.
// read a student object from the dictionary
static public User Retrieve(Guid ID)
{
User user;
// find the Guid in the Dictionary
user = Users[ID];
return user;
}
static public User Retrieve(string Email)
{
User user;
Guid id;
// find the Guid in the Dictionary
using (SHA1 sha1 = SHA1.Create())
{
byte[] hash = SHA1.ComputeHash(Encoding.Default.GetBytes(Email));
id = new Guid(hash);
}
user = Users[id];
return user;
}
Test Results
Result Message:
Test method SRS.CRUDUsers.UpdateStudent threw exception:
System.ArgumentException: Byte array for GUID must be exactly 16 bytes long.
Test Method:
public void UpdateStudent()
{
// Arrange
Student expected = (Student)UserRepo.Retrieve("info#info.com");
// Act
Student actual = (Student)UserRepo.Retrieve("info#info.com");
actual.FirstName = "Joe";
actual.LastName = "Brown";
actual.Birthday = new DateTime(1977, 2, 23);
actual.DegreeSelected = 1;
// Assert (this is only really checking the object agains itself
// because both variables are referencing the same object).
Assert.IsNotNull(actual.ID);
Console.WriteLine(actual.ID);
Assert.AreEqual(expected.Name, actual.Name);
Assert.AreEqual(expected.GetType(), actual.GetType());
Assert.AreEqual(expected.Birthday, actual.Birthday);
Assert.AreEqual(expected.Age, actual.Age);
}
It seems to be a type issue so probably something obvious.
From wiki:
SHA-1 produces a 160-bit (20-byte)
Error:
Byte array for GUID must be exactly 16 bytes long.
So you can't just use SHA1 as Guid. You can try MD5 (it is 128) if this is not security related code.
Try following
new Guid(hash.Take(16).ToArray())
Or you can use MD5 hash, since it is a 16-byte hash
var md5 = MD5.Create();
var hash = md5.ComputeHash(Encoding.Default.GetBytes(Email));
new Guid(hash);

Categories