Files
atakanozbancom/Models/classes/PasswordHasher.cs
T
Atakan Doğan ÖzbanandCursor fc45c35dbe Add support page, admin features, and auth hardening.
Rename public affiliate route to /support with localized nav labels, and include affiliate/social/wallpaper admin, 2FA login, and related site updates.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-29 20:25:55 +02:00

105 lines
3.1 KiB
C#

using System;
using System.Security.Cryptography;
using System.Text;
namespace atakanozbancom.Models.classes
{
public static class PasswordHasher
{
private const string Prefix = "pbkdf2";
private const int DefaultIterations = 100000;
private const int SaltSize = 16;
private const int HashSize = 32;
public static string Hash(string password)
{
if (password == null)
throw new ArgumentNullException("password");
var salt = new byte[SaltSize];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
var hash = Pbkdf2(password, salt, DefaultIterations, HashSize);
return string.Format(
"{0}${1}${2}${3}",
Prefix,
DefaultIterations,
Convert.ToBase64String(salt),
Convert.ToBase64String(hash));
}
public static bool IsHashed(string stored)
{
return !string.IsNullOrWhiteSpace(stored)
&& stored.StartsWith(Prefix + "$", StringComparison.Ordinal);
}
public static bool Verify(string password, string stored)
{
if (string.IsNullOrEmpty(password) || string.IsNullOrEmpty(stored))
return false;
if (!IsHashed(stored))
return FixedTimeEquals(password, stored);
var parts = stored.Split('$');
if (parts.Length != 4 || !string.Equals(parts[0], Prefix, StringComparison.Ordinal))
return false;
int iterations;
if (!int.TryParse(parts[1], out iterations) || iterations < 1000)
return false;
byte[] salt;
byte[] expected;
try
{
salt = Convert.FromBase64String(parts[2]);
expected = Convert.FromBase64String(parts[3]);
}
catch
{
return false;
}
var actual = Pbkdf2(password, salt, iterations, expected.Length);
return FixedTimeEquals(actual, expected);
}
private static byte[] Pbkdf2(string password, byte[] salt, int iterations, int length)
{
using (var derive = new Rfc2898DeriveBytes(password, salt, iterations, HashAlgorithmName.SHA256))
{
return derive.GetBytes(length);
}
}
private static bool FixedTimeEquals(byte[] a, byte[] b)
{
if (a == null || b == null || a.Length != b.Length)
return false;
var diff = 0;
for (var i = 0; i < a.Length; i++)
diff |= a[i] ^ b[i];
return diff == 0;
}
private static bool FixedTimeEquals(string a, string b)
{
if (a == null || b == null || a.Length != b.Length)
return false;
var diff = 0;
for (var i = 0; i < a.Length; i++)
diff |= a[i] ^ b[i];
return diff == 0;
}
}
}