Cryptography service now handles random byte generation

Protected strings are now protected in memory
This commit is contained in:
Geoffroy BONNEVILLE
2020-05-18 14:14:28 +02:00
parent ceaf7dabd3
commit 9126307b4c
22 changed files with 134 additions and 105 deletions

View File

@@ -6,5 +6,6 @@ namespace ModernKeePass.Application.Common.Interfaces
{
Task<string> Protect(string value);
Task<string> UnProtect(string value);
byte[] Random(uint length);
}
}

View File

@@ -35,7 +35,7 @@ namespace ModernKeePass.Application.Common.Interfaces
EntryEntity GetEntry(string id);
Task AddEntry(string parentGroupId, string entryId);
Task MoveEntry(string parentGroupId, string entryId, int index);
void UpdateEntry(string entryId, string fieldName, object fieldValue, bool isProtected);
Task UpdateEntry(string entryId, string fieldName, object fieldValue, bool isProtected);
void DeleteField(string entryId, string fieldName);
Task RemoveEntry(string parentGroupId, string entryId);
EntryEntity CreateEntry(string parentGroupId);

View File

@@ -1,4 +1,5 @@
using MediatR;
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
@@ -11,7 +12,7 @@ namespace ModernKeePass.Application.Entry.Commands.UpsertField
public object FieldValue { get; set; }
public bool IsProtected { get; set; } = true;
public class UpsertFieldCommandHandler : IRequestHandler<UpsertFieldCommand>
public class UpsertFieldCommandHandler : IAsyncRequestHandler<UpsertFieldCommand>
{
private readonly IDatabaseProxy _database;
@@ -20,11 +21,11 @@ namespace ModernKeePass.Application.Entry.Commands.UpsertField
_database = database;
}
public void Handle(UpsertFieldCommand message)
public async Task Handle(UpsertFieldCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
_database.UpdateEntry(message.EntryId, message.FieldName, message.FieldValue, message.IsProtected);
await _database.UpdateEntry(message.EntryId, message.FieldName, message.FieldValue, message.IsProtected);
}
}
}

View File

@@ -39,29 +39,20 @@ namespace ModernKeePass.Application.Entry.Models
public void Mapping(Profile profile)
{
profile.CreateMap<EntryEntity, EntryVm>()
.ForMember(d => d.ParentGroupId, opts => opts.MapFrom(s => s.ParentId))
.ForMember(d => d.ParentGroupName, opts => opts.MapFrom(s => s.ParentName))
.ForMember(d => d.Id, opts => opts.MapFrom(s => s.Id))
.ForMember(d => d.Title, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
f.Name.Equals(EntryFieldName.Title, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Title, IsProtected = true } ))
f.Name.Equals(EntryFieldName.Title, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Title, IsProtected = false } ))
.ForMember(d => d.Username, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
f.Name.Equals(EntryFieldName.UserName, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.UserName, IsProtected = true } ))
f.Name.Equals(EntryFieldName.UserName, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.UserName, IsProtected = false } ))
.ForMember(d => d.Password, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
f.Name.Equals(EntryFieldName.Password, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Password, IsProtected = true } ))
.ForMember(d => d.Url, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
f.Name.Equals(EntryFieldName.Url, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Url, IsProtected = true } ))
f.Name.Equals(EntryFieldName.Url, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Url, IsProtected = false } ))
.ForMember(d => d.Notes, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
f.Name.Equals(EntryFieldName.Notes, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Notes, IsProtected = true } ))
f.Name.Equals(EntryFieldName.Notes, StringComparison.OrdinalIgnoreCase)) ?? new FieldEntity { Name = EntryFieldName.Notes, IsProtected = false } ))
.ForMember(d => d.AdditionalFields, opts => opts.MapFrom(s =>
s.Fields.Where(f => !EntryFieldName.StandardFieldNames.Contains(f.Name, StringComparer.OrdinalIgnoreCase))))
.ForMember(d => d.History, opts => opts.MapFrom(s => s.History.Reverse()))
.ForMember(d => d.HasExpirationDate, opts => opts.MapFrom(s => s.HasExpirationDate))
.ForMember(d => d.ExpirationDate, opts => opts.MapFrom(s => s.ExpirationDate))
.ForMember(d => d.ModificationDate, opts => opts.MapFrom(s => s.LastModificationDate))
.ForMember(d => d.Icon, opts => opts.MapFrom(s => s.HasExpirationDate && s.ExpirationDate < DateTimeOffset.Now ? Icon.ReportHacked : s.Icon))
.ForMember(d => d.ForegroundColor, opts => opts.MapFrom(s => s.ForegroundColor))
.ForMember(d => d.BackgroundColor, opts => opts.MapFrom(s => s.BackgroundColor))
.ForMember(d => d.Attachments, opts => opts.MapFrom(s => s.Attachments));
.ForMember(d => d.Icon, opts => opts.MapFrom(s => s.HasExpirationDate && s.ExpirationDate < DateTimeOffset.Now ? Icon.ReportHacked : s.Icon));
}
}
}

