Skip to content

Commit 558ef07

Browse files
committed
Extract an interface from SaltedHash
1 parent bb159fc commit 558ef07

1 file changed

Lines changed: 116 additions & 108 deletions

File tree

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

0 commit comments

Comments
 (0)