Hello,
I created a class and a few extensions to create a token:
public String Issue(String data) {
Sash sash = new Sash(new SHA256Managed(), 64);
Byte[] hash = sash.CalculateHash(Encoding.UTF8.GetBytes(data), Encoding.UTF8.GetBytes(SaltProvider.GetSalt());
sash.Dispose();
return Convert.ToBase64String(hash);
} // Issue
public Boolean Check(String data, String token) {
Sash sash = new Sash(new SHA256Managed(), 256);
Boolean valid = sash.CheckHash(Encoding.UTF8.GetBytes(data), Encoding.UTF8.GetBytes(SaltProvider.GetSalt()), Encoding.UTF8.GetBytes(token));
sash.Dispose();
return valid;
} // Check
I am building data variable according to the use of the token. Can be for example:
String data = String.Concat(user.Username, user.Created)
But how can I define a Token Issue and Expiration date?
I am not sure how to include this in data and later user as ...
I am not sure how this is usually done.
Could someone, please, help me out?
Thank You,
Miguel
Hello Pete,
The 64/256 mismatch was a typo problem in my code.
I am sending a verification email when a user signs up.
These emails have a verification URL which I am building.
I have seen 3 types of verification URLs as follows:
A)
http://domain.com/verify/HY9UoDigNa-cZzWlvzWNQ3
There is no information on the user (I think).
I suppose the token is saved for later verification.
B)
http://domain.com/verify/username-slug/HY9UoDigNa-cZzWlvzWNQ3
It is passed the username.slug and the token.
C)
http://domain.com/verify/id/HY9UoDigNa-cZzWlvzWNQ3
I don't think passing the user's id is a good idea.
Maybe I am wrong ... So I go for username-slug.
I am creating the Token by concatenating the following User fields:
Username, Email and CreatedDate
I am not sure if you suggest something else ...
Then I hash the data using the following:
Sash sash = new Sash(new SHA256Managed(), 64);
Byte[] hash = sash.CalculateHash(Encoding.UTF8.GetBytes(data), AppSalt));
sash.Dispose();
return Convert.ToBase64String(hash);
AppSalt is a Guid which I use in my application.
My Sash class is the following:
public sealed class Sash : IDisposable {
private Boolean _disposed = false;
private readonly Int32 _repeats;
private readonly HashAlgorithm _algorithm;
private static Int32 _defaultRepeats = 10000;
private static HashAlgorithm _defaultAlgorithm = new SHA256Managed();
private static RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
public Sash(HashAlgorithm algorithm, Int32 repeats) {
this._algorithm = algorithm;
this._repeats = repeats;
} // Sash
public Sash(Int32 repeats)
: this(_defaultAlgorithm, repeats) {
} // Sash
public Sash(HashAlgorithm algorithm)
: this(algorithm, _defaultRepeats) {
} // Sash
public Sash()
: this(_defaultAlgorithm, _defaultRepeats) {
} // Sash
public Byte[] GenerateSalt(Int32 size) {
Byte[] salt = new Byte[size];
_rng.GetBytes(salt);
return salt;
} // GenerateSalt
public Byte[] CalculateHash(Byte[] data, Byte[] salt) {
Byte[] hash;
hash = _algorithm.ComputeHash(Concat(data, salt));
for (Int32 i = 0; i < _repeats; ++i) {
hash = _algorithm.ComputeHash(Concat(hash, salt));
}
for (Int32 j = 0; j < data.Length; ++j) {
data[j] = 0;
}
return hash;
} // CalculateHash
public Boolean CheckHash(Byte[] data, Byte[] salt, Byte[] expected) {
Byte[] actual = CalculateHash(data, salt);
for (Int32 i = 0; i < actual.Length; ++i) {
if (actual
!= expected) { return false; }
}
return true;
} // CheckHash
public void Dispose() {
this.Dispose(true);
GC.SuppressFinalize(this);
} // Dispose
public void Dispose(Boolean disposing) {
if (_disposed) return;
if (disposing) {
if (_algorithm != null) _algorithm.Clear();
}
_disposed = true;
} // Dispose
private Byte[] Concat(Byte[] lhs, Byte[] rhs) {
Byte[] result = new Byte[lhs.Length + rhs.Length];
Array.Copy(lhs, result, lhs.Length);
Array.Copy(rhs, 0, result, lhs.Length, rhs.Length);
return result;
} // Concat
} // Sash
Finally, I have a few extensions:
public static class CryptographyHelpers {
public static Byte[] Sash(Byte[] value, HashAlgorithm algorithm, Int32 repeats, out Byte[] salt) {
Sash sash = new Sash(algorithm, repeats);
salt = sash.GenerateSalt(repeats);
Byte[] hash = sash.CalculateHash(value, salt);
sash.Dispose();
return hash;
} // Sash
public static Byte[] Sash(String value, HashAlgorithm algorithm, Int32 repeats, out Byte[] salt) {
return Sash(Encoding.UTF8.GetBytes(value), algorithm, repeats, out salt);
} // Sash
} // CryptographyHelpers
So this is my code. Any suggestion in improve is welcome.
About the expiration ... If I want to set it in this case is simple:
On verification I check the elapsed time since user was created.
But other times this is not so simple ... So I was just wondering.
Finally, I am trying to create a class that makes simple to:
1 - Issue a token from given data;
2 - Verify if a token is valid.
I am not sure if I should use encryption or hashing.
I think Hashing would be safer ... But how is usually done?
I am working on the Token Class but I am not sure the best way to do it ...