Compare commits
3 Commits
c427006283
...
e1123cf36b
Author | SHA1 | Date | |
---|---|---|---|
e1123cf36b | |||
930edd4c2c | |||
7e283fe643 |
76
Security/PasswordHashService.cs
Normal file
76
Security/PasswordHashService.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
using System.Buffers.Text;
|
||||||
|
using System.Text;
|
||||||
|
using Konscious.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Security;
|
||||||
|
|
||||||
|
public class PasswordHashService
|
||||||
|
{
|
||||||
|
public int SaltSize { private get; init; }
|
||||||
|
public int HashSize { private get; init; }
|
||||||
|
public int Iterations { private get; init; }
|
||||||
|
public int Memory { private get; init; }
|
||||||
|
public int Parallelism { private get; init; }
|
||||||
|
public string? Secret { private get; init; }
|
||||||
|
|
||||||
|
private ReadOnlySpan<byte> HashPassword(string password, ReadOnlySpan<byte> salt)
|
||||||
|
{
|
||||||
|
var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password))
|
||||||
|
{
|
||||||
|
Iterations = Iterations,
|
||||||
|
MemorySize = Memory,
|
||||||
|
DegreeOfParallelism = Parallelism,
|
||||||
|
Salt = salt.ToArray()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Secret))
|
||||||
|
argon2.KnownSecret = Convert.FromBase64String(Secret);
|
||||||
|
|
||||||
|
return argon2.GetBytes(HashSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ConstantTimeComparison(ReadOnlySpan<byte> a, ReadOnlySpan<byte> b)
|
||||||
|
{
|
||||||
|
if (a.Length != b.Length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
for (int i = 0; i < a.Length; i++)
|
||||||
|
result |= a[i] ^ b[i];
|
||||||
|
return result == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReadOnlySpan<byte> GenerateRandomKeyBytes(int size)
|
||||||
|
{
|
||||||
|
var key = new byte[size];
|
||||||
|
using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
|
||||||
|
rng.GetNonZeroBytes(key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GenerateRandomKeyStringBase64(int size) =>
|
||||||
|
Convert.ToBase64String(GenerateRandomKeyBytes(size));
|
||||||
|
|
||||||
|
public static string GenerateRandomKeyString(int size)
|
||||||
|
{
|
||||||
|
var randomBytes = GenerateRandomKeyBytes(size);
|
||||||
|
Span<byte> utf8Bytes = new byte[Base64.GetMaxEncodedToUtf8Length(randomBytes.Length)];
|
||||||
|
|
||||||
|
Base64.EncodeToUtf8(randomBytes, utf8Bytes, out _, out _);
|
||||||
|
return Encoding.UTF8.GetString(utf8Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public (string Salt, string Hash) HashPassword(string password)
|
||||||
|
{
|
||||||
|
var salt = GenerateRandomKeyBytes(SaltSize);
|
||||||
|
var hash = HashPassword(password, salt);
|
||||||
|
|
||||||
|
return (Convert.ToBase64String(salt), Convert.ToBase64String(hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool VerifyPassword(string password, ReadOnlySpan<byte> salt, ReadOnlySpan<byte> hash) =>
|
||||||
|
ConstantTimeComparison(HashPassword(password, salt), hash);
|
||||||
|
|
||||||
|
public bool VerifyPassword(string password, string saltBase64, string hashBase64) =>
|
||||||
|
VerifyPassword(password, Convert.FromBase64String(saltBase64), Convert.FromBase64String(hashBase64));
|
||||||
|
}
|
19
Security/Security.csproj
Normal file
19
Security/Security.csproj
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<Company>Winsomnia</Company>
|
||||||
|
<Version>1.0.0-a0</Version>
|
||||||
|
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||||
|
<FileVersion>1.0.0.0</FileVersion>
|
||||||
|
<AssemblyName>Mirea.Api.Security</AssemblyName>
|
||||||
|
<RootNamespace>$(AssemblyName)</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
Loading…
Reference in New Issue
Block a user