View File

@@ -29,7 +29,7 @@ namespace ModernKeePass.Application.Group.Commands.CreateGroup
var group = _database.CreateGroup(message.ParentGroup.Id, message.Name, message.IsRecycleBin);
var groupVm = _mapper.Map<GroupVm>(group);
message.ParentGroup.SubGroups.Add(groupVm);
message.ParentGroup.Groups.Add(groupVm);
return groupVm;
}
}

View File

@@ -26,7 +26,7 @@ namespace ModernKeePass.Application.Group.Commands.MoveGroup
if (!_database.IsOpen) throw new DatabaseClosedException();
await _database.MoveGroup(message.ParentGroup.Id, message.Group.Id, message.Index);
message.ParentGroup.SubGroups.Insert(message.Index, message.Group);
message.ParentGroup.Groups.Insert(message.Index, message.Group);
}
}
}

View File

@@ -24,7 +24,7 @@ namespace ModernKeePass.Application.Group.Commands.SortGroups
if (!_database.IsOpen) throw new DatabaseClosedException();
_database.SortSubGroups(message.Group.Id);
message.Group.SubGroups = message.Group.SubGroups.OrderBy(g => g.Title).ToList();
message.Group.Groups = message.Group.Groups.OrderBy(g => g.Title).ToList();
}
}
}

View File

@@ -15,7 +15,7 @@ namespace ModernKeePass.Application.Group.Models
public string Id { get; set; }
public string Title { get; set; }
public Icon Icon { get; set; }
public List<GroupVm> SubGroups { get; set; }
public List<GroupVm> Groups { get; set; }
public List<EntryVm> Entries { get; set; }
public override string ToString()
@@ -26,13 +26,7 @@ namespace ModernKeePass.Application.Group.Models
public void Mapping(Profile profile)
{
profile.CreateMap<GroupEntity, GroupVm>()
.ForMember(d => d.ParentGroupId, opts => opts.MapFrom(s => s.ParentId))
.ForMember(d => d.ParentGroupName, opts => opts.MapFrom(s => s.ParentName))
.ForMember(d => d.Id, opts => opts.MapFrom(s => s.Id))
.ForMember(d => d.Title, opts => opts.MapFrom(s => s.Name))
.ForMember(d => d.Icon, opts => opts.MapFrom(s => s.Icon))
.ForMember(d => d.Entries, opts => opts.MapFrom(s => s.Entries))
.ForMember(d => d.SubGroups, opts => opts.MapFrom(s => s.SubGroups))
.MaxDepth(2);
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Threading.Tasks;
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
@@ -14,11 +13,13 @@ namespace ModernKeePass.Application.Security.Commands.GenerateKeyFile
{
private readonly ICredentialsProxy _security;
private readonly IFileProxy _file;
private readonly ICryptographyClient _cryptography;
public GenerateKeyFileCommandHandler(ICredentialsProxy security, IFileProxy file)
public GenerateKeyFileCommandHandler(ICredentialsProxy security, IFileProxy file, ICryptographyClient cryptography)
{
_security = security;
_file = file;
_cryptography = cryptography;
}
public async Task Handle(GenerateKeyFileCommand message)
@@ -26,9 +27,7 @@ namespace ModernKeePass.Application.Security.Commands.GenerateKeyFile
byte[] entropy = null;
if (message.AddAdditionalEntropy)
{
entropy = new byte[10];
var random = new Random();
random.NextBytes(entropy);
entropy = _cryptography.Random(10);
}
var keyFile = _security.GenerateKeyFile(entropy);
await _file.WriteBinaryContentsToFile(message.KeyFilePath, keyFile);