Adds Argon2 for password protection (#123)
This commit is contained in:
parent
29467a3ed9
commit
dad8a64fad
54 changed files with 1152 additions and 167 deletions
13
.circleci/checksum.txt
Normal file
13
.circleci/checksum.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
95482048463cdc99c77a69951654de7b28fd6880 ../Projects/Argon2/Argon2.csproj
|
||||
ebafae4e8160057cbf408cb13114479ca26e1b58 ../Projects/Scripts.Tests/Scripts.Tests.csproj
|
||||
6c6a48220658bdfa7b2e1e173077fd139ed4af2c ../Projects/Scripts/Scripts.csproj
|
||||
6213c10f697b45729bab15f7870c42dcf49b026b ../Projects/Server.Tests/Server.Tests.csproj
|
||||
4b3626e04f76dff1ab445e207658a3b386fce4e5 ../Projects/Server/Server.csproj
|
||||
a663d309b6b86c7632ea5cd175468dd5180808c1 ../Projects/Argon2/Argon2.cs
|
||||
1e89625abe364f895346d0c5753f3ca6653cf7df ../Projects/Argon2/Argon2Context.cs
|
||||
abbb34d85f55ca1d78a400b4d46afbd6965f642b ../Projects/Argon2/Argon2Error.cs
|
||||
00ef35a6809d4959bdda1de01f45e39ff388270f ../Projects/Argon2/Argon2Exception.cs
|
||||
53164d1621e24adefc6917379d36d7273551f457 ../Projects/Argon2/Argon2PasswordHasher.cs
|
||||
a137d2fe0478d065d478366168f80ab9eaaa9c3a ../Projects/Argon2/Argon2Type.cs
|
||||
c09f7a2f9690d56ca838aafb28640c09950c5a8c ../Projects/Argon2/HashMetadata.cs
|
||||
b5da07548eb41ec9bd35bc2def006f23698b357e ../Projects/Argon2/Utility.cs
|
||||
|
|
@ -19,17 +19,20 @@ jobs:
|
|||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- dotnet-packages-linux-{{ checksum "Projects/Server/Server.csproj" }}-{{ checksum "Projects/Scripts/Scripts.csproj" }}
|
||||
- dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
|
||||
- run:
|
||||
name: Build Argon2
|
||||
command: dotnet build -c Release -r linux-x64 Projects/Argon2/Argon2.csproj
|
||||
- run:
|
||||
name: Install ModernUO dependencies
|
||||
command: dotnet restore
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.nuget/packages
|
||||
key: dotnet-packages-linux-{{ checksum "Projects/Server/Server.csproj" }}-{{ checksum "Projects/Scripts/Scripts.csproj" }}
|
||||
- /mnt/ramdisk/packages
|
||||
key: dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
|
||||
- run:
|
||||
name: Building ModernUO for Linux (Debug)
|
||||
command: dotnet build -c Release /p:PublishProfile=Linux
|
||||
command: dotnet build -c Debug -r linux-x64
|
||||
build_windows:
|
||||
description: Build application
|
||||
executor: win/default
|
||||
|
|
@ -37,17 +40,20 @@ jobs:
|
|||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- dotnet-packages-windows-{{ checksum "Projects/Server/Server.csproj" }}-{{ checksum "Projects/Scripts/Scripts.csproj" }}
|
||||
- dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
|
||||
- run:
|
||||
name: Build Argon2
|
||||
command: dotnet build -c Debug -r win-x64 Projects/Argon2/Argon2.csproj
|
||||
- run:
|
||||
name: Install ModernUO dependencies
|
||||
command: dotnet restore
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.nuget/packages
|
||||
key: dotnet-packages-windows-{{ checksum "Projects/Server/Server.csproj" }}-{{ checksum "Projects/Scripts/Scripts.csproj" }}
|
||||
- /mnt/ramdisk/packages
|
||||
key: dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
|
||||
- run:
|
||||
name: Building ModernUO for Windows (Debug)
|
||||
command: dotnet build -c Release /p:PublishProfile=Windows
|
||||
command: dotnet build -c Debug -r win-x64
|
||||
code_styling:
|
||||
description: Code analysis
|
||||
executor: linux-build
|
||||
|
|
@ -56,17 +62,20 @@ jobs:
|
|||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- dotnet-packages-linux-{{ checksum "Projects/Server/Server.csproj" }}-{{ checksum "Projects/Scripts/Scripts.csproj" }}
|
||||
- dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
|
||||
- run:
|
||||
name: Build Argon2
|
||||
command: dotnet build -c Debug -r linux-x64 Projects/Argon2/Argon2.csproj
|
||||
- run:
|
||||
name: Install ModernUO dependencies
|
||||
command: dotnet restore
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.nuget/packages
|
||||
key: dotnet-packages-linux-{{ checksum "Projects/Server/Server.csproj" }}-{{ checksum "Projects/Scripts/Scripts.csproj" }}
|
||||
- /mnt/ramdisk/packages
|
||||
key: dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
|
||||
- run:
|
||||
name: Building with Analyzers
|
||||
command: dotnet build -c Analyze /p:PublishProfile=Linux
|
||||
command: dotnet build -c Analyze -r linux-x64
|
||||
tests:
|
||||
description: Unit Tests
|
||||
executor: linux-build
|
||||
|
|
@ -75,17 +84,20 @@ jobs:
|
|||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- dotnet-packages-linux-{{ checksum "Projects/Server/Server.csproj" }}-{{ checksum "Projects/Scripts/Scripts.csproj" }}
|
||||
- dotnet-packages-v1-{{ arch }}-{{ checksum ".circleci/checksum.txt" }}
|
||||
- run:
|
||||
name: Build Argon2
|
||||
command: dotnet build -c Debug -r linux-x64 Projects/Argon2/Argon2.csproj
|
||||
- run:
|
||||
name: Install ModernUO dependencies
|
||||
command: dotnet restore
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.nuget/packages
|
||||
key: dotnet-packages-linux-{{ checksum "Projects/Server/Server.csproj" }}-{{ checksum "Projects/Scripts/Scripts.csproj" }}
|
||||
- /mnt/ramdisk/packages
|
||||
key: dotnet-packages-linux-{{ checksum ".circleci/checksum.txt" }}
|
||||
- run:
|
||||
name: Running unit tests
|
||||
command: dotnet test
|
||||
command: dotnet test -r linux-x64
|
||||
workflows:
|
||||
build-and-test:
|
||||
jobs:
|
||||
|
|
|
|||
1
.circleci/genchecksum.sh
Executable file
1
.circleci/genchecksum.sh
Executable file
|
|
@ -0,0 +1 @@
|
|||
sha1sum ../Projects/*/*.csproj ../Projects/Argon2/*.cs > "checksum.txt"
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -39,3 +39,6 @@
|
|||
/.vs
|
||||
|
||||
.DS_Store
|
||||
|
||||
/packages/*
|
||||
!/packages/do_not_delete
|
||||
|
|
|
|||
66
ModernUO.sln
66
ModernUO.sln
|
|
@ -2,45 +2,53 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||
# 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}") = "Scripts", "Projects\Scripts\Scripts.csproj", "{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.Tests", "Projects\Server.Tests\Server.Tests.csproj", "{D7A5D3AF-D607-46EF-BAAD-0D424190311F}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server.Tests", "Projects\Server.Tests\Server.Tests.csproj", "{D7A5D3AF-D607-46EF-BAAD-0D424190311F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scripts.Tests", "Projects\Scripts.Tests\Scripts.Tests.csproj", "{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scripts.Tests", "Projects\Scripts.Tests\Scripts.Tests.csproj", "{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Analyze|Any CPU = Analyze|Any CPU
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Analyze|x64 = Analyze|x64
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Analyze|Any CPU.ActiveCfg = Analyze|Any CPU
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Analyze|Any CPU.Build.0 = Analyze|Any CPU
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Analyze|Any CPU.ActiveCfg = Analyze|Any CPU
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Analyze|Any CPU.Build.0 = Analyze|Any CPU
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Analyze|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Analyze|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Analyze|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Analyze|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Analyze|x64.ActiveCfg = Release|x64
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Analyze|x64.Build.0 = Release|x64
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Debug|x64.Build.0 = Debug|x64
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Release|x64.ActiveCfg = Release|x64
|
||||
{5E93BB35-3661-4822-9A8A-859726BAD87F}.Release|x64.Build.0 = Release|x64
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Analyze|x64.ActiveCfg = Release|x64
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Analyze|x64.Build.0 = Release|x64
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Debug|x64.Build.0 = Debug|x64
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Release|x64.ActiveCfg = Release|x64
|
||||
{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Release|x64.Build.0 = Release|x64
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Analyze|x64.ActiveCfg = Debug|x64
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Analyze|x64.Build.0 = Debug|x64
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Debug|x64.Build.0 = Debug|x64
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Release|x64.ActiveCfg = Release|x64
|
||||
{D7A5D3AF-D607-46EF-BAAD-0D424190311F}.Release|x64.Build.0 = Release|x64
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Analyze|x64.ActiveCfg = Debug|x64
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Analyze|x64.Build.0 = Debug|x64
|
||||
{3C4797F9-603E-44EF-8E8C-9275CC9EA74B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{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 = Release|x64
|
||||
{97150E9D-5561-4D3C-9B78-E795544507D0}.Analyze|x64.Build.0 = Release|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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
|||
6
NuGet.Config
Normal file
6
NuGet.Config
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="local" value="packages" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
128
Projects/Argon2/Argon2.cs
Normal file
128
Projects/Argon2/Argon2.cs
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
internal interface IArgon2
|
||||
{
|
||||
public Argon2Error Hash(uint t_cost, uint m_cost, uint parallelism,
|
||||
byte[] pwd,
|
||||
byte[] salt,
|
||||
byte[] hash,
|
||||
byte[] encoded,
|
||||
int type, int version);
|
||||
|
||||
Argon2Error Verify(byte[] encoded, byte[] pwd, int pwdlen, int type);
|
||||
|
||||
// TODO: Change str to use ReadOnlySpan<char> then convert to pointer later
|
||||
Argon2Error Decode(Argon2Context ctx, string str, int type);
|
||||
}
|
||||
|
||||
internal static class Argon2
|
||||
{
|
||||
internal static readonly IArgon2 Library;
|
||||
|
||||
static Argon2()
|
||||
{
|
||||
if (RuntimeUtility.Unix)
|
||||
Library = new UnixArgon2();
|
||||
else
|
||||
Library = new WindowsArgon2();
|
||||
}
|
||||
}
|
||||
|
||||
internal class WindowsArgon2 : IArgon2
|
||||
{
|
||||
public Argon2Error Hash(uint t_cost, uint m_cost, uint parallelism,
|
||||
byte[] pwd,
|
||||
byte[] salt,
|
||||
byte[] hash,
|
||||
byte[] encoded,
|
||||
int type, int version) =>
|
||||
NativeMethods.crypto_argon2_hash(t_cost, m_cost, parallelism,
|
||||
pwd, pwd.Length,
|
||||
salt, salt.Length,
|
||||
hash, hash.Length,
|
||||
encoded, encoded.Length,
|
||||
type, version
|
||||
);
|
||||
|
||||
public Argon2Error Verify(byte[] encoded, byte[] pwd, int pwdlen, int type) =>
|
||||
NativeMethods.crypto_argon2_verify(encoded, pwd, pwdlen, type);
|
||||
|
||||
public Argon2Error Decode(Argon2Context ctx, string str, int type)
|
||||
{
|
||||
byte[] bytes = new byte[str.Length];
|
||||
Encoding.ASCII.GetBytes(str, bytes);
|
||||
|
||||
// TODO: Use pointers instead
|
||||
return NativeMethods.crypto_decode_string(ctx, bytes, type);
|
||||
}
|
||||
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[DllImport("argon2.dll", EntryPoint = "crypto_argon2_hash", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern Argon2Error crypto_argon2_hash(uint t_cost, uint m_cost, uint parallelism,
|
||||
byte[] pwd, int pwdlen,
|
||||
byte[] salt, int saltlen,
|
||||
byte[] hash, int hashlen,
|
||||
byte[] encoded, int encodedlen,
|
||||
int type, int version
|
||||
);
|
||||
|
||||
[DllImport("argon2.dll", EntryPoint = "crypto_argon2_verify", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern Argon2Error crypto_argon2_verify(byte[] encoded, byte[] pwd, int pwdlen, int type);
|
||||
|
||||
[DllImport("argon2.dll", EntryPoint = "crypto_decode_string", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern Argon2Error crypto_decode_string(Argon2Context ctx, byte[] str, int type);
|
||||
}
|
||||
}
|
||||
|
||||
internal class UnixArgon2 : IArgon2
|
||||
{
|
||||
public Argon2Error Hash(uint t_cost, uint m_cost, uint parallelism,
|
||||
byte[] pwd,
|
||||
byte[] salt,
|
||||
byte[] hash,
|
||||
byte[] encoded,
|
||||
int type, int version) =>
|
||||
NativeMethods.crypto_argon2_hash(t_cost, m_cost, parallelism,
|
||||
pwd, pwd.Length,
|
||||
salt, salt.Length,
|
||||
hash, hash.Length,
|
||||
encoded, encoded.Length,
|
||||
type, version
|
||||
);
|
||||
|
||||
public Argon2Error Verify(byte[] encoded, byte[] pwd, int pwdlen, int type) =>
|
||||
NativeMethods.crypto_argon2_verify(encoded, pwd, pwdlen, type);
|
||||
|
||||
public Argon2Error Decode(Argon2Context ctx, string str, int type)
|
||||
{
|
||||
byte[] bytes = new byte[str.Length];
|
||||
Encoding.ASCII.GetBytes(str, bytes);
|
||||
|
||||
// TODO: Use pointers instead
|
||||
return NativeMethods.crypto_decode_string(ctx, bytes, type);
|
||||
}
|
||||
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[DllImport("libargon2", EntryPoint = "argon2_hash")]
|
||||
internal static extern Argon2Error crypto_argon2_hash(uint t_cost, uint m_cost, uint parallelism,
|
||||
byte[] pwd, int pwdlen,
|
||||
byte[] salt, int saltlen,
|
||||
byte[] hash, int hashlen,
|
||||
byte[] encoded, int encodedlen,
|
||||
int type, int version
|
||||
);
|
||||
|
||||
[DllImport("libargon2", EntryPoint = "argon2_verify")]
|
||||
internal static extern Argon2Error crypto_argon2_verify(byte[] encoded, byte[] pwd, int pwdlen, int type);
|
||||
|
||||
[DllImport("libargon2", EntryPoint = "decode_string")]
|
||||
internal static extern Argon2Error crypto_decode_string(Argon2Context ctx, byte[] str, int type);
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Projects/Argon2/Argon2.csproj
Normal file
42
Projects/Argon2/Argon2.csproj
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<PackageVersion>1.0.0</PackageVersion>
|
||||
<RootNamespace>Server</RootNamespace>
|
||||
<AssemblyName>Argon2.Bindings</AssemblyName>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>true</IsPackable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<Configurations>Debug;Release;Analyze</Configurations>
|
||||
<DefineConstants Condition="'$(RuntimeIdentifier)' == 'win-x64'">WINDOWS</DefineConstants>
|
||||
<AssemblyVersion>1.0.0</AssemblyVersion>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="runtimes\win-x64\native\argon2.dll">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>runtimes/win-x64/native</PackagePath>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="runtimes\osx-x64\native\libargon2.dylib">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>runtimes/osx-x64/native</PackagePath>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="runtimes\linux-x64\native\libargon2.so">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>runtimes/linux-x64/native</PackagePath>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Target Name="CopyPackage" AfterTargets="Pack">
|
||||
<Exec Command="dotnet nuget push $(OutputPath)..\..\$(PackageId).$(PackageVersion).nupkg -s local" />
|
||||
</Target>
|
||||
<!-- <Target Name="CopyPackage" AfterTargets="Pack">
|
||||
<Exec Command="nuget add $(OutputPath)..\$(PackageId).$(PackageVersion).nupkg -Source ../../packages" />
|
||||
</Target> -->
|
||||
</Project>
|
||||
15
Projects/Argon2/Argon2.nuspec
Normal file
15
Projects/Argon2/Argon2.nuspec
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0"?>
|
||||
<package >
|
||||
<metadata>
|
||||
<id>Argon2.Bindings</id>
|
||||
<version>1.0.0</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>Initial release</releaseNotes>
|
||||
<copyright>Copyright 2020</copyright>
|
||||
</metadata>
|
||||
</package>
|
||||
34
Projects/Argon2/Argon2Context.cs
Normal file
34
Projects/Argon2/Argon2Context.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
[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;
|
||||
}
|
||||
}
|
||||
77
Projects/Argon2/Argon2Error.cs
Normal file
77
Projects/Argon2/Argon2Error.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
namespace Server.Accounting.Security
|
||||
{
|
||||
/// <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 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
|
||||
}
|
||||
}
|
||||
20
Projects/Argon2/Argon2Exception.cs
Normal file
20
Projects/Argon2/Argon2Exception.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
/// <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(string.Format("Error during Argon2 {0}: ({1}) {2}", action, (int)error, error)) {}
|
||||
}
|
||||
}
|
||||
388
Projects/Argon2/Argon2PasswordHasher.cs
Normal file
388
Projects/Argon2/Argon2PasswordHasher.cs
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
// using System.Text.RegularExpressions;
|
||||
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
/// <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 readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider();
|
||||
|
||||
// private static readonly Regex HashRegex = new Regex(@"^\$argon2([di])\$v=(\d+)$m=(\d+),t=(\d+),p=(\d+)\$([A-Za-z0-9+/=]+)\$([A-Za-z0-9+/=]*)$", RegexOptions.Compiled);
|
||||
|
||||
|
||||
/// <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>
|
||||
/// 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()
|
||||
{
|
||||
TimeCost = 3;
|
||||
MemoryCost = 8192;
|
||||
Parallelism = 1;
|
||||
ArgonType = Argon2Type.Argon2i;
|
||||
HashLength = 32;
|
||||
StringEncoding = Encoding.UTF8;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the Argon2 PasswordHasher with the performance and algorithm settings to use while hashing
|
||||
/// <param name="timeCost">How many iterations of the Argon2 hash to perform (default: 3, must be at least 1)</param>
|
||||
/// <param name="memoryCost">How much memory to use while hashing in kibibytes (KiB) (default: 8192 KiB [8 MiB], must be at least 8 KiB)</param>
|
||||
/// <param name="parallelism">How many threads to use while hashing (default: 1, must be at least 1)</param>
|
||||
/// <param name="argonType">The type of Argon2 hashing algorithm to use (Independent [default] or Dependent)</param>
|
||||
/// <param name="hashLength">The length of the resulting hash in bytes (default: 32)</param>
|
||||
/// </summary>
|
||||
public Argon2PasswordHasher(uint timeCost = 3, uint memoryCost = 8192, uint parallelism = 1, Argon2Type argonType = Argon2Type.Argon2i, uint hashLength = 32)
|
||||
{
|
||||
TimeCost = timeCost;
|
||||
MemoryCost = memoryCost;
|
||||
Parallelism = parallelism;
|
||||
ArgonType = argonType;
|
||||
HashLength = hashLength;
|
||||
StringEncoding = Encoding.UTF8;
|
||||
}
|
||||
|
||||
|
||||
/// <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(string password)
|
||||
{
|
||||
CheckNull("Hash", "password", password);
|
||||
|
||||
return Hash(StringEncoding.GetBytes(password));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hash the raw password bytes using Argon2 with a cryptographically-secure, random, 16-byte salt.
|
||||
/// 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>
|
||||
/// <returns>A formatted string representing the hashed password, encoded with the parameters used to perform the hash</returns>
|
||||
/// </summary>
|
||||
public string Hash(byte[] password)
|
||||
{
|
||||
CheckNull("Hash", "password", password);
|
||||
|
||||
return Hash(password, GenerateSalt());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hash the password using Argon2 with the specified salt.
|
||||
/// Unless you need to specify your own salt for interoperability purposes, prefer the Hash(string password) overload instead.
|
||||
/// 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>
|
||||
/// <param name="salt">A string representing the salt to be used for the hash. The salt must be at least 8 bytes. The salt 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(string password, string salt)
|
||||
{
|
||||
CheckNull("Hash", "password", password, "salt", salt);
|
||||
|
||||
return Hash(StringEncoding.GetBytes(password), StringEncoding.GetBytes(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(byte[] password, byte[] salt)
|
||||
{
|
||||
CheckNull("Hash", "password", password, "salt", salt);
|
||||
|
||||
byte[] hash = new byte[HashLength];
|
||||
byte[] encoded = new byte[39 + ((HashLength + salt.Length) * 4 + 3) / 3];
|
||||
var result = Argon2.Library.Hash(
|
||||
TimeCost,
|
||||
MemoryCost,
|
||||
Parallelism,
|
||||
password,
|
||||
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, 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">A string representing the password to be hashed. The password is first decoded into bytes using StringEncoding (default: Encoding.UTF8)</param>
|
||||
/// <param name="salt">A string representing the salt to be used for the hash. The salt must be at least 8 bytes. The salt is first decoded into bytes using StringEncoding (default: Encoding.UTF8)</param>
|
||||
/// <returns>A byte array containing only the resulting hash</returns>
|
||||
/// </summary>
|
||||
public byte[] HashRaw(string password, string salt)
|
||||
{
|
||||
CheckNull("HashRaw", "password", password, "salt", salt);
|
||||
|
||||
return HashRaw(StringEncoding.GetBytes(password), StringEncoding.GetBytes(salt));
|
||||
}
|
||||
|
||||
/// <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 byte[] HashRaw(byte[] password, byte[] salt)
|
||||
{
|
||||
byte[] hash = new byte[(int)HashLength];
|
||||
|
||||
var result = Argon2.Library.Hash(
|
||||
TimeCost,
|
||||
MemoryCost,
|
||||
Parallelism,
|
||||
password,
|
||||
salt,
|
||||
hash,
|
||||
null,
|
||||
(int)ArgonType,
|
||||
0x13
|
||||
);
|
||||
|
||||
if (result != Argon2Error.OK)
|
||||
throw new Argon2Exception("raw hashing", result);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
/// <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(string expectedHash, string password)
|
||||
{
|
||||
CheckNull("Verify", "expectedHash", expectedHash, "password", password);
|
||||
|
||||
return Verify(expectedHash, StringEncoding.GetBytes(password));
|
||||
}
|
||||
|
||||
/// <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(string expectedHash, byte[] password)
|
||||
{
|
||||
CheckNull("Verify", "expectedHash", expectedHash, "password", password);
|
||||
|
||||
var result = Argon2.Library.Verify(StringEncoding.GetBytes(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 password to hash and compare its result to expectedHash. The password is first decoded into bytes using StringEncoding (default: Encoding.UTF8)</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(string expectedHash, string password, out bool isUpdated, out string newFormattedHash)
|
||||
{
|
||||
CheckNull("VerifyAndUpdate", "expectedHash", expectedHash, "password", password);
|
||||
|
||||
return VerifyAndUpdate(expectedHash, StringEncoding.GetBytes(password), out isUpdated, out newFormattedHash);
|
||||
}
|
||||
|
||||
/// <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(string expectedHash, byte[] password, out bool isUpdated, out string newFormattedHash)
|
||||
{
|
||||
CheckNull("VerifyAndUpdate", "expectedHash", expectedHash, "password", password);
|
||||
|
||||
if (Verify(expectedHash, password))
|
||||
{
|
||||
var hashMetadata = ExtractMetadata(expectedHash);
|
||||
|
||||
if (hashMetadata.MemoryCost != MemoryCost || hashMetadata.TimeCost != TimeCost || hashMetadata.Parallelism != Parallelism)
|
||||
{
|
||||
isUpdated = true;
|
||||
byte[] salt = hashMetadata.Salt;
|
||||
newFormattedHash = Hash(password, salt);
|
||||
}
|
||||
else
|
||||
{
|
||||
isUpdated = false;
|
||||
newFormattedHash = expectedHash;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
isUpdated = false;
|
||||
newFormattedHash = expectedHash;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Generate salt using a Cryptographically-Secure Pseudo-Random Number Generator
|
||||
/// <param name="byteLength">The number of bytes of salt to generate (default: 16)</param>
|
||||
/// <returns>A array of randomly-generated bytes</returns>
|
||||
/// </summary>
|
||||
public static byte[] GenerateSalt(uint byteLength = 16)
|
||||
{
|
||||
var salt = new byte[byteLength];
|
||||
Rng.GetBytes(salt);
|
||||
return salt;
|
||||
}
|
||||
|
||||
|
||||
/// <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(string formattedHash)
|
||||
{
|
||||
CheckNull("ExtractMetadata", "formattedHash", 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;
|
||||
var result = Argon2.Library.Decode(context, $"{formattedHash}\0", (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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void CheckNull(string methodName, params object[] arguments)
|
||||
{
|
||||
for (var i = 0; i < arguments.Length; i += 2)
|
||||
if (arguments[i + 1] == null)
|
||||
throw new ArgumentNullException(arguments[i].ToString(), string.Format("Argument {0} to method PasswordHasher.{1} is null", arguments[i], methodName));
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Projects/Argon2/Argon2Type.cs
Normal file
18
Projects/Argon2/Argon2Type.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
namespace Server.Accounting.Security
|
||||
{
|
||||
/// <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
|
||||
}
|
||||
}
|
||||
60
Projects/Argon2/HashMetadata.cs
Normal file
60
Projects/Argon2/HashMetadata.cs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
/// <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()}";
|
||||
}
|
||||
}
|
||||
13
Projects/Argon2/Utility.cs
Normal file
13
Projects/Argon2/Utility.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
internal static class RuntimeUtility
|
||||
{
|
||||
public static bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
public static bool IsDarwin = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
public static bool IsFreeBSD = RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD);
|
||||
public static bool IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || IsFreeBSD;
|
||||
public static bool Unix = IsDarwin || IsFreeBSD || IsLinux;
|
||||
}
|
||||
}
|
||||
BIN
Projects/Argon2/runtimes/linux-x64/native/libargon2.so
Executable file
BIN
Projects/Argon2/runtimes/linux-x64/native/libargon2.so
Executable file
Binary file not shown.
BIN
Projects/Argon2/runtimes/osx-x64/native/libargon2.dylib
Executable file
BIN
Projects/Argon2/runtimes/osx-x64/native/libargon2.dylib
Executable file
Binary file not shown.
BIN
Projects/Argon2/runtimes/win-x64/native/argon2.dll
Normal file
BIN
Projects/Argon2/runtimes/win-x64/native/argon2.dll
Normal file
Binary file not shown.
|
|
@ -0,0 +1,30 @@
|
|||
using Server.Accounting.Security;
|
||||
using Xunit;
|
||||
|
||||
namespace Server.Tests.Accounting.Security
|
||||
{
|
||||
public class Argon2PasswordProtectionTest
|
||||
{
|
||||
private const string plainPassword = "hello-good-sir";
|
||||
|
||||
[Fact]
|
||||
public void TestValidates()
|
||||
{
|
||||
var passwordProtection = new Argon2PasswordProtection();
|
||||
|
||||
string encryptedPassword = passwordProtection.EncryptPassword(plainPassword);
|
||||
|
||||
Assert.True(passwordProtection.ValidatePassword(encryptedPassword, plainPassword));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestPasswordDoesNotValidate()
|
||||
{
|
||||
var passwordProtection = new Argon2PasswordProtection();
|
||||
|
||||
string encryptedPassword = passwordProtection.EncryptPassword(plainPassword);
|
||||
|
||||
Assert.False(passwordProtection.ValidatePassword(encryptedPassword, "Not the same password"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using Server.Accounting.Security;
|
||||
using Xunit;
|
||||
using Server.Accounting;
|
||||
|
||||
namespace Server.Tests.Accounting
|
||||
namespace Server.Tests.Accounting.Security
|
||||
{
|
||||
public class PBKDF2PasswordProtectionTest
|
||||
{
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Platforms>x64</Platforms>
|
||||
<DefineConstants Condition="'$(RuntimeIdentifier)' == 'win-x64'">WINDOWS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Xml;
|
||||
using Server.Accounting.Security;
|
||||
using Server.Misc;
|
||||
using Server.Mobiles;
|
||||
using Server.Multis;
|
||||
|
|
@ -297,13 +298,9 @@ namespace Server.Accounting
|
|||
|
||||
public bool GetBanTags(out DateTime banTime, out TimeSpan banDuration)
|
||||
{
|
||||
string tagTime = GetTag("BanTime");
|
||||
string tagDuration = GetTag("BanDuration");
|
||||
|
||||
if (tagTime != null)
|
||||
banTime = Utility.GetXMLDateTime(tagTime, DateTime.MinValue);
|
||||
else
|
||||
banTime = DateTime.MinValue;
|
||||
banTime = Utility.GetXMLDateTime(GetTag("BanTime"), DateTime.MinValue);
|
||||
|
||||
if (tagDuration == "Infinite")
|
||||
banDuration = TimeSpan.MaxValue;
|
||||
|
|
@ -323,7 +320,9 @@ namespace Server.Accounting
|
|||
|
||||
public bool CheckPassword(string plainPassword)
|
||||
{
|
||||
bool ok = AccountSecurity.GetPasswordProtection(m_PasswordAlgorithm).ValidatePassword(Password, plainPassword);
|
||||
string phrase = m_PasswordAlgorithm == PasswordProtectionAlgorithm.SHA1 ? $"{Username}{plainPassword}" : plainPassword;
|
||||
|
||||
bool ok = AccountSecurity.GetPasswordProtection(m_PasswordAlgorithm).ValidatePassword(Password, phrase);
|
||||
if (!ok)
|
||||
return false;
|
||||
|
||||
|
|
@ -459,6 +458,24 @@ namespace Server.Accounting
|
|||
// TODO: Offload passwords to its own module so it can be easily written/upgraded
|
||||
Password = Utility.GetText(node["password"], null);
|
||||
Enum.TryParse(Utility.GetText(node["passwordAlgorithm"], null), true, out m_PasswordAlgorithm);
|
||||
|
||||
if (m_PasswordAlgorithm == PasswordProtectionAlgorithm.None)
|
||||
{
|
||||
string md5Password = Utility.GetText(node["cryptPassword"], null);
|
||||
string sha1Password = Utility.GetText(node["newCryptPassword"], null);
|
||||
|
||||
if (sha1Password != null)
|
||||
{
|
||||
Password = sha1Password;
|
||||
m_PasswordAlgorithm = PasswordProtectionAlgorithm.SHA1;
|
||||
}
|
||||
else if (md5Password != null)
|
||||
{
|
||||
Password = md5Password;
|
||||
m_PasswordAlgorithm = PasswordProtectionAlgorithm.MD5;
|
||||
}
|
||||
}
|
||||
|
||||
Enum.TryParse(Utility.GetText(node["accessLevel"], "Player"), true, out m_AccessLevel);
|
||||
Flags = Utility.GetXMLInt32(Utility.GetText(node["flags"], "0"), 0);
|
||||
Created = Utility.GetXMLDateTime(Utility.GetText(node["created"], null), DateTime.UtcNow);
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
namespace Server.Accounting
|
||||
{
|
||||
public enum PasswordProtectionAlgorithm
|
||||
{
|
||||
PBKDF2
|
||||
}
|
||||
|
||||
public static class AccountSecurity
|
||||
{
|
||||
// TODO: Put it in a configuration
|
||||
public const PasswordProtectionAlgorithm AlgorithmName = PasswordProtectionAlgorithm.PBKDF2;
|
||||
|
||||
public static readonly IPasswordProtection CurrentPasswordProtection = GetPasswordProtection(AlgorithmName);
|
||||
|
||||
public static IPasswordProtection GetPasswordProtection(PasswordProtectionAlgorithm algorithm)
|
||||
{
|
||||
var passwordProtection = algorithm switch
|
||||
{
|
||||
PasswordProtectionAlgorithm.PBKDF2 => PBKDF2PasswordProtection.Instance,
|
||||
_ => null
|
||||
};
|
||||
|
||||
return passwordProtection;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
Projects/Scripts/Accounting/Security/AccountSecurity.cs
Normal file
45
Projects/Scripts/Accounting/Security/AccountSecurity.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
public enum PasswordProtectionAlgorithm
|
||||
{
|
||||
// Obsolete algorithms. These are not secure!
|
||||
// They are included for password upgrades only.
|
||||
None,
|
||||
MD5,
|
||||
SHA1,
|
||||
|
||||
// Support algorithms
|
||||
PBKDF2,
|
||||
Argon2 // Recommended algorithm for real security.
|
||||
}
|
||||
|
||||
public static class AccountSecurity
|
||||
{
|
||||
// TODO: Put it in a configuration
|
||||
public const PasswordProtectionAlgorithm AlgorithmName = PasswordProtectionAlgorithm.Argon2;
|
||||
|
||||
public static readonly IPasswordProtection CurrentPasswordProtection = GetPasswordProtection(AlgorithmName);
|
||||
|
||||
public static void Configure()
|
||||
{
|
||||
if (AlgorithmName < PasswordProtectionAlgorithm.PBKDF2)
|
||||
throw new Exception($"Security: {AlgorithmName} is obselete and not secure. Do not use it.");
|
||||
}
|
||||
|
||||
public static IPasswordProtection GetPasswordProtection(PasswordProtectionAlgorithm algorithm)
|
||||
{
|
||||
var passwordProtection = algorithm switch
|
||||
{
|
||||
PasswordProtectionAlgorithm.MD5 => MD5PasswordProtection.Instance,
|
||||
PasswordProtectionAlgorithm.SHA1 => SHA1PasswordProtection.Instance,
|
||||
PasswordProtectionAlgorithm.PBKDF2 => PBKDF2PasswordProtection.Instance,
|
||||
PasswordProtectionAlgorithm.Argon2 => Argon2PasswordProtection.Instance,
|
||||
_ => null
|
||||
};
|
||||
|
||||
return passwordProtection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
namespace Server.Accounting.Security
|
||||
{
|
||||
public class Argon2PasswordProtection : IPasswordProtection
|
||||
{
|
||||
public static IPasswordProtection Instance = new Argon2PasswordProtection();
|
||||
private Argon2PasswordHasher m_PasswordHasher = new Argon2PasswordHasher();
|
||||
|
||||
public string EncryptPassword(string plainPassword) =>
|
||||
m_PasswordHasher.Hash(plainPassword);
|
||||
|
||||
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
||||
m_PasswordHasher.Verify(encryptedPassword, plainPassword);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
public class MD5PasswordProtection : IPasswordProtection
|
||||
{
|
||||
public static IPasswordProtection Instance = new MD5PasswordProtection();
|
||||
private MD5CryptoServiceProvider m_MD5HashProvider = new MD5CryptoServiceProvider();
|
||||
|
||||
public string EncryptPassword(string plainPassword)
|
||||
{
|
||||
ReadOnlySpan<char> password = plainPassword.AsSpan(0, Math.Min(256, plainPassword.Length));
|
||||
byte[] bytes = new byte[Encoding.ASCII.GetByteCount(password)];
|
||||
Encoding.ASCII.GetBytes(password, bytes);
|
||||
|
||||
return BitConverter.ToString(m_MD5HashProvider.ComputeHash(bytes));
|
||||
}
|
||||
|
||||
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
||||
EncryptPassword(plainPassword) == encryptedPassword;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,11 +3,11 @@ using System.Buffers.Binary;
|
|||
using System.Security.Cryptography;
|
||||
using Server.Misc;
|
||||
|
||||
namespace Server.Accounting
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
public class PBKDF2PasswordProtection : IPasswordProtection
|
||||
{
|
||||
public static PBKDF2PasswordProtection Instance = new PBKDF2PasswordProtection();
|
||||
public static IPasswordProtection Instance = new PBKDF2PasswordProtection();
|
||||
|
||||
private const ushort m_MinIterations = 1024;
|
||||
private const ushort m_MaxIterations = 1536;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Accounting.Security
|
||||
{
|
||||
public class SHA1PasswordProtection : IPasswordProtection
|
||||
{
|
||||
public static IPasswordProtection Instance = new SHA1PasswordProtection();
|
||||
private SHA1CryptoServiceProvider m_SHA1HashProvider = new SHA1CryptoServiceProvider();
|
||||
|
||||
public string EncryptPassword(string plainPassword)
|
||||
{
|
||||
ReadOnlySpan<char> password = plainPassword.AsSpan(0, Math.Min(256, plainPassword.Length));
|
||||
byte[] bytes = new byte[Encoding.ASCII.GetByteCount(password)];
|
||||
Encoding.ASCII.GetBytes(password, bytes);
|
||||
|
||||
return BitConverter.ToString(m_SHA1HashProvider.ComputeHash(bytes));
|
||||
}
|
||||
|
||||
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
||||
EncryptPassword(plainPassword) == encryptedPassword;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,8 @@
|
|||
<PublishDir>$(SolutionDir)\Distribution\Assemblies</PublishDir>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Configurations>Debug;Release;Analyze</Configurations>
|
||||
<DefineConstants Condition="'$(RuntimeIdentifier)' == 'win-x64'">WINDOWS</DefineConstants>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
<Target Name="CleanPub" AfterTargets="Clean">
|
||||
<Message Text="Removing distribution assemblies..." />
|
||||
|
|
@ -38,14 +40,14 @@
|
|||
<Delete Files="$(SolutionDir)\Distribution\Assemblies\$(AssemblyName).pdb" ContinueOnError="true" />
|
||||
<Delete Files="$(SolutionDir)\Distribution\Assemblies\System.IO.Pipelines.dll" ContinueOnError="true" />
|
||||
</Target>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DefineConstants>TRACE;DEBUG;$(DefineConstants)</DefineConstants>
|
||||
<Optimize>false</Optimize>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Optimize>true</Optimize>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Analyze|AnyCPU'">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Analyze|x64'">
|
||||
<Optimize>true</Optimize>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
<RunAnalyzersDuringBuild>true</RunAnalyzersDuringBuild>
|
||||
|
|
@ -64,6 +66,7 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="3.1.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.3" />
|
||||
<PackageReference Include="Argon2.Bindings" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Analyze|AnyCPU'">
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
|
||||
|
|
@ -74,4 +77,21 @@
|
|||
</PackageReference>
|
||||
<AdditionalFiles Include="$(SolutionDir)\Rules.ruleset" Link="Rules.rulest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Analyze|x64'">
|
||||
<PackageReference Include="StyleCop.Analyzers">
|
||||
<Version>1.1.118</Version>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<AdditionalFiles Include="$(SolutionDir)\stylecop.json">
|
||||
<Link>stylecop.json</Link>
|
||||
</AdditionalFiles>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers">
|
||||
<Version>2.9.8</Version>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<AdditionalFiles Include="$(SolutionDir)\Rules.ruleset">
|
||||
<Link>Rules.rulest</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the MIT license.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<Configuration>Release</Configuration>
|
||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<Configuration>Release</Configuration>
|
||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||
<SelfContained>false</SelfContained>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<Configuration>Release</Configuration>
|
||||
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<Configuration>Release</Configuration>
|
||||
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
||||
<SelfContained>false</SelfContained>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<Configuration>Release</Configuration>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<Configuration>Release</Configuration>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<SelfContained>false</SelfContained>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
<StartupObject>Server.Core</StartupObject>
|
||||
<AssemblyName>ModernUO</AssemblyName>
|
||||
<Win32Resource />
|
||||
<Version>0.3.0</Version>
|
||||
<Version>0.3.1</Version>
|
||||
<Authors>Kamron Batman</Authors>
|
||||
<Company>ModernUO</Company>
|
||||
<Product>ModernUO Server</Product>
|
||||
|
|
@ -17,13 +17,14 @@
|
|||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<PublishDir>$(SolutionDir)\Distribution</PublishDir>
|
||||
<OutDir>$(SolutionDir)\Distribution</OutDir>
|
||||
<OutputPath>$(SolutionDir)\Distribution</OutputPath>
|
||||
<!-- <OutDir>$(SolutionDir)\Distribution</OutDir>
|
||||
<OutputPath>$(SolutionDir)\Distribution</OutputPath> -->
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||
<Configurations>Debug;Release;Analyze</Configurations>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
<Target Name="CleanPub" AfterTargets="Clean">
|
||||
<Message Text="Removing distribution files..." />
|
||||
|
|
@ -48,14 +49,14 @@
|
|||
<Delete Files="$(SolutionDir)\Distribution\$(AssemblyName).runtimeconfig.json" ContinueOnError="true" />
|
||||
<Delete Files="$(SolutionDir)\Distribution\System.IO.Pipelines.dll" ContinueOnError="true" />
|
||||
</Target>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<Optimize>false</Optimize>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Optimize>true</Optimize>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Analyze|AnyCPU'">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Analyze|x64'">
|
||||
<Optimize>true</Optimize>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
<RunAnalyzersDuringBuild>true</RunAnalyzersDuringBuild>
|
||||
|
|
@ -86,13 +87,21 @@
|
|||
<ItemGroup>
|
||||
<None Remove="Kestrel\Transport.Libuv\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Analyze|AnyCPU'">
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
|
||||
<AdditionalFiles Include="$(SolutionDir)\stylecop.json" Link="stylecop.json" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8">
|
||||
<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Analyze|x64'">
|
||||
<PackageReference Include="StyleCop.Analyzers">
|
||||
<Version>1.1.118</Version>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<AdditionalFiles Include="$(SolutionDir)\stylecop.json">
|
||||
<Link>stylecop.json</Link>
|
||||
</AdditionalFiles>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers">
|
||||
<Version>2.9.8</Version>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<AdditionalFiles Include="$(SolutionDir)\Rules.ruleset" Link="Rules.rulest" />
|
||||
<AdditionalFiles Include="$(SolutionDir)\Rules.ruleset">
|
||||
<Link>Rules.rulest</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -580,6 +580,8 @@ consider it more useful to permit linking proprietary applications with the
|
|||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
|
||||
License notice for BufferReader/BufferWrite
|
||||
---------------------------
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Harry Pierson
|
||||
|
|
@ -601,3 +603,27 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
License notice for csharp-argon-2
|
||||
---------------------------
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Kevin Spinar (Alipha)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
rm -rf Projects/*/obj
|
||||
rm -rf Projects/*/bin
|
||||
|
||||
rm -f Distribution/Assemblies/BouncyCastle.Crypto.dll
|
||||
rm -f Distribution/Assemblies/MailKit.dll
|
||||
|
|
@ -12,10 +13,15 @@ rm -f Distribution/Assemblies/Microsoft.Extensions.Logging.Abstractions.dll
|
|||
rm -f Distribution/Assemblies/Microsoft.Extensions.Primitives.dll
|
||||
rm -f Distribution/Assemblies/MimeKit.dll
|
||||
rm -f Distribution/Assemblies/System.IO.Pipelines.dll
|
||||
rm -f Distribution/Assemblies/Argon2.Bindings.dll
|
||||
rm -f Distribution/Assemblies/libargon2.so
|
||||
rm -f Distribution/Assemblies/libargon2.dylib
|
||||
rm -f Distribution/Assemblies/argon2.dll
|
||||
|
||||
rm -f Distribution/libdrng.dll
|
||||
rm -f Distribution/libuv.dll
|
||||
rm -f Distribution/libuv.so
|
||||
rm -f Distribution/libuv.dylib
|
||||
rm -f Distribution/Microsoft.AspNetCore.Connections.Abstractions.dll
|
||||
rm -f Distribution/Microsoft.AspNetCore.Http.Features.dll
|
||||
rm -f Distribution/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.dll
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Debug /p:PublishProfile=Linux
|
||||
dotnet build -c Debug -r linux-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Debug -r linux-x64 --self-contained=false
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Debug /p:PublishProfile=Linux
|
||||
dotnet build -c Debug -r linux-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Debug -r linux-x64 --self-contained=false
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Release /p:PublishProfile=Linux
|
||||
dotnet build -c Release -r linux-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Release -r linux-x64 --self-contained=false
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Release /p:PublishProfile=Linux
|
||||
dotnet build -c Release -r linux-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Release -r linux-x64 --self-contained=false
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Debug /p:PublishProfile=OSX
|
||||
dotnet build -c Debug -r osx-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Debug -r osx-x64 --self-contained=false
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Debug /p:PublishProfile=OSX
|
||||
dotnet build -c Debug -r osx-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Debug -r osx-x64 --self-contained=false
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Release /p:PublishProfile=OSX
|
||||
dotnet build -c Release -r osx-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Release -r osx-x64 --self-contained=false
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Release /p:PublishProfile=OSX
|
||||
dotnet build -c Release -r osx-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Release -r osx-x64 --self-contained=false
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Debug /p:PublishProfile=Windows
|
||||
dotnet build -c Debug -r win-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Debug -r win-x64 --self-contained=false
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Debug /p:PublishProfile=Windows
|
||||
dotnet build -c Debug -r win-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Debug -r win-x64 --self-contained=false
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Release /p:PublishProfile=Windows
|
||||
dotnet build -c Release -r win-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Release -r win-x64 --self-contained=false
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
dotnet publish -c Release /p:PublishProfile=Windows
|
||||
dotnet build -c Release -r win-x64 Projects/Argon2/Argon2.csproj
|
||||
dotnet publish -c Release -r win-x64 --self-contained=false
|
||||
|
|
|
|||
0
packages/do_not_delete
Normal file
0
packages/do_not_delete
Normal file
Loading…
Add table
Add a link
Reference in a new issue