Separate cryptography project to server and client to reduce client WASM size (#185)

This commit is contained in:
Leendert de Borst
2024-09-01 13:52:53 +02:00
parent 5ecdf926b6
commit 4373e6fa62
27 changed files with 137 additions and 79 deletions

View File

@@ -11,8 +11,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FaviconExtractor", "src\Uti
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AliasVault.UnitTests", "src\Tests\AliasVault.UnitTests\AliasVault.UnitTests.csproj", "{8E6A418A-B305-465D-857D-49953605C18E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cryptography", "src\Utilities\Cryptography\Cryptography.csproj", "{427EA8E2-EA76-467E-A6BC-201EFE40C0D0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AliasVault.Api", "src\AliasVault.Api\AliasVault.Api.csproj", "{B797C533-260E-4DA2-83B1-0EE4BCFE08DB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AliasVault.Client", "src\AliasVault.Client\AliasVault.Client.csproj", "{25248E01-5A4B-4F95-A63C-BEA01499A1C2}"
@@ -55,6 +53,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TotpGenerator", "src\Utilit
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AliasVault.AuthLogging", "src\Utilities\AliasVault.AuthLogging\AliasVault.AuthLogging.csproj", "{DA175274-0FF7-4436-9266-742F96C2D1ED}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cryptography", "Cryptography", "{BB7E701E-B1C6-453E-800A-E12CE256318D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cryptography.Server", "src\Utilities\Cryptography\Cryptography.Server\Cryptography.Server.csproj", "{341EC443-0B6B-4E8C-AF46-D6156573CEA5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cryptography.Client", "src\Utilities\Cryptography\Cryptography.Client\Cryptography.Client.csproj", "{542C7B7D-C2B4-4AE3-9B2C-C62FCF4DFF8E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -73,10 +77,6 @@ Global
{8E6A418A-B305-465D-857D-49953605C18E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E6A418A-B305-465D-857D-49953605C18E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E6A418A-B305-465D-857D-49953605C18E}.Release|Any CPU.Build.0 = Release|Any CPU
{427EA8E2-EA76-467E-A6BC-201EFE40C0D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{427EA8E2-EA76-467E-A6BC-201EFE40C0D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{427EA8E2-EA76-467E-A6BC-201EFE40C0D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{427EA8E2-EA76-467E-A6BC-201EFE40C0D0}.Release|Any CPU.Build.0 = Release|Any CPU
{B797C533-260E-4DA2-83B1-0EE4BCFE08DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B797C533-260E-4DA2-83B1-0EE4BCFE08DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B797C533-260E-4DA2-83B1-0EE4BCFE08DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -145,6 +145,14 @@ Global
{DA175274-0FF7-4436-9266-742F96C2D1ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DA175274-0FF7-4436-9266-742F96C2D1ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DA175274-0FF7-4436-9266-742F96C2D1ED}.Release|Any CPU.Build.0 = Release|Any CPU
{341EC443-0B6B-4E8C-AF46-D6156573CEA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{341EC443-0B6B-4E8C-AF46-D6156573CEA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{341EC443-0B6B-4E8C-AF46-D6156573CEA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{341EC443-0B6B-4E8C-AF46-D6156573CEA5}.Release|Any CPU.Build.0 = Release|Any CPU
{542C7B7D-C2B4-4AE3-9B2C-C62FCF4DFF8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{542C7B7D-C2B4-4AE3-9B2C-C62FCF4DFF8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{542C7B7D-C2B4-4AE3-9B2C-C62FCF4DFF8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{542C7B7D-C2B4-4AE3-9B2C-C62FCF4DFF8E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -152,7 +160,6 @@ Global
GlobalSection(NestedProjects) = preSolution
{ED328644-A152-403D-86EB-81201AA07744} = {01AB9389-2F89-4F8E-A688-BF4BF1FC42C8}
{8E6A418A-B305-465D-857D-49953605C18E} = {29DE523D-EEF2-41E9-AC12-F20D8D02BEBB}
{427EA8E2-EA76-467E-A6BC-201EFE40C0D0} = {01AB9389-2F89-4F8E-A688-BF4BF1FC42C8}
{AF013D08-1BF6-4E23-87D2-37F614BE7952} = {29DE523D-EEF2-41E9-AC12-F20D8D02BEBB}
{1277105D-50CD-4CE0-9C2C-549F46867E54} = {5F7417F6-4388-49CC-9511-ED63C4A6488A}
{FE10F294-817F-477E-A24F-8597A15AF0B5} = {5F7417F6-4388-49CC-9511-ED63C4A6488A}
@@ -167,6 +174,9 @@ Global
{951C3DF8-DF22-4B2B-839F-FBA26DDD8ABD} = {01AB9389-2F89-4F8E-A688-BF4BF1FC42C8}
{E8D9C551-67D2-4651-8EDF-4262DF7375CE} = {01AB9389-2F89-4F8E-A688-BF4BF1FC42C8}
{DA175274-0FF7-4436-9266-742F96C2D1ED} = {01AB9389-2F89-4F8E-A688-BF4BF1FC42C8}
{BB7E701E-B1C6-453E-800A-E12CE256318D} = {01AB9389-2F89-4F8E-A688-BF4BF1FC42C8}
{341EC443-0B6B-4E8C-AF46-D6156573CEA5} = {BB7E701E-B1C6-453E-800A-E12CE256318D}
{542C7B7D-C2B4-4AE3-9B2C-C62FCF4DFF8E} = {BB7E701E-B1C6-453E-800A-E12CE256318D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FEE82475-C009-4762-8113-A6563D9DC49E}

View File

@@ -46,6 +46,6 @@
<ProjectReference Include="..\Utilities\AliasVault.AuthLogging\AliasVault.AuthLogging.csproj" />
<ProjectReference Include="..\Utilities\AliasVault.Logging\AliasVault.Logging.csproj" />
<ProjectReference Include="..\Utilities\AliasVault.RazorComponents\AliasVault.RazorComponents.csproj" />
<ProjectReference Include="..\Utilities\Cryptography\Cryptography.csproj" />
<ProjectReference Include="..\Utilities\Cryptography\Cryptography.Server\Cryptography.Server.csproj" />
</ItemGroup>
</Project>

View File

@@ -5,7 +5,6 @@
// </copyright>
//-----------------------------------------------------------------------
using System.Data.Common;
using System.Globalization;
using System.Reflection;
using AliasServerDb;
@@ -16,10 +15,9 @@ using AliasVault.Admin.Main;
using AliasVault.Admin.Services;
using AliasVault.AuthLogging;
using AliasVault.Logging;
using Cryptography;
using Cryptography.Server;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);

View File

@@ -37,7 +37,8 @@
<ProjectReference Include="..\Databases\AliasServerDb\AliasServerDb.csproj" />
<ProjectReference Include="..\Utilities\AliasVault.AuthLogging\AliasVault.AuthLogging.csproj" />
<ProjectReference Include="..\Utilities\AliasVault.Logging\AliasVault.Logging.csproj" />
<ProjectReference Include="..\Utilities\Cryptography\Cryptography.csproj" />
<ProjectReference Include="..\Utilities\Cryptography\Cryptography.Client\Cryptography.Client.csproj" />
<ProjectReference Include="..\Utilities\Cryptography\Cryptography.Server\Cryptography.Server.csproj" />
<ProjectReference Include="..\Utilities\FaviconExtractor\FaviconExtractor.csproj" />
</ItemGroup>

View File

@@ -18,7 +18,8 @@ using AliasVault.Shared.Models.WebApi;
using AliasVault.Shared.Models.WebApi.Auth;
using AliasVault.Shared.Providers.Time;
using Asp.Versioning;
using Cryptography.Models;
using Cryptography.Client;
using Cryptography.Client.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
@@ -84,7 +85,7 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
}
// Server creates ephemeral and sends to client
var ephemeral = Cryptography.Srp.GenerateEphemeralServer(user.Verifier);
var ephemeral = Srp.GenerateEphemeralServer(user.Verifier);
// Store the server ephemeral in memory cache for Validate() endpoint to use.
cache.Set(model.Username, ephemeral.Secret, TimeSpan.FromMinutes(5));
@@ -461,7 +462,7 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
return null;
}
var serverSession = Cryptography.Srp.DeriveSessionServer(
var serverSession = Srp.DeriveSessionServer(
serverSecretEphemeral.ToString() ?? string.Empty,
clientEphemeral,
user.Salt,

View File

@@ -14,10 +14,9 @@ using AliasVault.AuthLogging;
using AliasVault.Logging;
using AliasVault.Shared.Providers.Time;
using Asp.Versioning;
using Cryptography;
using Cryptography.Server;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;

View File

@@ -77,7 +77,7 @@
<ProjectReference Include="..\AliasGenerators\AliasGenerators.csproj" />
<ProjectReference Include="..\AliasVault.Shared\AliasVault.Shared.csproj" />
<ProjectReference Include="..\Utilities\AliasVault.RazorComponents\AliasVault.RazorComponents.csproj" />
<ProjectReference Include="..\Utilities\Cryptography\Cryptography.csproj" />
<ProjectReference Include="..\Utilities\Cryptography\Cryptography.Client\Cryptography.Client.csproj" />
<ProjectReference Include="..\Utilities\CsvImportExport\CsvImportExport.csproj" />
<ProjectReference Include="..\Utilities\FaviconExtractor\FaviconExtractor.csproj" />
</ItemGroup>

View File

@@ -5,7 +5,7 @@
@using System.Text.Json
@using AliasVault.Shared.Models.WebApi.Auth
@using AliasVault.Client.Auth.Components
@using Cryptography
@using Cryptography.Client
@using SecureRemotePassword
@if (ShowTwoFactorAuthStep)

View File

@@ -9,7 +9,7 @@
@using AliasVault.Shared.Models.WebApi.Auth
@using AliasVault.Client.Auth.Components
@using AliasVault.Client.Auth.Pages.Base
@using Cryptography
@using Cryptography.Client
@using SecureRemotePassword
<h2 class="text-2xl font-bold text-gray-900 dark:text-white">
@@ -71,7 +71,7 @@
byte[] passwordHash = await Encryption.DeriveKeyFromPasswordAsync(RegisterModel.Password, salt);
var passwordHashString = BitConverter.ToString(passwordHash).Replace("-", string.Empty);
var srpSignup = Cryptography.Srp.SignupPrepareAsync(client, salt, RegisterModel.Username, passwordHashString);
var srpSignup = Srp.SignupPrepareAsync(client, salt, RegisterModel.Username, passwordHashString);
var result = await Http.PostAsJsonAsync("api/v1/Auth/register", srpSignup);
var responseContent = await result.Content.ReadAsStringAsync();

View File

@@ -2,10 +2,9 @@
@inherits AliasVault.Client.Auth.Pages.Base.LoginBase
@layout Auth.Layout.MainLayout
@using System.Text.Json
@using AliasVault.Shared.Models
@using AliasVault.Client.Auth.Components
@using AliasVault.Shared.Models.WebApi.Auth
@using Cryptography
@using Cryptography.Client
<div class="flex space-x-4">
<img class="w-8 h-8 rounded-full" src="/img/avatar.webp" alt="Bonnie image">

View File

@@ -104,10 +104,10 @@
window.addEventListener('load', manageLoadingScreen);
</script>
<script src="lib/qrcode.min.js?v=@CacheBuster"></script>
<script src="js/crypto.js?v=@CacheBuster"></script>
<script src="js/utilities.js?v=@CacheBuster"></script>
<script src="_framework/blazor.webassembly.js?v=@CacheBuster"></script>
<script src="js/crypto.js?v=@CacheBuster" async></script>
<script src="js/utilities.js?v=@CacheBuster" async></script>
<script src="_framework/blazor.webassembly.js?v=@CacheBuster" async></script>
<script src="lib/qrcode.min.js?v=@CacheBuster" defer></script>
</body>
</html>

View File

@@ -38,6 +38,6 @@
<ItemGroup>
<ProjectReference Include="..\..\Databases\AliasServerDb\AliasServerDb.csproj" />
<ProjectReference Include="..\..\Utilities\AliasVault.Logging\AliasVault.Logging.csproj" />
<ProjectReference Include="..\..\Utilities\Cryptography\Cryptography.csproj" />
<ProjectReference Include="..\..\Utilities\Cryptography\Cryptography.Server\Cryptography.Server.csproj" />
</ItemGroup>
</Project>

View File

@@ -11,7 +11,7 @@ using System.Buffers;
using System.Net.Mail;
using System.Text.RegularExpressions;
using AliasServerDb;
using Cryptography;
using Cryptography.Server;
using Microsoft.EntityFrameworkCore;
using MimeKit;
using NUglify;

View File

@@ -44,6 +44,7 @@
<ItemGroup>
<ProjectReference Include="..\..\Services\AliasVault.SmtpService\AliasVault.SmtpService.csproj" />
<ProjectReference Include="..\..\Utilities\Cryptography\Cryptography.Server\Cryptography.Server.csproj" />
</ItemGroup>
</Project>

View File

@@ -9,7 +9,7 @@ namespace AliasVault.IntegrationTests.SmtpServer;
using System.Text;
using AliasServerDb;
using Cryptography;
using Cryptography.Server;
using MailKit.Net.Smtp;
using MailKit.Security;
using Microsoft.EntityFrameworkCore;

View File

@@ -52,7 +52,8 @@
<ProjectReference Include="..\..\AliasVault.Api\AliasVault.Api.csproj" />
<ProjectReference Include="..\..\Databases\AliasClientDb\AliasClientDb.csproj" />
<ProjectReference Include="..\..\Databases\AliasServerDb\AliasServerDb.csproj" />
<ProjectReference Include="..\..\Utilities\Cryptography\Cryptography.csproj" />
<ProjectReference Include="..\..\Utilities\Cryptography\Cryptography.Client\Cryptography.Client.csproj" />
<ProjectReference Include="..\..\Utilities\Cryptography\Cryptography.Server\Cryptography.Server.csproj" />
<ProjectReference Include="..\..\Utilities\CsvImportExport\CsvImportExport.csproj" />
<ProjectReference Include="..\..\Utilities\FaviconExtractor\FaviconExtractor.csproj" />
<ProjectReference Include="..\..\Utilities\TotpGenerator\TotpGenerator.csproj" />

View File

@@ -8,7 +8,7 @@
namespace AliasVault.Tests.Utilities;
using System.Text.Json;
using Cryptography;
using Cryptography.Server;
/// <summary>
/// Tests for the SrpArgonEncryption class.

View File

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DocumentationFile>bin\Debug\net8.0\CryptographyClient.xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DocumentationFile>bin\Release\net8.0\CryptographyClient.xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\..\stylecop.json">
<Link>stylecop.json</Link>
</AdditionalFiles>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.1" />
<PackageReference Include="srp" Version="1.0.7" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,39 @@
//-----------------------------------------------------------------------
// <copyright file="Encryption.cs" company="lanedirt">
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace Cryptography.Client;
using System.Text;
using Konscious.Security.Cryptography;
/// <summary>
/// RSA/AES and Argon2id encryption methods.
/// </summary>
public static class Encryption
{
/// <summary>
/// Derive a key used for encryption/decryption based on a user password and system salt.
/// </summary>
/// <param name="password">User password.</param>
/// <param name="salt">The salt to use for the Argon2id hash.</param>
/// <returns>SrpArgonEncryption key as byte array.</returns>
public static async Task<byte[]> DeriveKeyFromPasswordAsync(string password, string salt)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
var argon2 = new Argon2id(passwordBytes)
{
Salt = saltBytes,
DegreeOfParallelism = 4,
MemorySize = 8192,
Iterations = 1,
};
return await argon2.GetBytesAsync(32); // Generate a 256-bit key
}
}

View File

@@ -5,7 +5,7 @@
// </copyright>
//-----------------------------------------------------------------------
namespace Cryptography.Models;
namespace Cryptography.Client.Models;
/// <summary>
/// Represents the data required for signing up with the Secure Remote Password (SRP) protocol.

View File

@@ -5,9 +5,9 @@
// </copyright>
//-----------------------------------------------------------------------
namespace Cryptography;
namespace Cryptography.Client;
using Cryptography.Models;
using Cryptography.Client.Models;
using SecureRemotePassword;
/// <summary>

View File

@@ -5,7 +5,7 @@
// </copyright>
//-----------------------------------------------------------------------
namespace Cryptography;
namespace Cryptography.Server;
using System;
using System.IO;

View File

@@ -17,13 +17,11 @@
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" />
<AdditionalFiles Include="..\..\..\stylecop.json" Link="stylecop.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.NetCore" Version="2.2.1" />
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.1" />
<PackageReference Include="srp" Version="1.0.7" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -31,7 +29,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Databases\AliasServerDb\AliasServerDb.csproj" />
<ProjectReference Include="..\..\..\Databases\AliasServerDb\AliasServerDb.csproj" />
</ItemGroup>
</Project>

View File

@@ -5,7 +5,7 @@
// </copyright>
//-----------------------------------------------------------------------
namespace Cryptography;
namespace Cryptography.Server;
using System.Security.Cryptography.X509Certificates;
using AliasServerDb;

View File

@@ -5,7 +5,7 @@
// </copyright>
//-----------------------------------------------------------------------
namespace Cryptography;
namespace Cryptography.Server;
using AliasServerDb;

View File

@@ -5,12 +5,11 @@
// </copyright>
//-----------------------------------------------------------------------
namespace Cryptography;
namespace Cryptography.Server;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using Konscious.Security.Cryptography;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
@@ -68,28 +67,6 @@ public static class Encryption
}
}
/// <summary>
/// Derive a key used for encryption/decryption based on a user password and system salt.
/// </summary>
/// <param name="password">User password.</param>
/// <param name="salt">The salt to use for the Argon2id hash.</param>
/// <returns>SrpArgonEncryption key as byte array.</returns>
public static async Task<byte[]> DeriveKeyFromPasswordAsync(string password, string salt)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
var argon2 = new Argon2id(passwordBytes)
{
Salt = saltBytes,
DegreeOfParallelism = 4,
MemorySize = 8192,
Iterations = 1,
};
return await argon2.GetBytesAsync(32); // Generate a 256-bit key
}
/// <summary>
/// SymmetricEncrypt a plaintext string using AES-256 GCM.
/// </summary>