You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
5.3 KiB
138 lines
5.3 KiB
using Isopoh.Cryptography.Argon2;
|
|
using Isopoh.Cryptography.SecureArray;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using Chaos.NaCl;
|
|
|
|
|
|
namespace Hasher
|
|
{
|
|
/// <summary>
|
|
/// A utility class for generating and verifying Argon2 hashes.
|
|
/// </summary>
|
|
public static class Argon2dHasher
|
|
{
|
|
private static readonly RandomNumberGenerator Rng = RandomNumberGenerator.Create();
|
|
|
|
/// <summary>
|
|
/// Generates an Argon2 hash for the given password and salt.
|
|
/// </summary>
|
|
/// <param name="password">The password to hash.</param>
|
|
/// <param name="salt">A random salt to use for the hash. If null, a new 16-byte salt will be generated.</param>
|
|
/// <returns>The generated Argon2 hash as a string.</returns>
|
|
public static string GenerateArgon2Hash(string password, byte[]? salt)
|
|
{
|
|
if (salt == null)
|
|
{
|
|
salt = new byte[16];
|
|
}
|
|
byte[] pwBytes = Encoding.UTF8.GetBytes(password);
|
|
|
|
// Generate a random salt
|
|
Rng.GetBytes(salt);
|
|
|
|
var config = new Argon2Config
|
|
{
|
|
Type = Argon2Type.DataIndependentAddressing,
|
|
Version = Argon2Version.Nineteen,
|
|
TimeCost = 6,
|
|
Lanes = 3,
|
|
Threads = Environment.ProcessorCount - 1, // higher than "Lanes" doesn't help (or hurt)
|
|
Password = pwBytes,
|
|
Salt = salt,
|
|
};
|
|
|
|
var argon2 = new Argon2(config);
|
|
|
|
string hashString;
|
|
using(SecureArray<byte> hashA = argon2.Hash())
|
|
{
|
|
hashString = config.EncodeString(hashA.Buffer);
|
|
}
|
|
return hashString;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that a given password matches an Argon2 hash.
|
|
/// </summary>
|
|
/// <param name="password">The password to check.</param>
|
|
/// <param name="hash">The Argon2 hash to check against.</param>
|
|
/// <returns>True if the password matches the hash, false otherwise.</returns>
|
|
public static bool VerifyArgon2Hash(string password, string hash)
|
|
{
|
|
byte[] pwBytes = Encoding.UTF8.GetBytes(password);
|
|
var valid = Argon2.Verify(hash, pwBytes);
|
|
return valid;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The FingerPrinter class provides methods to generate and hash fingerprints.
|
|
/// </summary>
|
|
public class FingerPrinter
|
|
{
|
|
/// <summary>
|
|
/// Helper function to generate a random string of a given length.
|
|
/// </summary>
|
|
/// <param name="length">The length of the string to generate.</param>
|
|
/// <returns>A random string of the specified length.</returns>
|
|
private static string GetRandomString(int length)
|
|
{
|
|
var r = new Random();
|
|
return new String(Enumerable.Range(0, length).Select(n => (Char)(r.Next(32, 127))).ToArray());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper function to hash a fingerprint using SHA-256.
|
|
/// </summary>
|
|
/// <param name="fingerprint">The fingerprint to hash.</param>
|
|
/// <returns>The SHA-256 hash of the input fingerprint as a base64-encoded string.</returns>
|
|
private static string HashFingerprint(string fingerprint)
|
|
{
|
|
using var sha256 = SHA256.Create();
|
|
var hashedFingerprint = sha256.ComputeHash(Encoding.UTF8.GetBytes(fingerprint));
|
|
return Convert.ToBase64String(hashedFingerprint);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an array containing a randomly generated plain text fingerprint and its hashed value.
|
|
/// </summary>
|
|
/// <param name="length">The length of the plain text fingerprint to generate (default is 32).</param>
|
|
/// <returns>An array of two strings: the plain text fingerprint and its hashed value.</returns>
|
|
public static string[] GetFingerprintSet(int length = 32)
|
|
{
|
|
string plainText = GetRandomString(length);
|
|
string hashed = HashFingerprint(plainText);
|
|
|
|
return new string[] { plainText, hashed };
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates whether the specified fingerprint matches the provided hashed fingerprint using SHA256 encryption.
|
|
/// </summary>
|
|
/// <param name="fingerprint">The fingerprint string to be validated.</param>
|
|
/// <param name="fpHash">The hashed fingerprint to be compared against the fingerprint.</param>
|
|
/// <returns>Returns a boolean value indicating whether the fingerprint and its hash match or not.</returns>
|
|
public static bool ValidateFingerpint(string fingerprint, string fpHash)
|
|
{
|
|
using var sha256 = SHA256.Create();
|
|
var newFpHash = sha256.ComputeHash(Encoding.UTF8.GetBytes(fingerprint));
|
|
return Convert.ToBase64String(newFpHash) == fpHash ;
|
|
}
|
|
}
|
|
|
|
public class KeyHelper
|
|
{
|
|
private static byte[] FromBase64String(string input)
|
|
{
|
|
return Convert.FromBase64String(input);
|
|
}
|
|
|
|
public static bool validateSignature(string signature, string message, string publicKey)
|
|
{
|
|
return Ed25519.Verify(FromBase64String(signature), Encoding.UTF8.GetBytes(message), FromBase64String(publicKey));
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|