-
-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
github-actions
committed
Nov 5, 2023
1 parent
521d864
commit ae23dc0
Showing
15 changed files
with
548 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
...Identity.Argon2PasswordHasher/Aguacongas.TheIdServer.Identity.Argon2PasswordHasher.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<Authors>Olivier Lefebvre</Authors> | ||
<Description>Argon2 Password Hasher for ASP.NET Core Identity.</Description> | ||
<Copyright>Copyright (c) 2023 @Olivier Lefebvre</Copyright> | ||
<PackageProjectUrl>https://github.com/Aguafrommars/TheIdServer/tree/master/src/Aguacongas.TheIdServer.Identity.Argon2PasswordHasher</PackageProjectUrl> | ||
<RepositoryUrl>https://github.com/aguacongas/TheIdServer</RepositoryUrl> | ||
<RepositoryType>git</RepositoryType> | ||
<PackageTags>aspnetcore;identity;Argon2;password;hashing;hash;security</PackageTags> | ||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression> | ||
<GenerateDocumentationFile>true</GenerateDocumentationFile> | ||
<PackageIcon>package-icon.png</PackageIcon> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Geralt" Version="3.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.0-rc.2.23479.6" /> | ||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.0-rc.2.23480.2" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="package-icon.png" Pack="true" PackagePath="" /> | ||
</ItemGroup> | ||
|
||
</Project> |
31 changes: 31 additions & 0 deletions
31
src/Identity/Aguacongas.TheIdServer.Identity.Argon2PasswordHasher/Argon2Id.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using Geralt; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Aguacongas.TheIdServer.Identity.Argon2PasswordHasher; | ||
internal class Argon2Id : IArgon2Id | ||
{ | ||
private readonly IOptions<Argon2PasswordHasherOptions> _options; | ||
|
||
public Argon2Id(IOptions<Argon2PasswordHasherOptions> options) | ||
{ | ||
ArgumentNullException.ThrowIfNull(options); | ||
_options = options; | ||
} | ||
public Span<byte> ComputeHash(ReadOnlySpan<byte> password) | ||
{ | ||
var settings = _options.Value; | ||
var hash = new Span<byte>(new byte[Argon2id.MaxHashSize]); | ||
Argon2id.ComputeHash(hash, password, settings.Interations, settings.Memory); | ||
return hash; | ||
} | ||
|
||
public bool NeedsRehash(ReadOnlySpan<byte> hash) | ||
{ | ||
var settings = _options.Value; | ||
return Argon2id.NeedsRehash(hash, settings.Interations, settings.Memory); | ||
} | ||
|
||
public bool VerifyHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> password) | ||
=> Argon2id.VerifyHash(hash, password); | ||
|
||
} |
87 changes: 87 additions & 0 deletions
87
src/Identity/Aguacongas.TheIdServer.Identity.Argon2PasswordHasher/Argon2PasswordHasher.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using Microsoft.AspNetCore.Identity; | ||
using Microsoft.Extensions.Options; | ||
using System.Buffers; | ||
using System.Text; | ||
|
||
namespace Aguacongas.TheIdServer.Identity.Argon2PasswordHasher; | ||
|
||
/// <summary> | ||
/// Argon2 passwor hasher | ||
/// </summary> | ||
/// <typeparam name="TUser"></typeparam> | ||
public class Argon2PasswordHasher<TUser> : IPasswordHasher<TUser> where TUser : class | ||
{ | ||
private readonly IArgon2Id _argon2Id; | ||
private readonly IOptions<Argon2PasswordHasherOptions> _options; | ||
|
||
/// <summary> | ||
/// Initialize a new instance of <see cref="Argon2PasswordHasher{TUser}"/> | ||
/// </summary> | ||
/// <param name="argon2Id"><see cref="IArgon2Id"/> implementation</param> | ||
/// <param name="options">password hasher options</param> | ||
public Argon2PasswordHasher(IArgon2Id argon2Id, IOptions<Argon2PasswordHasherOptions> options) | ||
{ | ||
ArgumentNullException.ThrowIfNull(argon2Id); | ||
ArgumentNullException.ThrowIfNull(options); | ||
_argon2Id = argon2Id; | ||
_options = options; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public string HashPassword(TUser user, string password) | ||
{ | ||
ArgumentException.ThrowIfNullOrWhiteSpace(password); | ||
|
||
var passwordSpan = new ReadOnlySpan<byte>(Encoding.UTF8.GetBytes(password)); | ||
var hash = _argon2Id.ComputeHash(passwordSpan); | ||
return Convert.ToBase64String(new byte[] | ||
{ | ||
_options.Value.HashPrefix | ||
} | ||
.Concat(hash.ToArray()) | ||
.ToArray()); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public PasswordVerificationResult VerifyHashedPassword(TUser user, string hashedPassword, string providedPassword) | ||
{ | ||
ArgumentException.ThrowIfNullOrWhiteSpace(hashedPassword); | ||
ArgumentException.ThrowIfNullOrWhiteSpace(providedPassword); | ||
|
||
byte[] decodedHashedPassword; | ||
try | ||
{ | ||
decodedHashedPassword = Convert.FromBase64String(hashedPassword); | ||
} | ||
catch (FormatException) | ||
{ | ||
return PasswordVerificationResult.Failed; | ||
} | ||
|
||
var hashSpan = decodedHashedPassword.AsSpan()[1..]; | ||
|
||
try | ||
{ | ||
if (!_argon2Id.VerifyHash(hashSpan, | ||
new ReadOnlySpan<byte>(Encoding.UTF8.GetBytes(providedPassword)))) | ||
{ | ||
return PasswordVerificationResult.Failed; | ||
} | ||
} | ||
catch (ArgumentOutOfRangeException) | ||
{ | ||
return PasswordVerificationResult.Failed; | ||
} | ||
catch(FormatException) | ||
{ | ||
return PasswordVerificationResult.Failed; | ||
} | ||
|
||
if (_argon2Id.NeedsRehash(hashSpan)) | ||
{ | ||
return PasswordVerificationResult.SuccessRehashNeeded; | ||
} | ||
|
||
return PasswordVerificationResult.Success; | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
...ntity/Aguacongas.TheIdServer.Identity.Argon2PasswordHasher/Argon2PasswordHasherOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using Geralt; | ||
using System.ComponentModel.DataAnnotations; | ||
|
||
namespace Aguacongas.TheIdServer.Identity.Argon2PasswordHasher; | ||
|
||
/// <summary> | ||
/// Argon2 password hasher options | ||
/// </summary> | ||
public class Argon2PasswordHasherOptions | ||
{ | ||
/// <summary> | ||
/// Number of iteration to use. 2 by default. | ||
/// </summary> | ||
[Range(Argon2id.MinIterations, int.MaxValue)] | ||
public int Interations { get; set; } = 2; | ||
|
||
/// <summary> | ||
/// Memory to use. 67108864 by default. | ||
/// </summary> | ||
[Range(Argon2id.MinMemorySize, int.MaxValue)] | ||
public int Memory { get; set; } = 67108864; | ||
|
||
/// <summary> | ||
/// Hash prefix to inform it was generated by this hasher. 0xA0 by default. | ||
/// </summary> | ||
public byte HashPrefix { get; set; } = 0xA0; | ||
} |
3 changes: 3 additions & 0 deletions
3
src/Identity/Aguacongas.TheIdServer.Identity.Argon2PasswordHasher/AssemblyInfo.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
using System.Runtime.CompilerServices; | ||
|
||
[assembly: InternalsVisibleTo("Aguacongas.TheIdServer.Identity.Argon2PasswordHasher.Test")] |
41 changes: 41 additions & 0 deletions
41
...ongas.TheIdServer.Identity.Argon2PasswordHasher/Extensions/ServiceCollectionExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using Aguacongas.TheIdServer.Identity.Argon2PasswordHasher; | ||
using Geralt; | ||
using Microsoft.AspNetCore.Identity; | ||
using Microsoft.Extensions.Configuration; | ||
|
||
namespace Microsoft.Extensions.DependencyInjection; | ||
|
||
/// <summary> | ||
/// <see cref="IServiceCollection"/> extensions | ||
/// </summary> | ||
public static class ServiceCollectionExtensions | ||
{ | ||
/// <summary> | ||
/// Add argon2 password hasher services in DI | ||
/// </summary> | ||
/// <typeparam name="TUser"></typeparam> | ||
/// <param name="services"></param> | ||
/// <param name="configure"></param> | ||
/// <returns></returns> | ||
public static IServiceCollection AddArgon2PasswordHasher<TUser>(this IServiceCollection services, Action<Argon2PasswordHasherOptions>? configure = null) where TUser : class | ||
{ | ||
services.AddOptions<Argon2PasswordHasherOptions>() | ||
.Configure(options => configure?.Invoke(options)) | ||
.Validate(options => options.Memory > Argon2id.MinMemorySize && options.Interations > Argon2id.MinIterations); | ||
|
||
return services.AddTransient<IArgon2Id, Argon2Id>() | ||
.AddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>(); | ||
} | ||
|
||
/// <summary> | ||
/// Add argon2 password hasher services in DI | ||
/// </summary> | ||
/// <typeparam name="TUser"></typeparam> | ||
/// <param name="services"></param> | ||
/// <param name="configuration"></param> | ||
/// <returns></returns> | ||
public static IServiceCollection AddArgon2PasswordHasher<TUser>(this IServiceCollection services, IConfiguration configuration) where TUser : class | ||
=> services.AddArgon2PasswordHasher<TUser>(configuration.Bind); | ||
|
||
|
||
} |
28 changes: 28 additions & 0 deletions
28
src/Identity/Aguacongas.TheIdServer.Identity.Argon2PasswordHasher/IArgon2Id.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
namespace Aguacongas.TheIdServer.Identity.Argon2PasswordHasher; | ||
|
||
/// <summary> | ||
/// Implement Argon2 | ||
/// </summary> | ||
public interface IArgon2Id | ||
{ | ||
/// <summary> | ||
/// Compute the hash | ||
/// </summary> | ||
/// <param name="password"></param> | ||
Span<byte> ComputeHash(ReadOnlySpan<byte> password); | ||
|
||
/// <summary> | ||
/// Verify the hash | ||
/// </summary> | ||
/// <param name="hash"></param> | ||
/// <param name="password"></param> | ||
/// <returns></returns> | ||
bool VerifyHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> password); | ||
|
||
/// <summary> | ||
/// Verify if the hash needs to be rehashed | ||
/// </summary> | ||
/// <param name="hash"></param> | ||
/// <returns></returns> | ||
bool NeedsRehash(ReadOnlySpan<byte> hash); | ||
} |
34 changes: 34 additions & 0 deletions
34
src/Identity/Aguacongas.TheIdServer.Identity.Argon2PasswordHasher/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Argon2 Password Hasher for ASP.NET Core Identity | ||
|
||
An implementation of IPasswordHasher<TUser> using [Geralt](https://www.geralt.xyz/). | ||
|
||
## Installation | ||
|
||
```csharp | ||
services.AddIdentity<TUser, TRole>(); | ||
services.AddArgon2PasswordHasher<TUser>(); | ||
``` | ||
|
||
### Options | ||
|
||
Default values: | ||
|
||
``` json | ||
"Argon2PasswordHasherOptions": { | ||
"Interations": 2, | ||
"Memory": 67108864, | ||
"HashPrefix": 0xA0 | ||
} | ||
``` | ||
|
||
- **Interations** can not be less than 1 | ||
- **Memory** can not be less than 8192 | ||
|
||
Read [Geralt Password hashing Notes](https://www.geralt.xyz/password-hashing#notes) for more information to configure the hasher. | ||
|
||
`AddArgon2PasswordHasher` can take an action to configure an `Argon2PasswordHasherOptions` instance: | ||
|
||
```cs | ||
services.AddArgon2PasswordHasher<TUser>(options => configuration.Bind(options)); | ||
``` | ||
|
Binary file added
BIN
+12.1 KB
src/Identity/Aguacongas.TheIdServer.Identity.Argon2PasswordHasher/package-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.