using Isopoh.Cryptography.Argon2; using Isopoh.Cryptography.SecureArray; using System.Security.Cryptography; using System.Text; using Chaos.NaCl; namespace Hasher { /// /// A utility class for generating and verifying Argon2 hashes. /// public static class Argon2dHasher { private static readonly RandomNumberGenerator Rng = RandomNumberGenerator.Create(); /// /// Generates an Argon2 hash for the given password and salt. /// /// The password to hash. /// A random salt to use for the hash. If null, a new 16-byte salt will be generated. /// The generated Argon2 hash as a string. 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 hashA = argon2.Hash()) { hashString = config.EncodeString(hashA.Buffer); } return hashString; } /// /// Verifies that a given password matches an Argon2 hash. /// /// The password to check. /// The Argon2 hash to check against. /// True if the password matches the hash, false otherwise. public static bool VerifyArgon2Hash(string password, string hash) { byte[] pwBytes = Encoding.UTF8.GetBytes(password); var valid = Argon2.Verify(hash, pwBytes); return valid; } } /// /// The FingerPrinter class provides methods to generate and hash fingerprints. /// public class FingerPrinter { /// /// Helper function to generate a random string of a given length. /// /// The length of the string to generate. /// A random string of the specified length. 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()); } /// /// Helper function to hash a fingerprint using SHA-256. /// /// The fingerprint to hash. /// The SHA-256 hash of the input fingerprint as a base64-encoded string. private static string HashFingerprint(string fingerprint) { using var sha256 = SHA256.Create(); var hashedFingerprint = sha256.ComputeHash(Encoding.UTF8.GetBytes(fingerprint)); return Convert.ToBase64String(hashedFingerprint); } /// /// Returns an array containing a randomly generated plain text fingerprint and its hashed value. /// /// The length of the plain text fingerprint to generate (default is 32). /// An array of two strings: the plain text fingerprint and its hashed value. public static string[] GetFingerprintSet(int length = 32) { string plainText = GetRandomString(length); string hashed = HashFingerprint(plainText); return new string[] { plainText, hashed }; } /// /// Validates whether the specified fingerprint matches the provided hashed fingerprint using SHA256 encryption. /// /// The fingerprint string to be validated. /// The hashed fingerprint to be compared against the fingerprint. /// Returns a boolean value indicating whether the fingerprint and its hash match or not. 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)); } } }