Moves Argon2 to real nuget (#163)
This commit is contained in:
parent
1246a135f7
commit
561b40c3d8
21 changed files with 43 additions and 718 deletions
19
.github/workflows/dotnet-core.yml
vendored
19
.github/workflows/dotnet-core.yml
vendored
|
|
@ -32,7 +32,6 @@ jobs:
|
|||
with:
|
||||
path: |
|
||||
~/.nuget/packages
|
||||
!~/.nuget/packages/argon2.bindings
|
||||
!~/.nuget/packages/zlib.bindings
|
||||
${{ github.workspace }}/Projects/*/obj/project.assets.json
|
||||
${{ github.workspace }}/Projects/*/obj/project.nuget.cache
|
||||
|
|
@ -40,17 +39,6 @@ jobs:
|
|||
key: ${{ matrix.os }}-nuget-cache-v6-${{ hashFiles('**/packages.lock.json') }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-nuget-cache-v3
|
||||
- name: Argon2 Library Cache
|
||||
id: argon2-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.nuget/packages/argon2.bindings
|
||||
${{ github.workspace }}/Projects/Argon2/**
|
||||
${{ github.workspace }}/packages/Argon2.Bindings*.nupkg
|
||||
key: ${{ matrix.os }}-argon2-cache-v6-${{ hashFiles('Projects/Argon2/*') }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-argon2-cache-v4
|
||||
- name: ZLib Library Cache
|
||||
id: zlib-cache
|
||||
uses: actions/cache@v2
|
||||
|
|
@ -67,13 +55,8 @@ jobs:
|
|||
- name: Pack ZLib NuGet
|
||||
if: steps.zlib-cache.outputs.cache-hit != 'true'
|
||||
run: dotnet pack -c Release -o packages Projects/ZLib/ZLib.csproj
|
||||
- name: Build Argon2
|
||||
run: dotnet build -c Release Projects/Argon2/Argon2.csproj
|
||||
- name: Pack Argon2 NuGet
|
||||
if: steps.argon2-cache.outputs.cache-hit != 'true'
|
||||
run: dotnet pack -c Release -o packages Projects/Argon2/Argon2.csproj
|
||||
- name: Restore dependencies
|
||||
if: steps.nuget-cache.outputs.cache-hit != 'true' || steps.argon2-cache.outputs.cache-hit != 'true' || steps.zlib-cache.outputs.cache-hit != 'true'
|
||||
if: steps.nuget-cache.outputs.cache-hit != 'true' || steps.zlib-cache.outputs.cache-hit != 'true'
|
||||
run: dotnet restore --force-evaluate
|
||||
- name: Build Server
|
||||
run: dotnet build -c Release --no-restore Projects/Server/Server.csproj
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29102.190
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Argon2", "Projects\Argon2\Argon2.csproj", "{97150E9D-5561-4D3C-9B78-E795544507D0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Projects\Server\Server.csproj", "{5E93BB35-3661-4822-9A8A-859726BAD87F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UOContent", "Projects\UOContent\UOContent.csproj", "{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}"
|
||||
|
|
@ -45,12 +43,6 @@ Global
|
|||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Debug|x64.Build.0 = Debug|x64
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Release|x64.ActiveCfg = Release|x64
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Release|x64.Build.0 = Release|x64
|
||||
{97150E9D-5561-4D3C-9B78-E795544507D0}.Analyze|x64.ActiveCfg = Analyze|x64
|
||||
{97150E9D-5561-4D3C-9B78-E795544507D0}.Analyze|x64.Build.0 = Analyze|x64
|
||||
{97150E9D-5561-4D3C-9B78-E795544507D0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{97150E9D-5561-4D3C-9B78-E795544507D0}.Debug|x64.Build.0 = Debug|x64
|
||||
{97150E9D-5561-4D3C-9B78-E795544507D0}.Release|x64.ActiveCfg = Release|x64
|
||||
{97150E9D-5561-4D3C-9B78-E795544507D0}.Release|x64.Build.0 = Release|x64
|
||||
{3B030CD2-DB29-4BC2-9C90-D90804B30757}.Analyze|x64.ActiveCfg = Analyze|x64
|
||||
{3B030CD2-DB29-4BC2-9C90-D90804B30757}.Analyze|x64.Build.0 = Analyze|x64
|
||||
{3B030CD2-DB29-4BC2-9C90-D90804B30757}.Debug|x64.ActiveCfg = Debug|x64
|
||||
|
|
|
|||
|
|
@ -1,111 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System.Security.Cryptography
|
||||
{
|
||||
internal interface IArgon2
|
||||
{
|
||||
public Argon2Error Hash(uint t_cost, uint m_cost, uint parallelism,
|
||||
ReadOnlySpan<byte> pwd,
|
||||
ReadOnlySpan<byte> salt,
|
||||
Span<byte> hash,
|
||||
Span<byte> encoded,
|
||||
int type, int version);
|
||||
|
||||
Argon2Error Verify(ReadOnlySpan<byte> encoded, ReadOnlySpan<byte> pwd, int pwdlen, int type);
|
||||
|
||||
// TODO: Change str to use ReadOnlySpan<char> then convert to pointer later
|
||||
Argon2Error Decode(Argon2Context ctx, ReadOnlySpan<byte> str, int type);
|
||||
}
|
||||
|
||||
internal static class Argon2
|
||||
{
|
||||
internal static readonly bool IsDarwin = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
internal static readonly bool IsFreeBSD = RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD);
|
||||
internal static readonly bool IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||
internal static readonly bool IsUnix = IsLinux || IsDarwin || IsFreeBSD;
|
||||
|
||||
internal static readonly IArgon2 Library = IsUnix ? (IArgon2)new UnixArgon2() : new WindowsArgon2();
|
||||
}
|
||||
|
||||
internal class WindowsArgon2 : IArgon2
|
||||
{
|
||||
public Argon2Error Hash(uint t_cost, uint m_cost, uint parallelism,
|
||||
ReadOnlySpan<byte> pwd,
|
||||
ReadOnlySpan<byte> salt,
|
||||
Span<byte> hash,
|
||||
Span<byte> encoded,
|
||||
int type, int version) =>
|
||||
SafeNativeMethods.argon2_hash(t_cost, m_cost, parallelism,
|
||||
in pwd.GetPinnableReference(), pwd.Length,
|
||||
in salt.GetPinnableReference(), salt.Length,
|
||||
ref hash.GetPinnableReference(), hash.Length,
|
||||
ref encoded.GetPinnableReference(), encoded.Length,
|
||||
type, version
|
||||
);
|
||||
|
||||
public Argon2Error Verify(ReadOnlySpan<byte> encoded, ReadOnlySpan<byte> pwd, int pwdlen, int type) =>
|
||||
SafeNativeMethods.argon2_verify(in encoded.GetPinnableReference(), in pwd.GetPinnableReference(), pwdlen, type);
|
||||
|
||||
public Argon2Error Decode(Argon2Context ctx, ReadOnlySpan<byte> str, int type) =>
|
||||
SafeNativeMethods.decode_string(ctx, in str.GetPinnableReference(), type);
|
||||
|
||||
internal static class SafeNativeMethods
|
||||
{
|
||||
[DllImport("libargon2.dll", EntryPoint = "argon2_hash", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern Argon2Error argon2_hash(uint t_cost, uint m_cost, uint parallelism,
|
||||
in byte pwd, int pwdlen,
|
||||
in byte salt, int saltlen,
|
||||
ref byte hash, int hashlen,
|
||||
ref byte encoded, int encodedlen,
|
||||
int type, int version
|
||||
);
|
||||
|
||||
[DllImport("libargon2.dll", EntryPoint = "argon2_verify", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern Argon2Error argon2_verify(in byte encoded, in byte pwd, int pwdlen, int type);
|
||||
|
||||
[DllImport("libargon2.dll", EntryPoint = "decode_string", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern Argon2Error decode_string(Argon2Context ctx, in byte str, int type);
|
||||
}
|
||||
}
|
||||
|
||||
internal class UnixArgon2 : IArgon2
|
||||
{
|
||||
public Argon2Error Hash(uint t_cost, uint m_cost, uint parallelism,
|
||||
ReadOnlySpan<byte> pwd,
|
||||
ReadOnlySpan<byte> salt,
|
||||
Span<byte> hash,
|
||||
Span<byte> encoded,
|
||||
int type, int version) =>
|
||||
SafeNativeMethods.argon2_hash(t_cost, m_cost, parallelism,
|
||||
in pwd.GetPinnableReference(), pwd.Length,
|
||||
in salt.GetPinnableReference(), salt.Length,
|
||||
ref hash.GetPinnableReference(), hash.Length,
|
||||
ref encoded.GetPinnableReference(), encoded.Length,
|
||||
type, version
|
||||
);
|
||||
|
||||
public Argon2Error Verify(ReadOnlySpan<byte> encoded, ReadOnlySpan<byte> pwd, int pwdlen, int type) =>
|
||||
SafeNativeMethods.argon2_verify(in encoded.GetPinnableReference(), in pwd.GetPinnableReference(), pwdlen, type);
|
||||
|
||||
public Argon2Error Decode(Argon2Context ctx, ReadOnlySpan<byte> str, int type) =>
|
||||
SafeNativeMethods.decode_string(ctx, in str.GetPinnableReference(), type);
|
||||
|
||||
internal static class SafeNativeMethods
|
||||
{
|
||||
[DllImport("argon2", EntryPoint = "argon2_hash")]
|
||||
internal static extern Argon2Error argon2_hash(uint t_cost, uint m_cost, uint parallelism,
|
||||
in byte pwd, int pwdlen,
|
||||
in byte salt, int saltlen,
|
||||
ref byte hash, int hashlen,
|
||||
ref byte encoded, int encodedlen,
|
||||
int type, int version
|
||||
);
|
||||
|
||||
[DllImport("argon2", EntryPoint = "argon2_verify")]
|
||||
internal static extern Argon2Error argon2_verify(in byte encoded, in byte pwd, int pwdlen, int type);
|
||||
|
||||
[DllImport("argon2", EntryPoint = "decode_string")]
|
||||
internal static extern Argon2Error decode_string(Argon2Context ctx, in byte str, int type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<PackageVersion>1.2.7</PackageVersion>
|
||||
<RootNamespace>System.Security.Cryptography</RootNamespace>
|
||||
<AssemblyName>Argon2.Bindings</AssemblyName>
|
||||
<IsPackable>true</IsPackable>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
<Configurations>Debug;Release;Analyze</Configurations>
|
||||
<AssemblyVersion>1.2.7</AssemblyVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="runtimes\win-x64\native\libargon2.dll">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>runtimes/win-x64/native</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="runtimes\osx-x64\native\libargon2.dylib">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>runtimes/osx-x64/native</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="runtimes\linux-x64\native\libargon2.so">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>runtimes/linux-x64/native</PackagePath>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<package>
|
||||
<metadata>
|
||||
<id>Argon2.Bindings</id>
|
||||
<version>1.1.8</version>
|
||||
<authors>Kamron Batman</authors>
|
||||
<owners>Kamron Batman</owners>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/modernUO/ModernUO</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Argon2 C# Bindings for ModernUO</description>
|
||||
<releaseNotes>Updated to use spans/pointers</releaseNotes>
|
||||
<copyright>Copyright 2020</copyright>
|
||||
</metadata>
|
||||
</package>
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System.Security.Cryptography
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal class Argon2Context
|
||||
{
|
||||
public IntPtr Out;
|
||||
public uint OutLen;
|
||||
|
||||
public IntPtr Pwd;
|
||||
public uint PwdLen;
|
||||
|
||||
public IntPtr Salt;
|
||||
public uint SaltLen;
|
||||
|
||||
public IntPtr Secret;
|
||||
public uint SecretLen;
|
||||
|
||||
public IntPtr AssocData;
|
||||
public uint AssocDataLen;
|
||||
|
||||
public uint TimeCost;
|
||||
public uint MemoryCost;
|
||||
public uint Lanes;
|
||||
public uint Threads;
|
||||
|
||||
public IntPtr AllocateCallback;
|
||||
public IntPtr FreeCallback;
|
||||
|
||||
public uint Flags;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
namespace System.Security.Cryptography
|
||||
{
|
||||
/// <summary>
|
||||
/// An enumeration of the possible error codes which are returned from Daniel Dinu and
|
||||
/// Dmitry Khovratovich's Argon2 library.
|
||||
///
|
||||
/// Some of these error conditions cannot be reached while using the C# PasswordHasher wrapper
|
||||
/// </summary>
|
||||
public enum Argon2Error
|
||||
{
|
||||
/// <summary>
|
||||
/// The operation was successful
|
||||
/// </summary>
|
||||
OK = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The output hash length is less than 4 bytes
|
||||
/// </summary>
|
||||
OUTPUT_TOO_SHORT = -2,
|
||||
|
||||
/// <summary>
|
||||
/// The salt is less than 8 bytes
|
||||
/// </summary>
|
||||
SALT_TOO_SHORT = -6,
|
||||
|
||||
/// <summary>
|
||||
/// The salt is too big
|
||||
/// </summary>
|
||||
SALT_TOO_LONG = -7,
|
||||
|
||||
/// <summary>
|
||||
/// The time cost is less than 1
|
||||
/// </summary>
|
||||
TIME_TOO_SMALL = -12,
|
||||
|
||||
/// <summary>
|
||||
/// The memory cost is less than 8 (KiB)
|
||||
/// </summary>
|
||||
MEMORY_TOO_LITTLE = -14,
|
||||
/// <summary>
|
||||
/// The memory cost is greater than 2^21 (KiB) (2 GiB)
|
||||
/// </summary>
|
||||
MEMORY_TOO_MUCH = -15,
|
||||
|
||||
/// <summary>
|
||||
/// The parallelism is less than 1
|
||||
/// </summary>
|
||||
LANES_TOO_FEW = -16,
|
||||
/// <summary>
|
||||
/// The parallelism is greater than 16,777,215
|
||||
/// </summary>
|
||||
LANES_TOO_MANY = -17,
|
||||
|
||||
/// <summary>
|
||||
/// Memory allocation failed
|
||||
/// </summary>
|
||||
MEMORY_ALLOCATION_ERROR = -22,
|
||||
|
||||
/// <summary>
|
||||
/// The parallelism is less than 1
|
||||
/// </summary>
|
||||
THREADS_TOO_FEW = -28,
|
||||
/// <summary>
|
||||
/// The parallelism is greater than 16,777,215
|
||||
/// </summary>
|
||||
THREADS_TOO_MANY = -29,
|
||||
|
||||
/// <summary>
|
||||
/// This will not be returned from the C# PasswordHasher wrapper
|
||||
/// </summary>
|
||||
DECODING_FAIL = -32,
|
||||
|
||||
/// <summary>
|
||||
/// Unable to create the number of threads requested
|
||||
/// </summary>
|
||||
THREAD_FAIL = -33,
|
||||
|
||||
/// <summary>
|
||||
/// This will not be returned from the C# PasswordHasher wrapper
|
||||
/// </summary>
|
||||
VERIFY_MISMATCH = -35
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
namespace System.Security.Cryptography
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception class to wrap the errors returned by Daniel Dinu and Dmitry Khovratovich's Argon2 library.
|
||||
///
|
||||
/// Except through very unusual conditions, the only exceptions which could be thrown from PasswordHasher
|
||||
/// are Argon2Exception, ArgumentNullException, DllNotFoundException (if libargon2.dll is not found)
|
||||
/// </summary>
|
||||
public class Argon2Exception : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Construct an Argon2Exception with the specified Argon2 error code
|
||||
/// <param name="action">Which method the Argon2Exception originated from</param>
|
||||
/// <param name="error">The error returned from the Argon2 library</param>
|
||||
/// </summary>
|
||||
public Argon2Exception(string action, Argon2Error error) : base($"Error during Argon2 {action}: ({(int)error}) {error}") {}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,279 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Security.Cryptography
|
||||
{
|
||||
/// <summary>
|
||||
/// PasswordHasher is a class for creating Argon2 hashes and verifying them. This is a wrapper around
|
||||
/// Daniel Dinu and Dmitry Khovratovich's Argon2 library.
|
||||
/// </summary>
|
||||
public class Argon2PasswordHasher
|
||||
{
|
||||
private static RandomNumberGenerator m_Rng;
|
||||
|
||||
/// <summary>
|
||||
/// How many iterations of the Argon2 hash to perform
|
||||
/// </summary>
|
||||
public uint TimeCost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How much memory to use while hashing in kibibytes (KiB)
|
||||
/// </summary>
|
||||
public uint MemoryCost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How many threads to use while hashing
|
||||
/// </summary>
|
||||
public uint Parallelism { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of Argon2 hashing algorithm to use
|
||||
/// Argon2d - The memory access is dependent upon the hash value (vulnerable to side-channel attacks)
|
||||
/// Argon2i - The memory access is independent upon the hash value (safe from side-channel atacks)
|
||||
/// </summary>
|
||||
public Argon2Type ArgonType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of the generated raw hash in bytes
|
||||
/// </summary>
|
||||
public uint HashLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How strings should be decoded when passed to the Hash method.
|
||||
/// The default is Encoding.UTF8.
|
||||
/// </summary>
|
||||
public Encoding StringEncoding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Randomizer used to generate salts
|
||||
/// </summary>
|
||||
public RandomNumberGenerator Rng { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the Argon2 PasswordHasher with default performance and algorithm settings based upon the environment the hashing will be used in.
|
||||
/// You should perform your own profiling to determine what the parameters should be for your specific usage; however, this attempts to provide
|
||||
/// some reasonable defaults.
|
||||
/// </summary>
|
||||
public Argon2PasswordHasher(RandomNumberGenerator rng = null)
|
||||
{
|
||||
TimeCost = 3;
|
||||
MemoryCost = 8192;
|
||||
Parallelism = 1;
|
||||
ArgonType = Argon2Type.Argon2i;
|
||||
HashLength = 32;
|
||||
StringEncoding = Encoding.UTF8;
|
||||
Rng = rng ?? (m_Rng ??= new RNGCryptoServiceProvider());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hash the password using Argon2 with a cryptographically-secure, random, 16-byte salt.
|
||||
/// This is the only overload of the Hash method that the typical user will need to use for password storage. The other overloads are provided for interoperability purposes.
|
||||
/// Do not compare two Argon2 hashes directly. Instead, use the Verify or VerifyAndUpdate methods.
|
||||
/// <param name="password">A string representing the password to be hashed. The password is first decoded into bytes using StringEncoding (default: Encoding.UTF8)</param>
|
||||
/// <returns>A formatted string representing the hashed password, encoded with the parameters used to perform the hash</returns>
|
||||
/// </summary>
|
||||
public string Hash(ReadOnlySpan<char> password)
|
||||
{
|
||||
Span<byte> salt = stackalloc byte[16];
|
||||
Rng.GetBytes(salt);
|
||||
return Hash(password, salt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hash the raw password bytes using Argon2 with the specified salt bytes.
|
||||
/// Unless you need to specify your own salt for interoperability purposes, prefer the Hash(byte[] password) overload instead.
|
||||
/// Do not compare two Argon2 hashes directly. Instead, use the Verify or VerifyAndUpdate methods.
|
||||
/// <param name="password">The raw bytes of the password to be hashed</param>
|
||||
/// <param name="salt">The raw salt bytes to be used for the hash. The salt must be at least 8 bytes.</param>
|
||||
/// <returns>A formatted string representing the hashed password, encoded with the parameters used to perform the hash</returns>
|
||||
/// </summary>
|
||||
public string Hash(ReadOnlySpan<char> password, ReadOnlySpan<byte> salt)
|
||||
{
|
||||
Span<byte> hash = stackalloc byte[(int)HashLength];
|
||||
Span<byte> encoded = stackalloc byte[(int)(39 + ((HashLength + salt.Length) * 4 + 3) / 3)];
|
||||
Span<byte> passwordBytes = stackalloc byte[StringEncoding.GetByteCount(password)];
|
||||
StringEncoding.GetBytes(password, passwordBytes);
|
||||
|
||||
var result = Argon2.Library.Hash(
|
||||
TimeCost,
|
||||
MemoryCost,
|
||||
Parallelism,
|
||||
passwordBytes,
|
||||
salt,
|
||||
hash,
|
||||
encoded,
|
||||
(int)ArgonType,
|
||||
0x13
|
||||
);
|
||||
|
||||
if (result != Argon2Error.OK)
|
||||
throw new Argon2Exception("hashing", result);
|
||||
|
||||
var firstNonNull = encoded.Length - 2;
|
||||
while (encoded[firstNonNull] == 0)
|
||||
firstNonNull--;
|
||||
|
||||
return Encoding.ASCII.GetString(encoded.Slice(0, firstNonNull + 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hash the password using Argon2 with the specified salt. The HashRaw methods may be used for password-based key derivation.
|
||||
/// Unless you're using HashRaw for key deriviation or for interoperability purposes, the Hash methods should be used in favor of the HashRaw methods.
|
||||
/// <param name="password">The raw bytes of the password to be hashed</param>
|
||||
/// <param name="salt">The raw salt bytes to be used for the hash. The salt must be at least 8 bytes.</param>
|
||||
/// <returns>A byte array containing only the resulting hash</returns>
|
||||
/// </summary>
|
||||
public void HashRaw(ReadOnlySpan<char> password, ReadOnlySpan<byte> salt, Span<byte> hash)
|
||||
{
|
||||
Span<byte> passwordBytes = stackalloc byte[StringEncoding.GetByteCount(password)];
|
||||
StringEncoding.GetBytes(password, passwordBytes);
|
||||
|
||||
var result = Argon2.Library.Hash(
|
||||
TimeCost,
|
||||
MemoryCost,
|
||||
Parallelism,
|
||||
passwordBytes,
|
||||
salt,
|
||||
hash,
|
||||
null,
|
||||
(int)ArgonType,
|
||||
0x13
|
||||
);
|
||||
|
||||
if (result != Argon2Error.OK)
|
||||
throw new Argon2Exception("raw hashing", result);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Hashes the password and verifies that the password results in the specified hash.
|
||||
/// The ArgonType must of this PasswordHasher object must match what was used to generate expectedHash.
|
||||
/// The other parameters (timeCost, etc.) do not need to match and the parameters embedded in the expectedHash will be used.
|
||||
/// <param name="expectedHash">Hashing the password should result in this hash</param>
|
||||
/// <param name="password">The password to hash and compare its result to expectedHash. The password is first decoded into bytes using StringEncoding (default: Encoding.UTF8)</param>
|
||||
/// <returns>Whether the password results in the expectedHash when hashed</returns>
|
||||
/// </summary>
|
||||
public bool Verify(ReadOnlySpan<char> expectedHash, ReadOnlySpan<char> password)
|
||||
{
|
||||
Span<byte> expectedHashBytes = stackalloc byte[StringEncoding.GetByteCount(expectedHash)];
|
||||
StringEncoding.GetBytes(expectedHash, expectedHashBytes);
|
||||
Span<byte> passwordBytes = stackalloc byte[StringEncoding.GetByteCount(password)];
|
||||
StringEncoding.GetBytes(password, passwordBytes);
|
||||
return Verify(expectedHashBytes, passwordBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hashes the raw password bytes and verifies that the password results in the specified hash.
|
||||
/// The ArgonType must of this PasswordHasher object must match what was used to generate expectedHash.
|
||||
/// The other parameters (timeCost, etc.) do not need to match and the parameters embedded in the expectedHash will be used.
|
||||
/// <param name="expectedHash">Hashing the password should result in this hash</param>
|
||||
/// <param name="password">The raw password bytes to hash and compare its result to expectedHash</param>
|
||||
/// <returns>Whether the password results in the expectedHash when hashed</returns>
|
||||
/// </summary>
|
||||
public bool Verify(ReadOnlySpan<byte> expectedHash, ReadOnlySpan<byte> password)
|
||||
{
|
||||
var result = Argon2.Library.Verify(expectedHash, password, password.Length, (int)ArgonType);
|
||||
|
||||
if (result == Argon2Error.OK || result == Argon2Error.VERIFY_MISMATCH || result == Argon2Error.DECODING_FAIL)
|
||||
return result == Argon2Error.OK;
|
||||
|
||||
throw new Argon2Exception("verifying", result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hashes the password and verifies that the password results in the specified hash. (See Verify method)
|
||||
/// If the password verification is successful, this method checks to see if the memory cost, time cost, and parallelism
|
||||
/// match the parameters the PasswordHasher object was constructed with. If they do not much, then the password is rehashed
|
||||
/// using the new parameters and the result is outputted via the newFormattedHash parameter.
|
||||
/// <param name="expectedHash">Hashing the password should result in this hash</param>
|
||||
/// <param name="password">The raw password bytes to hash and compare its result to expectedHash</param>
|
||||
/// <param name="isUpdated">Whether the cost parameters of expectedHash differ from the PasswordHasher object and if the password was rehashed using th new parameters. This is always false if the password was incorrect.</param>
|
||||
/// <param name="newFormattedHash">If isUpdated is true, then newFormattedHash is the password hashed with the new cost parameters. If isUpdated is false, then newFormattedHash is expectedHash.</param>
|
||||
/// <returns>Whether the password results in the expectedHash when hashed</returns>
|
||||
/// </summary>
|
||||
public bool VerifyAndUpdate(ReadOnlySpan<char> expectedHash, ReadOnlySpan<char> password, out bool isUpdated, out string newFormattedHash)
|
||||
{
|
||||
bool verified = Verify(expectedHash, password);
|
||||
|
||||
if (verified)
|
||||
{
|
||||
var hashMetadata = ExtractMetadata(expectedHash);
|
||||
|
||||
if (hashMetadata.MemoryCost != MemoryCost || hashMetadata.TimeCost != TimeCost || hashMetadata.Parallelism != Parallelism)
|
||||
{
|
||||
isUpdated = true;
|
||||
byte[] salt = hashMetadata.Salt;
|
||||
newFormattedHash = Hash(password, salt);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
isUpdated = false;
|
||||
newFormattedHash = expectedHash.ToString();
|
||||
return verified;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the memory cost, time cost, etc. used to generate the Argon2 hash.
|
||||
/// <param name="formattedHash">An encoded Argon2 hash created by the Hash method</param>
|
||||
/// <returns>The hash metadata or null if the formattedHash was not a valid encoded Argon2 hash</returns>
|
||||
/// </summary>
|
||||
public static HashMetadata ExtractMetadata(ReadOnlySpan<char> formattedHash)
|
||||
{
|
||||
var context = new Argon2Context
|
||||
{
|
||||
Out = Marshal.AllocHGlobal(formattedHash.Length), // ensure the space to hold the hash is long enough
|
||||
OutLen = (uint)formattedHash.Length,
|
||||
Pwd = Marshal.AllocHGlobal(1),
|
||||
PwdLen = 1,
|
||||
Salt = Marshal.AllocHGlobal(formattedHash.Length), // ensure the space to hold the salt is long enough
|
||||
SaltLen = (uint)formattedHash.Length,
|
||||
Secret = Marshal.AllocHGlobal(1),
|
||||
SecretLen = 1,
|
||||
AssocData = Marshal.AllocHGlobal(1),
|
||||
AssocDataLen = 1,
|
||||
TimeCost = 0,
|
||||
MemoryCost = 0,
|
||||
Lanes = 0,
|
||||
Threads = 0
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var type = formattedHash.StartsWith("$argon2i") ? Argon2Type.Argon2i : Argon2Type.Argon2d;
|
||||
formattedHash = $"{formattedHash.ToString()}\0";
|
||||
|
||||
Span<byte> bytes = stackalloc byte[formattedHash.Length];
|
||||
Encoding.ASCII.GetBytes(formattedHash, bytes);
|
||||
|
||||
var result = Argon2.Library.Decode(context, bytes, (int)type);
|
||||
|
||||
if (result != Argon2Error.OK)
|
||||
return null;
|
||||
|
||||
var salt = new byte[context.SaltLen];
|
||||
var hash = new byte[context.OutLen];
|
||||
Marshal.Copy(context.Salt, salt, 0, salt.Length);
|
||||
Marshal.Copy(context.Out, hash, 0, hash.Length);
|
||||
|
||||
return new HashMetadata
|
||||
{
|
||||
ArgonType = type,
|
||||
MemoryCost = context.MemoryCost,
|
||||
TimeCost = context.TimeCost,
|
||||
Parallelism = context.Threads,
|
||||
Salt = salt,
|
||||
Hash = hash
|
||||
};
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(context.Out);
|
||||
Marshal.FreeHGlobal(context.Pwd);
|
||||
Marshal.FreeHGlobal(context.Salt);
|
||||
Marshal.FreeHGlobal(context.Secret);
|
||||
Marshal.FreeHGlobal(context.AssocData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
namespace System.Security.Cryptography
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of Argon2 hashing algorithm to use.
|
||||
/// </summary>
|
||||
public enum Argon2Type
|
||||
{
|
||||
/// <summary>
|
||||
/// The memory access is dependent upon the hash value (vulnerable to side-channel attacks)
|
||||
/// </summary>
|
||||
Argon2d = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The memory access is independent upon the hash value (safe from side-channel atacks)
|
||||
/// </summary>
|
||||
Argon2i = 1
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
namespace System.Security.Cryptography
|
||||
{
|
||||
/// <summary>
|
||||
/// HashMetadata represents the information stored in the encoded Argon2 format
|
||||
/// </summary>
|
||||
public class HashMetadata
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of Argon2 hashing algorithm to use
|
||||
/// Argon2d - The memory access is dependent upon the hash value (vulnerable to side-channel attacks)
|
||||
/// Argon2i - The memory access is independent upon the hash value (safe from side-channel atacks)
|
||||
/// </summary>
|
||||
public Argon2Type ArgonType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How much memory to use while hashing in kibibytes (KiB)
|
||||
/// </summary>
|
||||
public uint MemoryCost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How many iterations of the Argon2 hash to perform
|
||||
/// </summary>
|
||||
public uint TimeCost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How many threads to use while hashing
|
||||
/// </summary>
|
||||
public uint Parallelism { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw bytes of the salt
|
||||
/// </summary>
|
||||
public byte[] Salt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw bytes of the hash
|
||||
/// </summary>
|
||||
public byte[] Hash { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A base-64 encoded string of the salt, minus the padding (=) characters
|
||||
/// </summary>
|
||||
public string GetBase64Salt() => Convert.ToBase64String(Salt).Replace("=", "");
|
||||
|
||||
/// <summary>
|
||||
/// A base-64 encoded string of the hash, minus the padding (=) characters
|
||||
/// </summary>
|
||||
public string GetBase64Hash() => Convert.ToBase64String(Hash).Replace("=", "");
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts HashMetadata back into the original Argon2 formatted string.
|
||||
/// </summary>
|
||||
public override string ToString() =>
|
||||
$"$argon2{(ArgonType == Argon2Type.Argon2i ? "i" : "d")}$v=19$m={MemoryCost},t={TimeCost},p={Parallelism}${GetBase64Salt()}${GetBase64Hash()}";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
".NETCoreApp,Version=v3.1": {},
|
||||
".NETCoreApp,Version=v3.1/linux-x64": {},
|
||||
".NETCoreApp,Version=v3.1/osx-x64": {},
|
||||
".NETCoreApp,Version=v3.1/win-x64": {}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1184,7 +1184,7 @@
|
|||
"ZLib.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
},
|
||||
"ModernUO": {
|
||||
"type": "Project",
|
||||
|
|
@ -2068,7 +2068,7 @@
|
|||
"ZLib.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v3.1/osx-x64": {
|
||||
|
|
@ -2942,7 +2942,7 @@
|
|||
"ZLib.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v3.1/win-x64": {
|
||||
|
|
@ -3799,7 +3799,7 @@
|
|||
"ZLib.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
"type": "Direct",
|
||||
"requested": "[1.0.2, )",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
@ -116,7 +116,7 @@
|
|||
"type": "Direct",
|
||||
"requested": "[1.0.2, )",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
@ -132,7 +132,7 @@
|
|||
"type": "Direct",
|
||||
"requested": "[1.0.2, )",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
@ -148,7 +148,7 @@
|
|||
"type": "Direct",
|
||||
"requested": "[1.0.2, )",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@
|
|||
},
|
||||
"Argon2.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.2.7",
|
||||
"contentHash": "ZmxtDx9RwHdRBHSq8d97VNHF0el1OAQzWQAtMyT+F/1KApVjBpPcqXVr4eAvAp8qQqBSl5y3WhEvBMBRBdkpgw=="
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "cxRZ+nwH33QozaFBAftjctf9PoNEXgcEI5dBHHDkWI24EwCeOXRp0M+h5muavQADfxIvPG9o4FNCSnP7VkV6wQ=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
@ -1330,7 +1330,7 @@
|
|||
"ZLib.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
},
|
||||
"ModernUO": {
|
||||
"type": "Project",
|
||||
|
|
@ -1345,7 +1345,7 @@
|
|||
"uocontent": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Argon2.Bindings": "1.2.7",
|
||||
"Argon2.Bindings": "1.3.0",
|
||||
"MailKit": "2.7.0",
|
||||
"Microsoft.AspNetCore.Connections.Abstractions": "3.1.5",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.5",
|
||||
|
|
@ -1358,8 +1358,8 @@
|
|||
".NETCoreApp,Version=v3.1/linux-x64": {
|
||||
"Argon2.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.2.7",
|
||||
"contentHash": "ZmxtDx9RwHdRBHSq8d97VNHF0el1OAQzWQAtMyT+F/1KApVjBpPcqXVr4eAvAp8qQqBSl5y3WhEvBMBRBdkpgw=="
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "cxRZ+nwH33QozaFBAftjctf9PoNEXgcEI5dBHHDkWI24EwCeOXRp0M+h5muavQADfxIvPG9o4FNCSnP7VkV6wQ=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
@ -2242,14 +2242,14 @@
|
|||
"ZLib.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v3.1/osx-x64": {
|
||||
"Argon2.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.2.7",
|
||||
"contentHash": "ZmxtDx9RwHdRBHSq8d97VNHF0el1OAQzWQAtMyT+F/1KApVjBpPcqXVr4eAvAp8qQqBSl5y3WhEvBMBRBdkpgw=="
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "cxRZ+nwH33QozaFBAftjctf9PoNEXgcEI5dBHHDkWI24EwCeOXRp0M+h5muavQADfxIvPG9o4FNCSnP7VkV6wQ=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
@ -3132,14 +3132,14 @@
|
|||
"ZLib.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
}
|
||||
},
|
||||
".NETCoreApp,Version=v3.1/win-x64": {
|
||||
"Argon2.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.2.7",
|
||||
"contentHash": "ZmxtDx9RwHdRBHSq8d97VNHF0el1OAQzWQAtMyT+F/1KApVjBpPcqXVr4eAvAp8qQqBSl5y3WhEvBMBRBdkpgw=="
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "cxRZ+nwH33QozaFBAftjctf9PoNEXgcEI5dBHHDkWI24EwCeOXRp0M+h5muavQADfxIvPG9o4FNCSnP7VkV6wQ=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
@ -4019,7 +4019,7 @@
|
|||
"ZLib.Bindings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ namespace Server.Accounting.Security
|
|||
public class Argon2PasswordProtection : IPasswordProtection
|
||||
{
|
||||
public static IPasswordProtection Instance = new Argon2PasswordProtection();
|
||||
private Argon2PasswordHasher m_PasswordHasher = new Argon2PasswordHasher(RandomProviders.SecureProvider as RandomNumberGenerator);
|
||||
private Argon2PasswordHasher m_PasswordHasher = new Argon2PasswordHasher(
|
||||
rng: RandomProviders.SecureProvider as RandomNumberGenerator
|
||||
);
|
||||
|
||||
public string EncryptPassword(string plainPassword) =>
|
||||
m_PasswordHasher.Hash(plainPassword);
|
||||
|
|
|
|||
|
|
@ -66,9 +66,10 @@
|
|||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.5" />
|
||||
<!-- Direct packages -->
|
||||
<PackageReference Include="MailKit" Version="2.7.0" />
|
||||
<PackageReference Include="Argon2.Bindings" Version="1.2.7" />
|
||||
<PackageReference Include="Zlib.Bindings" Version="1.0.2" />
|
||||
<PackageReference Include="Argon2.Bindings" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Configuration)'=='Analyze'">
|
||||
<PackageReference Include="StyleCop.Analyzers">
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
".NETCoreApp,Version=v3.1": {
|
||||
"Argon2.Bindings": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.2.7, )",
|
||||
"resolved": "1.2.7",
|
||||
"contentHash": "ZmxtDx9RwHdRBHSq8d97VNHF0el1OAQzWQAtMyT+F/1KApVjBpPcqXVr4eAvAp8qQqBSl5y3WhEvBMBRBdkpgw=="
|
||||
"requested": "[1.3.0, )",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "cxRZ+nwH33QozaFBAftjctf9PoNEXgcEI5dBHHDkWI24EwCeOXRp0M+h5muavQADfxIvPG9o4FNCSnP7VkV6wQ=="
|
||||
},
|
||||
"MailKit": {
|
||||
"type": "Direct",
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
"type": "Direct",
|
||||
"requested": "[1.0.2, )",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
@ -799,15 +799,15 @@
|
|||
".NETCoreApp,Version=v3.1/linux-x64": {
|
||||
"Argon2.Bindings": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.2.7, )",
|
||||
"resolved": "1.2.7",
|
||||
"contentHash": "ZmxtDx9RwHdRBHSq8d97VNHF0el1OAQzWQAtMyT+F/1KApVjBpPcqXVr4eAvAp8qQqBSl5y3WhEvBMBRBdkpgw=="
|
||||
"requested": "[1.3.0, )",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "cxRZ+nwH33QozaFBAftjctf9PoNEXgcEI5dBHHDkWI24EwCeOXRp0M+h5muavQADfxIvPG9o4FNCSnP7VkV6wQ=="
|
||||
},
|
||||
"ZLib.Bindings": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.0.2, )",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
@ -1502,15 +1502,15 @@
|
|||
".NETCoreApp,Version=v3.1/osx-x64": {
|
||||
"Argon2.Bindings": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.2.7, )",
|
||||
"resolved": "1.2.7",
|
||||
"contentHash": "ZmxtDx9RwHdRBHSq8d97VNHF0el1OAQzWQAtMyT+F/1KApVjBpPcqXVr4eAvAp8qQqBSl5y3WhEvBMBRBdkpgw=="
|
||||
"requested": "[1.3.0, )",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "cxRZ+nwH33QozaFBAftjctf9PoNEXgcEI5dBHHDkWI24EwCeOXRp0M+h5muavQADfxIvPG9o4FNCSnP7VkV6wQ=="
|
||||
},
|
||||
"ZLib.Bindings": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.0.2, )",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
@ -2205,15 +2205,15 @@
|
|||
".NETCoreApp,Version=v3.1/win-x64": {
|
||||
"Argon2.Bindings": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.2.7, )",
|
||||
"resolved": "1.2.7",
|
||||
"contentHash": "ZmxtDx9RwHdRBHSq8d97VNHF0el1OAQzWQAtMyT+F/1KApVjBpPcqXVr4eAvAp8qQqBSl5y3WhEvBMBRBdkpgw=="
|
||||
"requested": "[1.3.0, )",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "cxRZ+nwH33QozaFBAftjctf9PoNEXgcEI5dBHHDkWI24EwCeOXRp0M+h5muavQADfxIvPG9o4FNCSnP7VkV6wQ=="
|
||||
},
|
||||
"ZLib.Bindings": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.0.2, )",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "oMnRfnRHzfboCS/SXUrrqbDVtM/9h5LkHkB8GuyUq70BYkJRza7CNZxLR+F6IKOTNDcDO68VVCID4DA5Sj8c4Q=="
|
||||
"contentHash": "KlvJLY55UYpwlxbiX+lJbTuaMWBK3mja3BC3GzTlCA3uHRYxsllL9uYqpe4poFe6l8NMBS/k759+ns8pbeXeMg=="
|
||||
},
|
||||
"Libuv": {
|
||||
"type": "Transitive",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue