forked from ServiceStack/ServiceStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSaltedHash.cs
More file actions
109 lines (86 loc) · 3.58 KB
/
SaltedHash.cs
File metadata and controls
109 lines (86 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
using System;
using System.Security.Cryptography;
using System.Text;
namespace ServiceStack.ServiceInterface.Auth
{
/// <summary>
/// Thank you Martijn
/// http://www.dijksterhuis.org/creating-salted-hash-values-in-c/
/// </summary>
public class SaltedHash
{
readonly HashAlgorithm HashProvider;
readonly int SalthLength;
public SaltedHash(HashAlgorithm HashAlgorithm, int theSaltLength)
{
HashProvider = HashAlgorithm;
SalthLength = theSaltLength;
}
public SaltedHash() : this(new SHA256Managed(), 4) {}
private byte[] ComputeHash(byte[] Data, byte[] Salt)
{
var DataAndSalt = new byte[Data.Length + SalthLength];
Array.Copy(Data, DataAndSalt, Data.Length);
Array.Copy(Salt, 0, DataAndSalt, Data.Length, SalthLength);
return HashProvider.ComputeHash(DataAndSalt);
}
public void GetHashAndSalt(byte[] Data, out byte[] Hash, out byte[] Salt)
{
Salt = new byte[SalthLength];
var random = new RNGCryptoServiceProvider();
random.GetNonZeroBytes(Salt);
Hash = ComputeHash(Data, Salt);
}
public void GetHashAndSaltString(string Data, out string Hash, out string Salt)
{
byte[] HashOut;
byte[] SaltOut;
GetHashAndSalt(Encoding.UTF8.GetBytes(Data), out HashOut, out SaltOut);
Hash = Convert.ToBase64String(HashOut);
Salt = Convert.ToBase64String(SaltOut);
}
public bool VerifyHash(byte[] Data, byte[] Hash, byte[] Salt)
{
var NewHash = ComputeHash(Data, Salt);
if (NewHash.Length != Hash.Length) return false;
for (int Lp = 0; Lp < Hash.Length; Lp++)
if (!Hash[Lp].Equals(NewHash[Lp]))
return false;
return true;
}
public bool VerifyHashString(string Data, string Hash, string Salt)
{
byte[] HashToVerify = Convert.FromBase64String(Hash);
byte[] SaltToVerify = Convert.FromBase64String(Salt);
byte[] DataToVerify = Encoding.UTF8.GetBytes(Data);
return VerifyHash(DataToVerify, HashToVerify, SaltToVerify);
}
}
/*
/// <summary>
/// This little demo code shows how to encode a users password.
/// </summary>
class SaltedHashDemo
{
public static void Main(string[] args)
{
// We use the default SHA-256 & 4 byte length
SaltedHash demo = new SaltedHash();
// We have a password, which will generate a Hash and Salt
string Password = "MyGlook234";
string Hash;
string Salt;
demo.GetHashAndSaltString(Password, out Hash, out Salt);
Console.WriteLine("Password = {0} , Hash = {1} , Salt = {2}", Password, Hash, Salt);
// Password validation
//
// We need to pass both the earlier calculated Hash and Salt (we need to store this somewhere safe between sessions)
// First check if a wrong password passes
string WrongPassword = "OopsOops";
Console.WriteLine("Verifying {0} = {1}", WrongPassword, demo.VerifyHashString(WrongPassword, Hash, Salt));
// Check if the correct password passes
Console.WriteLine("Verifying {0} = {1}", Password, demo.VerifyHashString(Password, Hash, Salt));
}
}
*/
}