wip
This commit is contained in:
@@ -54,12 +54,17 @@ public partial class App : Application
|
|||||||
{
|
{
|
||||||
args.AddServices(services =>
|
args.AddServices(services =>
|
||||||
{
|
{
|
||||||
|
services.AddTransient<IKeyGenerator, KeyGenerator>();
|
||||||
services.AddTransient<IEncryptor, AesEncryptor>();
|
services.AddTransient<IEncryptor, AesEncryptor>();
|
||||||
services.AddTransient<IDecryptor, AesDecryptor>();
|
services.AddTransient<IDecryptor, AesDecryptor>();
|
||||||
|
|
||||||
services.AddTransient<IPasswordHasher, PasswordHasher>();
|
services.AddTransient<IPasswordHasher, PasswordHasher>();
|
||||||
services.AddTransient<IKeyDeriver, KeyDeriver>();
|
services.AddTransient<IKeyDeriver, KeyDeriver>();
|
||||||
|
|
||||||
|
services.AddTransient<IVaultFactory, VaultFactory>();
|
||||||
|
services.AddTransient<IVaultKeyGenerator, VaultKeyGenerator>();
|
||||||
|
services.AddTransient<IVaultStorage, VaultStorage>();
|
||||||
|
|
||||||
services.AddDbContextFactory<VaultDbContext>(args =>
|
services.AddDbContextFactory<VaultDbContext>(args =>
|
||||||
{
|
{
|
||||||
args.UseSqlite();
|
args.UseSqlite();
|
||||||
@@ -69,9 +74,6 @@ public partial class App : Application
|
|||||||
|
|
||||||
services.AddHandler<OpenVaultHandler>();
|
services.AddHandler<OpenVaultHandler>();
|
||||||
|
|
||||||
services.AddHandler<CreateVaultStorageHandler>();
|
|
||||||
services.AddHandler<OpenVaultStorageHandler>();
|
|
||||||
|
|
||||||
services.AddTemplate<VaultNavigationViewModel, VaultNavigationView>();
|
services.AddTemplate<VaultNavigationViewModel, VaultNavigationView>();
|
||||||
services.AddTemplate<AllNavigationViewModel, AllNavigationView>();
|
services.AddTemplate<AllNavigationViewModel, AllNavigationView>();
|
||||||
services.AddTemplate<StarredNavigationViewModel, StarredNavigationView>();
|
services.AddTemplate<StarredNavigationViewModel, StarredNavigationView>();
|
||||||
@@ -83,13 +85,13 @@ public partial class App : Application
|
|||||||
});
|
});
|
||||||
})!);
|
})!);
|
||||||
|
|
||||||
services.AddSingleton<IVaultHostCollection, VaultHostCollection>();
|
services.AddTransient<IVaultComponentFactory, VaultComponentFactory>();
|
||||||
services.AddHandler<CreateVaultHandler>();
|
services.AddHandler<CreateVaultHandler>();
|
||||||
|
|
||||||
|
services.AddSingleton<IVaultHostCollection, VaultHostCollection>();
|
||||||
services.AddInitializer<VaultCollectionInitializer>();
|
services.AddInitializer<VaultCollectionInitializer>();
|
||||||
|
|
||||||
services.AddTemplate<MainViewModel, MainView>("Main");
|
services.AddTemplate<MainViewModel, MainView>("Main");
|
||||||
|
|
||||||
services.AddHandler<VaultNavigationViewModelHandler>();
|
services.AddHandler<VaultNavigationViewModelHandler>();
|
||||||
services.AddTransient<FooterViewModel>();
|
services.AddTransient<FooterViewModel>();
|
||||||
|
|
||||||
|
|||||||
+13
-14
@@ -7,23 +7,22 @@ public class AesDecryptor :
|
|||||||
{
|
{
|
||||||
private const int IvSize = 16;
|
private const int IvSize = 16;
|
||||||
|
|
||||||
public string Decrypt(string cipherText, byte[] key)
|
public byte[] Decrypt(byte[] cipher, byte[] key)
|
||||||
{
|
{
|
||||||
byte[] cipherData = Convert.FromBase64String(cipherText);
|
Span<byte> iv = cipher.AsSpan(0, IvSize);
|
||||||
|
ReadOnlySpan<byte> encryptedContent = cipher.AsSpan(IvSize);
|
||||||
|
|
||||||
byte[] iv = new byte[IvSize];
|
using Aes aes = Aes.Create();
|
||||||
Array.Copy(cipherData, 0, iv, 0, IvSize); // Extract the IV from the start of the cipher data
|
|
||||||
|
|
||||||
using var aes = Aes.Create();
|
|
||||||
aes.Key = key;
|
aes.Key = key;
|
||||||
aes.IV = iv;
|
aes.IV = iv.ToArray();
|
||||||
|
|
||||||
using var memoryStream = new MemoryStream(cipherData, IvSize, cipherData.Length - IvSize);
|
using MemoryStream memoryStream = new(encryptedContent.ToArray());
|
||||||
using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
|
using ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
|
||||||
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
|
using CryptoStream cryptoStream = new(memoryStream, decryptor, CryptoStreamMode.Read);
|
||||||
using (var streamReader = new StreamReader(cryptoStream))
|
|
||||||
{
|
using MemoryStream resultStream = new();
|
||||||
return streamReader.ReadToEnd(); // Return the decrypted text
|
cryptoStream.CopyTo(resultStream);
|
||||||
}
|
|
||||||
|
return resultStream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-14
@@ -2,28 +2,33 @@
|
|||||||
|
|
||||||
namespace Bitvault;
|
namespace Bitvault;
|
||||||
|
|
||||||
public class AesEncryptor : IEncryptor
|
public class AesEncryptor :
|
||||||
|
IEncryptor
|
||||||
{
|
{
|
||||||
public string Encrypt(string plainText, byte[] key)
|
private const int IvSize = 16;
|
||||||
{
|
|
||||||
const int IvSize = 16;
|
|
||||||
|
|
||||||
using var aes = Aes.Create();
|
public byte[] Encrypt(byte[] data,
|
||||||
|
byte[] key)
|
||||||
|
{
|
||||||
|
if (key.Length != 32)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Key must be 256 bits (32 bytes).");
|
||||||
|
}
|
||||||
|
|
||||||
|
using Aes aes = Aes.Create();
|
||||||
aes.Key = key;
|
aes.Key = key;
|
||||||
aes.GenerateIV();
|
aes.GenerateIV();
|
||||||
|
|
||||||
byte[] iv = aes.IV;
|
using MemoryStream memoryStream = new();
|
||||||
|
memoryStream.Write(aes.IV.AsSpan(0, IvSize));
|
||||||
|
|
||||||
using var memoryStream = new MemoryStream();
|
using (ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
|
||||||
memoryStream.Write(iv, 0, IvSize); // Store IV at the start of the stream
|
using (CryptoStream cryptoStream = new(memoryStream, encryptor, CryptoStreamMode.Write))
|
||||||
|
|
||||||
using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
|
|
||||||
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
|
|
||||||
using (var streamWriter = new StreamWriter(cryptoStream))
|
|
||||||
{
|
{
|
||||||
streamWriter.Write(plainText);
|
cryptoStream.Write(data, 0, data.Length);
|
||||||
|
cryptoStream.FlushFinalBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Convert.ToBase64String(memoryStream.ToArray()); // Return the encrypted data in base64
|
return memoryStream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,30 +3,23 @@ using Toolkit.Foundation;
|
|||||||
|
|
||||||
namespace Bitvault;
|
namespace Bitvault;
|
||||||
|
|
||||||
public class CreateVaultHandler(IComponentFactory componentFactory) :
|
public class CreateVaultHandler(IVaultComponentFactory vaultComponentFactory) :
|
||||||
IHandler<Create<Vault>, bool>
|
IHandler<Create<Vault>, bool>
|
||||||
{
|
{
|
||||||
public async Task<bool> Handle(Create<Vault> args,
|
public Task<bool> Handle(Create<Vault> args,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (args.Value is Vault vault)
|
if (args.Value is Vault vault && vault.Name is { Length: > 0 } name && vault.Password is { Length: > 0 } password)
|
||||||
{
|
{
|
||||||
if (vault.Name is { Length: > 0 } name && vault.Password is { Length: > 0 } password)
|
if (vaultComponentFactory.Create(name) is IComponentHost host)
|
||||||
{
|
{
|
||||||
if (componentFactory.Create<IVaultComponent, VaultConfiguration>($"Vault:{name}", new VaultConfiguration { Name = name }) is IComponentHost host)
|
IVaultFactory factory = host.Services.GetRequiredService<IVaultFactory>();
|
||||||
{
|
factory.Create(name, password);
|
||||||
if (host.Services.GetRequiredService<IMediator>() is IMediator mediator)
|
|
||||||
{
|
return Task.FromResult(true);
|
||||||
if (await mediator.Handle<Create<VaultStorage>, bool>(Create.As(new VaultStorage(name, password)), cancellationToken))
|
|
||||||
{
|
|
||||||
await host.StartAsync(cancellationToken);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return Task.FromResult(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,73 +1,89 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
//using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Hosting;
|
//using Microsoft.Extensions.Hosting;
|
||||||
using System.Security.Cryptography;
|
//using Toolkit.Foundation;
|
||||||
using Toolkit.Foundation;
|
|
||||||
|
|
||||||
namespace Bitvault;
|
//namespace Bitvault;
|
||||||
|
|
||||||
public class CreateVaultStorageHandler(IHostEnvironment environment,
|
//public class CreateVaultStorageHandler(IHostEnvironment environment,
|
||||||
IKeyDeriver deriver,
|
// IKeyGenerator generator,
|
||||||
IEncryptor encryptor,
|
// IKeyDeriver deriver,
|
||||||
IDecryptor decryptor,
|
// IEncryptor encryptor,
|
||||||
IDbContextFactory<VaultDbContext> dbContextFactory) : IHandler<Create<VaultStorage>, bool>
|
// IDecryptor decryptor,
|
||||||
{
|
// IDbContextFactory<VaultDbContext> dbContextFactory,
|
||||||
public async Task<bool> Handle(Create<VaultStorage> args, CancellationToken cancellationToken)
|
// IWritableConfiguration<VaultConfiguration> writer) : IHandler<Create<VaultStorage>, bool>
|
||||||
{
|
//{
|
||||||
if (args.Value is VaultStorage vault)
|
// public async Task<bool> Handle(Create<VaultStorage> args, CancellationToken cancellationToken)
|
||||||
{
|
// {
|
||||||
if (vault.Name is { Length: > 0 } name && vault.Password is { Length: > 0 } password)
|
// if (args.Value is VaultStorage vault)
|
||||||
{
|
// {
|
||||||
byte[] salt = new byte[16];
|
// if (vault.Name is { Length: > 0 } name && vault.Password is { Length: > 0 } password)
|
||||||
RandomNumberGenerator.Fill(salt);
|
// {
|
||||||
|
// byte[] salt = generator.Generate(16);
|
||||||
|
// byte[] key = generator.Generate(32);
|
||||||
|
|
||||||
byte[] key = new byte[32];
|
// byte[] derivedKey = deriver.DeriveKey(password, salt);
|
||||||
RandomNumberGenerator.Fill(key);
|
|
||||||
|
|
||||||
byte[] derivedKey = deriver.DeriveKey(password, salt);
|
// byte[] encryptedKey = encryptor.Encrypt(key, derivedKey);
|
||||||
string? encryptedKey = encryptor.Encrypt(Convert.ToBase64String(key), derivedKey);
|
// byte[] decryptedKey = decryptor.Decrypt(encryptedKey, derivedKey);
|
||||||
|
|
||||||
|
// Array.Clear(encryptedKey, 0, encryptedKey.Length);
|
||||||
|
|
||||||
|
// using VaultDbContext context = dbContextFactory.CreateDbContext();
|
||||||
|
// context.Database.SetConnectionString($"Data Source={Path.Combine(environment.ContentRootPath, name)}.vault;Mode=ReadWriteCreate;Password={Convert.ToBase64String(decryptedKey)}");
|
||||||
|
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// await context.Database.EnsureCreatedAsync(cancellationToken);
|
||||||
|
// writer.Write(args =>
|
||||||
|
// {
|
||||||
|
// var f = args.Name;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// catch
|
||||||
|
// {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Array.Clear(decryptedKey, 0, decryptedKey.Length);
|
||||||
|
|
||||||
|
// // Derive the key for encryption
|
||||||
|
|
||||||
|
// //byte[] encryptionKey = deriver.DeriveKey(password, salt);
|
||||||
|
|
||||||
|
// //// Derive the key for decryption
|
||||||
|
// //byte[] decryptionKey = deriver.DeriveKey(password, salt);
|
||||||
|
|
||||||
|
// //// Compare keys to ensure they're the same
|
||||||
|
// //bool areKeysEqual = encryptionKey.SequenceEqual(decryptionKey);
|
||||||
|
|
||||||
|
// ////byte[] derivedKey = deriver.DeriveKey(password, salt);
|
||||||
|
// //string? encrypted = encryptor.Encrypt(password, derivedKey);
|
||||||
|
|
||||||
|
// //var storedSalt = Convert.ToBase64String(salt);
|
||||||
|
|
||||||
|
|
||||||
byte[] derivedKey2 = deriver.DeriveKey(password, salt);
|
// //byte[] derivedKey2 = deriver.DeriveKey(password, salt);
|
||||||
var dod = decryptor.Decrypt(encryptedKey, derivedKey2);
|
|
||||||
|
|
||||||
// Derive the key for encryption
|
// //var d = decryptor.Decrypt(encrypted, derivedKey2);
|
||||||
|
|
||||||
//byte[] encryptionKey = deriver.DeriveKey(password, salt);
|
// // Generate a hash
|
||||||
|
// //string hash = hasher.HashPassword(password);
|
||||||
|
|
||||||
//// Derive the key for decryption
|
// //string[] parts = hash.Split(':');
|
||||||
//byte[] decryptionKey = deriver.DeriveKey(password, salt);
|
|
||||||
|
|
||||||
//// Compare keys to ensure they're the same
|
// //// Store the salt only
|
||||||
//bool areKeysEqual = encryptionKey.SequenceEqual(decryptionKey);
|
// //string storedSalt = parts[0];
|
||||||
|
|
||||||
////byte[] derivedKey = deriver.DeriveKey(password, salt);
|
// //// Use the hash as the password
|
||||||
//string? encrypted = encryptor.Encrypt(password, derivedKey);
|
// //string storedHash = parts[1];
|
||||||
|
|
||||||
//var storedSalt = Convert.ToBase64String(salt);
|
// //context.Database.SetConnectionString($"Data Source={Path.Combine(environment.ContentRootPath, name)}.vault;Mode=ReadWriteCreate;Password={storedHash}");
|
||||||
|
// //await context.Database.EnsureCreatedAsync();
|
||||||
|
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
//byte[] derivedKey2 = deriver.DeriveKey(password, salt);
|
// return false;
|
||||||
|
// }
|
||||||
//var d = decryptor.Decrypt(encrypted, derivedKey2);
|
//}
|
||||||
|
|
||||||
// Generate a hash
|
|
||||||
//string hash = hasher.HashPassword(password);
|
|
||||||
|
|
||||||
//string[] parts = hash.Split(':');
|
|
||||||
|
|
||||||
//// Store the salt only
|
|
||||||
//string storedSalt = parts[0];
|
|
||||||
|
|
||||||
//// Use the hash as the password
|
|
||||||
//string storedHash = parts[1];
|
|
||||||
|
|
||||||
//context.Database.SetConnectionString($"Data Source={Path.Combine(environment.ContentRootPath, name)}.vault;Mode=ReadWriteCreate;Password={storedHash}");
|
|
||||||
//await context.Database.EnsureCreatedAsync();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Bitvault
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public interface IDecryptor
|
||||||
{
|
{
|
||||||
public interface IDecryptor
|
byte[] Decrypt(byte[] cipher,
|
||||||
{
|
byte[] key);
|
||||||
string? Decrypt(string cipherText, byte[] key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace Bitvault
|
namespace Bitvault;
|
||||||
{
|
|
||||||
public interface IEncryptor
|
|
||||||
{
|
|
||||||
|
|
||||||
string? Encrypt(string plainText, byte[] key);
|
public interface IEncryptor
|
||||||
}
|
{
|
||||||
|
|
||||||
|
byte[] Encrypt(byte[] data, byte[] key);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public interface IKeyGenerator
|
||||||
|
{
|
||||||
|
byte[] Generate(int size);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
|
namespace Bitvault
|
||||||
|
{
|
||||||
|
public interface IVaultComponentFactory
|
||||||
|
{
|
||||||
|
IComponentHost? Create(string name);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Bitvault
|
||||||
|
{
|
||||||
|
public interface IVaultFactory
|
||||||
|
{
|
||||||
|
bool Create(string name, string password);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public interface IVaultKeyGenerator
|
||||||
|
{
|
||||||
|
VaultKey Create(string password);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public interface IVaultStorage
|
||||||
|
{
|
||||||
|
bool Create(string name, VaultKey key);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class KeyGenerator :
|
||||||
|
IKeyGenerator
|
||||||
|
{
|
||||||
|
public byte[] Generate(int size)
|
||||||
|
{
|
||||||
|
byte[] key = new byte[size];
|
||||||
|
RandomNumberGenerator.Fill(key);
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,10 +12,10 @@ public class OpenVaultHandler(IMediator mediator) :
|
|||||||
{
|
{
|
||||||
if (vault.Password is { Length: > 0 } password)
|
if (vault.Password is { Length: > 0 } password)
|
||||||
{
|
{
|
||||||
if (await mediator.Handle<Open<VaultStorage>, bool>(Open.As(new VaultStorage("Personal", password)), cancellationToken))
|
//if (await mediator.Handle<Open<VaultStorage>, bool>(Open.As(new VaultStorage("Personal", password)), cancellationToken))
|
||||||
{
|
//{
|
||||||
return true;
|
// return true;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
//using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Hosting;
|
//using Microsoft.Extensions.Hosting;
|
||||||
using Toolkit.Foundation;
|
//using Toolkit.Foundation;
|
||||||
|
|
||||||
namespace Bitvault;
|
//namespace Bitvault;
|
||||||
|
|
||||||
public class OpenVaultStorageHandler(IHostEnvironment environment,
|
//public class OpenVaultStorageHandler(IHostEnvironment environment,
|
||||||
IDbContextFactory<VaultDbContext> dbContextFactory) : IHandler<Open<VaultStorage>, bool>
|
// IDbContextFactory<VaultDbContext> dbContextFactory) : IHandler<Open<VaultStorage>, bool>
|
||||||
{
|
//{
|
||||||
public async Task<bool> Handle(Open<VaultStorage> args, CancellationToken cancellationToken)
|
// public async Task<bool> Handle(Open<VaultStorage> args, CancellationToken cancellationToken)
|
||||||
{
|
// {
|
||||||
if (args.Value is VaultStorage vault)
|
// if (args.Value is VaultStorage vault)
|
||||||
{
|
// {
|
||||||
if (vault.Name is { Length: > 0 } name && vault.Password is { Length: > 0 } password)
|
// if (vault.Name is { Length: > 0 } name && vault.Password is { Length: > 0 } password)
|
||||||
{
|
// {
|
||||||
using VaultDbContext context = dbContextFactory.CreateDbContext();
|
// using VaultDbContext context = dbContextFactory.CreateDbContext();
|
||||||
var d = context.Database.GetDbConnection().ConnectionString;
|
// var d = context.Database.GetDbConnection().ConnectionString;
|
||||||
context.Database.SetConnectionString($"Data Source={Path.Combine(environment.ContentRootPath, name)}.vault;Mode=ReadWriteCreate;Password={password}");
|
// context.Database.SetConnectionString($"Data Source={Path.Combine(environment.ContentRootPath, name)}.vault;Mode=ReadWriteCreate;Password={password}");
|
||||||
|
|
||||||
bool isOpen = false;
|
// bool isOpen = false;
|
||||||
await Task.Run(async () =>
|
// await Task.Run(async () =>
|
||||||
{
|
// {
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
await context.Database.OpenConnectionAsync();
|
// await context.Database.OpenConnectionAsync();
|
||||||
isOpen = true;
|
// isOpen = true;
|
||||||
}
|
// }
|
||||||
catch
|
// catch
|
||||||
{
|
// {
|
||||||
// We are ignoring this exception as it is either a go, or not.
|
// // We are ignoring this exception as it is either a go, or not.
|
||||||
}
|
// }
|
||||||
|
|
||||||
}, cancellationToken);
|
// }, cancellationToken);
|
||||||
|
|
||||||
return isOpen;
|
// return isOpen;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class VaultComponentFactory(IComponentFactory componentFactory) :
|
||||||
|
IVaultComponentFactory
|
||||||
|
{
|
||||||
|
public IComponentHost? Create(string name)
|
||||||
|
{
|
||||||
|
if (componentFactory.Create<IVaultComponent, VaultConfiguration>($"Vault:{name}",
|
||||||
|
new VaultConfiguration { Name = name }) is IComponentHost host)
|
||||||
|
{
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,4 +5,6 @@ namespace Bitvault;
|
|||||||
public record VaultConfiguration : ComponentConfiguration
|
public record VaultConfiguration : ComponentConfiguration
|
||||||
{
|
{
|
||||||
public string? Name { get; set; }
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
public string? Key { get; set; }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class VaultFactory(IVaultKeyGenerator keyGenerator,
|
||||||
|
IVaultStorage vaultStorageFactory) :
|
||||||
|
IVaultFactory
|
||||||
|
{
|
||||||
|
public bool Create(string name,
|
||||||
|
string password)
|
||||||
|
{
|
||||||
|
VaultKey key = keyGenerator.Create(password);
|
||||||
|
return vaultStorageFactory.Create(name, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public record VaultKey(byte[] Salt, byte[] Public, byte[] Private);
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class VaultKeyGenerator(IKeyGenerator generator,
|
||||||
|
IKeyDeriver deriver,
|
||||||
|
IEncryptor encryptor,
|
||||||
|
IDecryptor decryptor) :
|
||||||
|
IVaultKeyGenerator
|
||||||
|
{
|
||||||
|
public VaultKey Create(string password)
|
||||||
|
{
|
||||||
|
byte[] salt = generator.Generate(16);
|
||||||
|
byte[] key = generator.Generate(32);
|
||||||
|
|
||||||
|
byte[] derivedKey = deriver.DeriveKey(password, salt);
|
||||||
|
|
||||||
|
byte[] publicKey = encryptor.Encrypt(key, derivedKey);
|
||||||
|
byte[] privateKey = decryptor.Decrypt(publicKey, derivedKey);
|
||||||
|
|
||||||
|
return new VaultKey(salt, publicKey, privateKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,18 @@
|
|||||||
namespace Bitvault;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
public record VaultStorage(string Name, string Password);
|
namespace Bitvault;
|
||||||
|
|
||||||
|
public class VaultStorage(IHostEnvironment environment,
|
||||||
|
IDbContextFactory<VaultDbContext> dbContextFactory) :
|
||||||
|
IVaultStorage
|
||||||
|
{
|
||||||
|
public bool Create(string name, VaultKey key)
|
||||||
|
{
|
||||||
|
using VaultDbContext context = dbContextFactory.CreateDbContext();
|
||||||
|
context.Database.SetConnectionString($"Data Source={Path.Combine(environment.ContentRootPath, name)}" +
|
||||||
|
$".vault;Mode=ReadWriteCreate;Password={Convert.ToBase64String(key.Private)}");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
Submodule Toolkit updated: 7e980dbfce...b89f21b3ca
Reference in New Issue
Block a user