diff --git a/ModernKeePass.Application.12/Common/Interfaces/ICryptographyClient.cs b/ModernKeePass.Application.12/Common/Interfaces/ICryptographyClient.cs new file mode 100644 index 0000000..f7c19ff --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/ICryptographyClient.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using ModernKeePass.Domain.Entities; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface ICryptographyClient + { + IEnumerable Ciphers { get; } + IEnumerable KeyDerivations { get; } + IEnumerable CompressionAlgorithms { get; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Interfaces/IDatabaseProxy.cs b/ModernKeePass.Application.12/Common/Interfaces/IDatabaseProxy.cs new file mode 100644 index 0000000..de508b7 --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/IDatabaseProxy.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Entities; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IDatabaseProxy + { + bool IsOpen { get; } + GroupEntity RecycleBin { get; set; } + BaseEntity Cipher { get; set; } + BaseEntity KeyDerivation { get; set; } + string Compression { get; set; } + + Task Open(FileInfo fileInfo, Credentials credentials); + Task Create(FileInfo fileInfo, Credentials credentials); + Task SaveDatabase(); + Task SaveDatabase(FileInfo FileInfo); + Task UpdateCredentials(Credentials credentials); + void CloseDatabase(); + Task AddEntry(GroupEntity parentGroup, EntryEntity entity); + Task AddGroup(GroupEntity parentGroup, GroupEntity entity); + Task UpdateEntry(EntryEntity entity); + Task UpdateGroup(GroupEntity entity); + Task DeleteEntry(EntryEntity entity); + Task DeleteGroup(GroupEntity entity); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Interfaces/IFileProxy.cs b/ModernKeePass.Application.12/Common/Interfaces/IFileProxy.cs new file mode 100644 index 0000000..e9870e2 --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/IFileProxy.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IFileProxy + { + Task OpenBinaryFile(string path); + Task> OpenTextFile(string path); + Task WriteBinaryContentsToFile(string path, byte[] contents); + void ReleaseFile(string path); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Interfaces/IHasSelectableObject.cs b/ModernKeePass.Application.12/Common/Interfaces/IHasSelectableObject.cs new file mode 100644 index 0000000..f2fd247 --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/IHasSelectableObject.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IHasSelectableObject + { + ISelectableModel SelectedItem { get; set; } + } +} diff --git a/ModernKeePass.Application.12/Common/Interfaces/IImportFormat.cs b/ModernKeePass.Application.12/Common/Interfaces/IImportFormat.cs new file mode 100644 index 0000000..f581762 --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/IImportFormat.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IImportFormat + { + Task>> Import(string path); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Interfaces/IIsEnabled.cs b/ModernKeePass.Application.12/Common/Interfaces/IIsEnabled.cs new file mode 100644 index 0000000..1abc45a --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/IIsEnabled.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IIsEnabled + { + bool IsEnabled { get; } + } +} diff --git a/ModernKeePass.Application.12/Common/Interfaces/IPasswordProxy.cs b/ModernKeePass.Application.12/Common/Interfaces/IPasswordProxy.cs new file mode 100644 index 0000000..aec2b37 --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/IPasswordProxy.cs @@ -0,0 +1,11 @@ +using ModernKeePass.Domain.Dtos; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IPasswordProxy + { + string GeneratePassword(PasswordGenerationOptions options); + uint EstimatePasswordComplexity(string password); + byte[] GenerateKeyFile(byte[] additionalEntropy); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Interfaces/IProxyInvocationHandler.cs b/ModernKeePass.Application.12/Common/Interfaces/IProxyInvocationHandler.cs new file mode 100644 index 0000000..5a04d1f --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/IProxyInvocationHandler.cs @@ -0,0 +1,9 @@ +using System.Reflection; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IProxyInvocationHandler + { + object Invoke(object proxy, MethodInfo method, object[] parameters); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Interfaces/IRecentProxy.cs b/ModernKeePass.Application.12/Common/Interfaces/IRecentProxy.cs new file mode 100644 index 0000000..f0792ab --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/IRecentProxy.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ModernKeePass.Domain.Dtos; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IRecentProxy + { + int EntryCount { get; } + Task Get(string token); + Task> GetAll(); + Task Add(FileInfo recentItem); + void ClearAll(); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Interfaces/IResourceProxy.cs b/ModernKeePass.Application.12/Common/Interfaces/IResourceProxy.cs new file mode 100644 index 0000000..ba1530c --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/IResourceProxy.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IResourceProxy + { + string GetResourceValue(string key); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Interfaces/ISelectableModel.cs b/ModernKeePass.Application.12/Common/Interfaces/ISelectableModel.cs new file mode 100644 index 0000000..1102637 --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/ISelectableModel.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface ISelectableModel + { + bool IsSelected { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Interfaces/ISettingsProxy.cs b/ModernKeePass.Application.12/Common/Interfaces/ISettingsProxy.cs new file mode 100644 index 0000000..6471175 --- /dev/null +++ b/ModernKeePass.Application.12/Common/Interfaces/ISettingsProxy.cs @@ -0,0 +1,8 @@ +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface ISettingsProxy + { + T GetSetting(string property, T defaultValue = default); + void PutSetting(string property, T value); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Mappings/IMapFrom.cs b/ModernKeePass.Application.12/Common/Mappings/IMapFrom.cs new file mode 100644 index 0000000..da4ab61 --- /dev/null +++ b/ModernKeePass.Application.12/Common/Mappings/IMapFrom.cs @@ -0,0 +1,10 @@ +using AutoMapper; + +namespace ModernKeePass.Application.Common.Mappings +{ + + public interface IMapFrom + { + void Mapping(Profile profile); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Mappings/MappingProfile.cs b/ModernKeePass.Application.12/Common/Mappings/MappingProfile.cs new file mode 100644 index 0000000..c572745 --- /dev/null +++ b/ModernKeePass.Application.12/Common/Mappings/MappingProfile.cs @@ -0,0 +1,30 @@ +using System; +using System.Linq; +using System.Reflection; +using AutoMapper; + +namespace ModernKeePass.Application.Common.Mappings +{ + public class MappingProfile : Profile + { + public MappingProfile() + { + ApplyMappingsFromAssembly(Assembly.GetExecutingAssembly()); + } + + private void ApplyMappingsFromAssembly(Assembly assembly) + { + var types = assembly.GetExportedTypes() + .Where(t => t.GetInterfaces().Any(i => + i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>))) + .ToList(); + + foreach (var type in types) + { + var instance = Activator.CreateInstance(type); + var methodInfo = type.GetMethod("Mapping"); + methodInfo?.Invoke(instance, new object[] { this }); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Common/Mappings/MappingProfiles.cs b/ModernKeePass.Application.12/Common/Mappings/MappingProfiles.cs new file mode 100644 index 0000000..dbd055d --- /dev/null +++ b/ModernKeePass.Application.12/Common/Mappings/MappingProfiles.cs @@ -0,0 +1,17 @@ +using AutoMapper; +using ModernKeePass.Application.Database.Models; +using ModernKeePass.Application.Entry.Models; +using ModernKeePass.Application.Group.Models; + +namespace ModernKeePass.Application.Common.Mappings +{ + public class MappingProfiles: Profile + { + public void ApplyMappings() + { + new DatabaseVm().Mapping(this); + new EntryVm().Mapping(this); + new GroupVm().Mapping(this); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Database/Commands/CloseDatabase/CloseDatabaseCommand.cs b/ModernKeePass.Application.12/Database/Commands/CloseDatabase/CloseDatabaseCommand.cs new file mode 100644 index 0000000..904641e --- /dev/null +++ b/ModernKeePass.Application.12/Database/Commands/CloseDatabase/CloseDatabaseCommand.cs @@ -0,0 +1,31 @@ +using MediatR; +using System.Threading; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Database.Queries.IsDatabaseOpen; +using ModernKeePass.Domain.Exceptions; + +namespace ModernKeePass.Application.Database.Commands.CloseDatabase +{ + public class CloseDatabaseCommand: IRequest + { + public class CloseDatabaseCommandHandler : IRequestHandler + { + private readonly IDatabaseProxy _database; + private readonly IMediator _mediator; + + public CloseDatabaseCommandHandler(IDatabaseProxy database, IMediator mediator) + { + _database = database; + _mediator = mediator; + } + + public async Task Handle(CloseDatabaseCommand message, CancellationToken cancellationToken) + { + var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery(), cancellationToken); + if (isDatabaseOpen) _database.CloseDatabase(); + else throw new DatabaseClosedException(); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Database/Commands/CreateDatabase/CreateDatabaseCommand.cs b/ModernKeePass.Application.12/Database/Commands/CreateDatabase/CreateDatabaseCommand.cs new file mode 100644 index 0000000..e0e7c44 --- /dev/null +++ b/ModernKeePass.Application.12/Database/Commands/CreateDatabase/CreateDatabaseCommand.cs @@ -0,0 +1,48 @@ +using MediatR; +using System.Threading; +using System.Threading.Tasks; +using AutoMapper; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Database.Models; +using ModernKeePass.Application.Database.Queries.IsDatabaseOpen; +using ModernKeePass.Application.Group.Models; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Exceptions; + +namespace ModernKeePass.Application.Database.Commands.CreateDatabase +{ + public class CreateDatabaseCommand : IRequest + { + public FileInfo FileInfo { get; set; } + public Credentials Credentials { get; set; } + + public class CreateDatabaseCommandHandler : IRequestHandler + { + private readonly IDatabaseProxy _database; + private readonly IMediator _mediator; + private readonly IMapper _mapper; + + public CreateDatabaseCommandHandler(IDatabaseProxy database, IMediator mediator, IMapper mapper) + { + _database = database; + _mediator = mediator; + _mapper = mapper; + } + + public async Task Handle(CreateDatabaseCommand message, CancellationToken cancellationToken) + { + var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery(), cancellationToken); + if (isDatabaseOpen) throw new DatabaseOpenException(); + + var database = await _database.Create(message.FileInfo, message.Credentials); + var databaseVm = new DatabaseVm + { + IsOpen = true, + Name = database.Name, + RootGroup = _mapper.Map(database.RootGroupEntity) + }; + return databaseVm; + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Database/Commands/SaveDatabase/SaveDatabaseCommand.cs b/ModernKeePass.Application.12/Database/Commands/SaveDatabase/SaveDatabaseCommand.cs new file mode 100644 index 0000000..3d29159 --- /dev/null +++ b/ModernKeePass.Application.12/Database/Commands/SaveDatabase/SaveDatabaseCommand.cs @@ -0,0 +1,31 @@ +using MediatR; +using System.Threading; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Database.Queries.IsDatabaseOpen; +using ModernKeePass.Domain.Exceptions; + +namespace ModernKeePass.Application.Database.Commands.SaveDatabase +{ + public class SaveDatabaseCommand : IRequest + { + public class SaveDatabaseCommandHandler : IRequestHandler + { + private readonly IDatabaseProxy _database; + private readonly IMediator _mediator; + + public SaveDatabaseCommandHandler(IDatabaseProxy database, IMediator mediator) + { + _database = database; + _mediator = mediator; + } + + public async Task Handle(SaveDatabaseCommand message, CancellationToken cancellationToken) + { + var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery(), cancellationToken); + if (isDatabaseOpen) await _database.SaveDatabase(); + else throw new DatabaseClosedException(); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Database/Models/DatabaseVm.cs b/ModernKeePass.Application.12/Database/Models/DatabaseVm.cs new file mode 100644 index 0000000..bc7cbde --- /dev/null +++ b/ModernKeePass.Application.12/Database/Models/DatabaseVm.cs @@ -0,0 +1,21 @@ +using AutoMapper; +using ModernKeePass.Application.Common.Mappings; +using ModernKeePass.Application.Group.Models; +using ModernKeePass.Domain.Entities; + +namespace ModernKeePass.Application.Database.Models +{ + public class DatabaseVm: IMapFrom + { + public bool IsOpen { get; set; } + public string Name { get; set; } + public GroupVm RootGroup { get; set; } + + public void Mapping(Profile profile) + { + profile.CreateMap() + .ForMember(d => d.Name, opts => opts.MapFrom(s => s.Name)) + .ForMember(d => d.RootGroup, opts => opts.MapFrom(s => s.RootGroupEntity)); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Database/Models/MainVm.cs b/ModernKeePass.Application.12/Database/Models/MainVm.cs new file mode 100644 index 0000000..e13bb27 --- /dev/null +++ b/ModernKeePass.Application.12/Database/Models/MainVm.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Application.Database.Models +{ + public class MainVm + { + + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Database/Queries/IsDatabaseOpen/IsDatabaseOpenQuery.cs b/ModernKeePass.Application.12/Database/Queries/IsDatabaseOpen/IsDatabaseOpenQuery.cs new file mode 100644 index 0000000..0266666 --- /dev/null +++ b/ModernKeePass.Application.12/Database/Queries/IsDatabaseOpen/IsDatabaseOpenQuery.cs @@ -0,0 +1,24 @@ +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using ModernKeePass.Application.Common.Interfaces; + +namespace ModernKeePass.Application.Database.Queries.IsDatabaseOpen +{ + public class IsDatabaseOpenQuery: IRequest + { + public class IsDatabaseOpenQueryHandler: IRequestHandler + { + private readonly IDatabaseProxy _databaseProxy; + + public IsDatabaseOpenQueryHandler(IDatabaseProxy databaseProxy) + { + _databaseProxy = databaseProxy; + } + public Task Handle(IsDatabaseOpenQuery request, CancellationToken cancellationToken) + { + return Task.FromResult(_databaseProxy.IsOpen); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Database/Queries/OpenDatabase/OpenDatabaseQuery.cs b/ModernKeePass.Application.12/Database/Queries/OpenDatabase/OpenDatabaseQuery.cs new file mode 100644 index 0000000..0fd8917 --- /dev/null +++ b/ModernKeePass.Application.12/Database/Queries/OpenDatabase/OpenDatabaseQuery.cs @@ -0,0 +1,48 @@ +using System.Threading; +using System.Threading.Tasks; +using AutoMapper; +using MediatR; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Database.Models; +using ModernKeePass.Application.Database.Queries.IsDatabaseOpen; +using ModernKeePass.Application.Group.Models; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Exceptions; + +namespace ModernKeePass.Application.Database.Queries.OpenDatabase +{ + public class OpenDatabaseQuery: IRequest + { + public FileInfo FileInfo { get; set; } + public Credentials Credentials { get; set; } + + public class OpenDatabaseQueryHandler : IRequestHandler + { + private readonly IMapper _mapper; + private readonly IMediator _mediator; + private readonly IDatabaseProxy _databaseProxy; + + public OpenDatabaseQueryHandler(IMapper mapper, IMediator mediator, IDatabaseProxy databaseProxy) + { + _mapper = mapper; + _mediator = mediator; + _databaseProxy = databaseProxy; + } + + public async Task Handle(OpenDatabaseQuery request, CancellationToken cancellationToken) + { + var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery(), cancellationToken); + if (isDatabaseOpen) throw new DatabaseOpenException(); + + var database = await _databaseProxy.Open(request.FileInfo, request.Credentials); + var databaseVm = new DatabaseVm + { + IsOpen = true, + Name = database.Name, + RootGroup = _mapper.Map(database.RootGroupEntity) + }; + return databaseVm; + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Database/Queries/OpenDatabase/OpenDatabaseQueryValidator.cs b/ModernKeePass.Application.12/Database/Queries/OpenDatabase/OpenDatabaseQueryValidator.cs new file mode 100644 index 0000000..d773f08 --- /dev/null +++ b/ModernKeePass.Application.12/Database/Queries/OpenDatabase/OpenDatabaseQueryValidator.cs @@ -0,0 +1,12 @@ +using FluentValidation; + +namespace ModernKeePass.Application.Database.Queries.OpenDatabase +{ + public class OpenDatabaseQueryValidator : AbstractValidator + { + public OpenDatabaseQueryValidator() + { + RuleFor(v => v.Credentials != null && v.FileInfo != null); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/DependencyInjection.cs b/ModernKeePass.Application.12/DependencyInjection.cs new file mode 100644 index 0000000..0328d9a --- /dev/null +++ b/ModernKeePass.Application.12/DependencyInjection.cs @@ -0,0 +1,13 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace ModernKeePass.Application +{ + public static class DependencyInjection + { + public static IServiceCollection AddApplication(this IServiceCollection services) + { + + return services; + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Entry/Models/EntryVm.cs b/ModernKeePass.Application.12/Entry/Models/EntryVm.cs new file mode 100644 index 0000000..44f6bcd --- /dev/null +++ b/ModernKeePass.Application.12/Entry/Models/EntryVm.cs @@ -0,0 +1,27 @@ +using System.Drawing; +using AutoMapper; +using ModernKeePass.Application.Common.Mappings; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Enums; + +namespace ModernKeePass.Application.Entry.Models +{ + public class EntryVm: IMapFrom + { + public string Id { get; set; } + public string Title { get; set; } + public Icon Icon { get; set; } + public Color ForegroundColor { get; set; } + public Color BackgroundColor { get; set; } + + public void Mapping(Profile profile) + { + profile.CreateMap() + .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.ForegroundColor, opts => opts.MapFrom(s => s.ForegroundColor)) + .ForMember(d => d.BackgroundColor, opts => opts.MapFrom(s => s.BackgroundColor)); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Group/Models/GroupVm.cs b/ModernKeePass.Application.12/Group/Models/GroupVm.cs new file mode 100644 index 0000000..3ba48f7 --- /dev/null +++ b/ModernKeePass.Application.12/Group/Models/GroupVm.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Drawing; +using AutoMapper; +using ModernKeePass.Application.Common.Mappings; +using ModernKeePass.Application.Entry.Models; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Enums; + +namespace ModernKeePass.Application.Group.Models +{ + public class GroupVm: IMapFrom + { + public string Id { get; set; } + public string Title { get; set; } + public Icon Icon { get; set; } + public Color ForegroundColor { get; set; } + public Color BackgroundColor { get; set; } + public List SubGroups { get; set; } = new List(); + public List Entries { get; set; } = new List(); + + public void Mapping(Profile profile) + { + profile.CreateMap() + .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.ForegroundColor, opts => opts.MapFrom(s => s.ForegroundColor)) + .ForMember(d => d.BackgroundColor, opts => opts.MapFrom(s => s.BackgroundColor)) + .ForMember(d => d.Entries, opts => opts.MapFrom(s => s.Entries)) + .ForMember(d => d.SubGroups, opts => opts.MapFrom(s => s.SubGroups)); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/ModernKeePass.Application.csproj b/ModernKeePass.Application.12/ModernKeePass.Application.csproj new file mode 100644 index 0000000..8c133a3 --- /dev/null +++ b/ModernKeePass.Application.12/ModernKeePass.Application.csproj @@ -0,0 +1,59 @@ + + + + netstandard1.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ModernKeePass.Application.12/Services/CryptographyService.cs b/ModernKeePass.Application.12/Services/CryptographyService.cs new file mode 100644 index 0000000..caa6a57 --- /dev/null +++ b/ModernKeePass.Application.12/Services/CryptographyService.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class CryptographyService : ICryptographyService + { + private readonly ICryptographyClient _cryptographyClient; + public IEnumerable Ciphers => _cryptographyClient.Ciphers; + + public IEnumerable KeyDerivations => _cryptographyClient.KeyDerivations; + + public IEnumerable CompressionAlgorithms => _cryptographyClient.CompressionAlgorithms; + + public CryptographyService(ICryptographyClient cryptographyClient) + { + _cryptographyClient = cryptographyClient; + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Services/DatabaseService.cs b/ModernKeePass.Application.12/Services/DatabaseService.cs new file mode 100644 index 0000000..cbfe4ce --- /dev/null +++ b/ModernKeePass.Application.12/Services/DatabaseService.cs @@ -0,0 +1,103 @@ +using System; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class DatabaseService: IDatabaseService + { + private readonly IDatabaseProxy _databaseProxy; + + public string Name { get; private set; } + public bool IsOpen { get; private set; } + public Domain.Entities.GroupEntity RootGroupEntity { get; private set; } + public Domain.Entities.GroupEntity RecycleBin + { + get => _databaseProxy.RecycleBin; + set => _databaseProxy.RecycleBin = value; + } + public Entity Cipher + { + get => _databaseProxy.Cipher; + set => _databaseProxy.Cipher = value; + } + public Entity KeyDerivation + { + get => _databaseProxy.KeyDerivation; + set => _databaseProxy.KeyDerivation = value; + } + public string Compression + { + get => _databaseProxy.Compression; + set => _databaseProxy.Compression = value; + } + public bool IsRecycleBinEnabled => RecycleBin != null; + + public DatabaseService(IDatabaseProxy databaseProxy) + { + _databaseProxy = databaseProxy; + } + + public async Task Open(FileInfo fileInfo, Credentials credentials) + { + RootGroupEntity = await _databaseProxy.Open(fileInfo, credentials); + Name = RootGroupEntity?.Name; + IsOpen = true; + } + + public async Task Create(FileInfo fileInfo, Credentials credentials) + { + RootGroupEntity = await _databaseProxy.Create(fileInfo, credentials); + Name = RootGroupEntity?.Name; + IsOpen = true; + } + + public async Task Save() + { + await _databaseProxy.SaveDatabase(); + } + + public async Task SaveAs(FileInfo fileInfo) + { + await _databaseProxy.SaveDatabase(fileInfo); + } + + public Task CreateRecycleBin(Domain.Entities.GroupEntity recycleBinGroupEntity) + { + throw new NotImplementedException(); + } + + public async Task UpdateCredentials(Credentials credentials) + { + await _databaseProxy.UpdateCredentials(credentials); + await Save(); + } + + public void Close() + { + _databaseProxy.CloseDatabase(); + IsOpen = false; + } + + public async Task AddEntity(GroupEntity parentEntity, Entity entity) + { + await _databaseProxy.AddEntity(parentEntity, entity); + //await Save(); + } + + public async Task UpdateEntity(Entity entity) + { + await _databaseProxy.UpdateEntity(entity); + } + + public async Task DeleteEntity(Entity entity) + { + if (IsRecycleBinEnabled) await AddEntity(RecycleBin, entity); + await _databaseProxy.DeleteEntity(entity); + //await Save(); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Services/FileService.cs b/ModernKeePass.Application.12/Services/FileService.cs new file mode 100644 index 0000000..6d85c01 --- /dev/null +++ b/ModernKeePass.Application.12/Services/FileService.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class FileService: IFileService + { + private readonly IFileProxy _fileProxy; + + public FileService(IFileProxy fileProxy) + { + _fileProxy = fileProxy; + } + + public Task OpenBinaryFile(string path) + { + return _fileProxy.OpenBinaryFile(path); + } + + public Task WriteBinaryContentsToFile(string path, byte[] contents) + { + return _fileProxy.WriteBinaryContentsToFile(path, contents); + } + + public Task> OpenTextFile(string path) + { + return _fileProxy.OpenTextFile(path); + } + + public void ReleaseFile(string path) + { + _fileProxy.ReleaseFile(path); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Services/ImportService.cs b/ModernKeePass.Application.12/Services/ImportService.cs new file mode 100644 index 0000000..ca1b40e --- /dev/null +++ b/ModernKeePass.Application.12/Services/ImportService.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Enums; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class ImportService: IImportService + { + private readonly Func _importFormatProviders; + + public ImportService(Func importFormatProviders) + { + _importFormatProviders = importFormatProviders; + } + + public async Task Import(ImportFormat format, string filePath, Group group) + { + var importProvider = _importFormatProviders(format); + var data = await importProvider.Import(filePath); + + /*foreach (var entity in data) + { + var entry = group.AddNewEntry(); + entry.Name = entity["0"]; + entry.UserName = entity["1"]; + entry.Password = entity["2"]; + if (entity.Count > 3) entry.Url = entity["3"]; + if (entity.Count > 4) entry.Notes = entity["4"]; + }*/ + } + } +} diff --git a/ModernKeePass.Application.12/Services/RecentService.cs b/ModernKeePass.Application.12/Services/RecentService.cs new file mode 100644 index 0000000..13f2625 --- /dev/null +++ b/ModernKeePass.Application.12/Services/RecentService.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class RecentService: IRecentService + { + private readonly IRecentProxy _recentProxy; + + public RecentService(IRecentProxy recentProxy) + { + _recentProxy = recentProxy; + } + + public bool HasEntries => _recentProxy.EntryCount > 0; + + public async Task Get(string token) + { + return await _recentProxy.Get(token); + } + + public async Task> GetAll() + { + return await _recentProxy.GetAll(); + } + + public async Task Add(FileInfo recentItem) + { + await _recentProxy.Add(recentItem); + } + + public void ClearAll() + { + _recentProxy.ClearAll(); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Services/ResourceService.cs b/ModernKeePass.Application.12/Services/ResourceService.cs new file mode 100644 index 0000000..8f3e920 --- /dev/null +++ b/ModernKeePass.Application.12/Services/ResourceService.cs @@ -0,0 +1,20 @@ +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class ResourceService: IResourceService + { + private readonly IResourceProxy _resourceProxy; + + public ResourceService(IResourceProxy resourceProxy) + { + _resourceProxy = resourceProxy; + } + + public string GetResourceValue(string key) + { + return _resourceProxy.GetResourceValue(key); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Services/SecurityService.cs b/ModernKeePass.Application.12/Services/SecurityService.cs new file mode 100644 index 0000000..14918fe --- /dev/null +++ b/ModernKeePass.Application.12/Services/SecurityService.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class SecurityService: ISecurityService + { + private readonly IPasswordProxy _passwordProxy; + private readonly IFileService _fileService; + + public SecurityService(IPasswordProxy passwordProxy, IFileService fileService) + { + _passwordProxy = passwordProxy; + _fileService = fileService; + } + + public string GeneratePassword(PasswordGenerationOptions options) + { + return _passwordProxy.GeneratePassword(options); + } + + public uint EstimatePasswordComplexity(string password) + { + return _passwordProxy.EstimatePasswordComplexity(password); + } + + public async Task GenerateKeyFile(string filePath) + { + var fileContents = _passwordProxy.GenerateKeyFile(null); + await _fileService.WriteBinaryContentsToFile(filePath, fileContents); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application.12/Services/SettingsService.cs b/ModernKeePass.Application.12/Services/SettingsService.cs new file mode 100644 index 0000000..2c16006 --- /dev/null +++ b/ModernKeePass.Application.12/Services/SettingsService.cs @@ -0,0 +1,25 @@ +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class SettingsService: ISettingsService + { + private readonly ISettingsProxy _settingsProxy; + + public SettingsService(ISettingsProxy settingsProxy) + { + _settingsProxy = settingsProxy; + } + + public T GetSetting(string property, T defaultValue = default) + { + return _settingsProxy.GetSetting(property, defaultValue); + } + + public void PutSetting(string property, T value) + { + _settingsProxy.PutSetting(property, value); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/ICryptographyClient.cs b/ModernKeePass.Application/Common/Interfaces/ICryptographyClient.cs new file mode 100644 index 0000000..f7c19ff --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/ICryptographyClient.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using ModernKeePass.Domain.Entities; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface ICryptographyClient + { + IEnumerable Ciphers { get; } + IEnumerable KeyDerivations { get; } + IEnumerable CompressionAlgorithms { get; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs b/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs new file mode 100644 index 0000000..de508b7 --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Entities; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IDatabaseProxy + { + bool IsOpen { get; } + GroupEntity RecycleBin { get; set; } + BaseEntity Cipher { get; set; } + BaseEntity KeyDerivation { get; set; } + string Compression { get; set; } + + Task Open(FileInfo fileInfo, Credentials credentials); + Task Create(FileInfo fileInfo, Credentials credentials); + Task SaveDatabase(); + Task SaveDatabase(FileInfo FileInfo); + Task UpdateCredentials(Credentials credentials); + void CloseDatabase(); + Task AddEntry(GroupEntity parentGroup, EntryEntity entity); + Task AddGroup(GroupEntity parentGroup, GroupEntity entity); + Task UpdateEntry(EntryEntity entity); + Task UpdateGroup(GroupEntity entity); + Task DeleteEntry(EntryEntity entity); + Task DeleteGroup(GroupEntity entity); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/IFileProxy.cs b/ModernKeePass.Application/Common/Interfaces/IFileProxy.cs new file mode 100644 index 0000000..e9870e2 --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/IFileProxy.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IFileProxy + { + Task OpenBinaryFile(string path); + Task> OpenTextFile(string path); + Task WriteBinaryContentsToFile(string path, byte[] contents); + void ReleaseFile(string path); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/IHasSelectableObject.cs b/ModernKeePass.Application/Common/Interfaces/IHasSelectableObject.cs new file mode 100644 index 0000000..f2fd247 --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/IHasSelectableObject.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IHasSelectableObject + { + ISelectableModel SelectedItem { get; set; } + } +} diff --git a/ModernKeePass.Application/Common/Interfaces/IImportFormat.cs b/ModernKeePass.Application/Common/Interfaces/IImportFormat.cs new file mode 100644 index 0000000..f581762 --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/IImportFormat.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IImportFormat + { + Task>> Import(string path); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/IIsEnabled.cs b/ModernKeePass.Application/Common/Interfaces/IIsEnabled.cs new file mode 100644 index 0000000..1abc45a --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/IIsEnabled.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IIsEnabled + { + bool IsEnabled { get; } + } +} diff --git a/ModernKeePass.Application/Common/Interfaces/IPasswordProxy.cs b/ModernKeePass.Application/Common/Interfaces/IPasswordProxy.cs new file mode 100644 index 0000000..aec2b37 --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/IPasswordProxy.cs @@ -0,0 +1,11 @@ +using ModernKeePass.Domain.Dtos; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IPasswordProxy + { + string GeneratePassword(PasswordGenerationOptions options); + uint EstimatePasswordComplexity(string password); + byte[] GenerateKeyFile(byte[] additionalEntropy); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/IProxyInvocationHandler.cs b/ModernKeePass.Application/Common/Interfaces/IProxyInvocationHandler.cs new file mode 100644 index 0000000..5a04d1f --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/IProxyInvocationHandler.cs @@ -0,0 +1,9 @@ +using System.Reflection; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IProxyInvocationHandler + { + object Invoke(object proxy, MethodInfo method, object[] parameters); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/IRecentProxy.cs b/ModernKeePass.Application/Common/Interfaces/IRecentProxy.cs new file mode 100644 index 0000000..f0792ab --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/IRecentProxy.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ModernKeePass.Domain.Dtos; + +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IRecentProxy + { + int EntryCount { get; } + Task Get(string token); + Task> GetAll(); + Task Add(FileInfo recentItem); + void ClearAll(); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/IResourceProxy.cs b/ModernKeePass.Application/Common/Interfaces/IResourceProxy.cs new file mode 100644 index 0000000..ba1530c --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/IResourceProxy.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface IResourceProxy + { + string GetResourceValue(string key); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/ISelectableModel.cs b/ModernKeePass.Application/Common/Interfaces/ISelectableModel.cs new file mode 100644 index 0000000..1102637 --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/ISelectableModel.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface ISelectableModel + { + bool IsSelected { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/ISettingsProxy.cs b/ModernKeePass.Application/Common/Interfaces/ISettingsProxy.cs new file mode 100644 index 0000000..6471175 --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/ISettingsProxy.cs @@ -0,0 +1,8 @@ +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface ISettingsProxy + { + T GetSetting(string property, T defaultValue = default); + void PutSetting(string property, T value); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Mappings/IMapFrom.cs b/ModernKeePass.Application/Common/Mappings/IMapFrom.cs new file mode 100644 index 0000000..da4ab61 --- /dev/null +++ b/ModernKeePass.Application/Common/Mappings/IMapFrom.cs @@ -0,0 +1,10 @@ +using AutoMapper; + +namespace ModernKeePass.Application.Common.Mappings +{ + + public interface IMapFrom + { + void Mapping(Profile profile); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Mappings/MappingProfile.cs b/ModernKeePass.Application/Common/Mappings/MappingProfile.cs new file mode 100644 index 0000000..c572745 --- /dev/null +++ b/ModernKeePass.Application/Common/Mappings/MappingProfile.cs @@ -0,0 +1,30 @@ +using System; +using System.Linq; +using System.Reflection; +using AutoMapper; + +namespace ModernKeePass.Application.Common.Mappings +{ + public class MappingProfile : Profile + { + public MappingProfile() + { + ApplyMappingsFromAssembly(Assembly.GetExecutingAssembly()); + } + + private void ApplyMappingsFromAssembly(Assembly assembly) + { + var types = assembly.GetExportedTypes() + .Where(t => t.GetInterfaces().Any(i => + i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>))) + .ToList(); + + foreach (var type in types) + { + var instance = Activator.CreateInstance(type); + var methodInfo = type.GetMethod("Mapping"); + methodInfo?.Invoke(instance, new object[] { this }); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Mappings/MappingProfiles.cs b/ModernKeePass.Application/Common/Mappings/MappingProfiles.cs new file mode 100644 index 0000000..dbd055d --- /dev/null +++ b/ModernKeePass.Application/Common/Mappings/MappingProfiles.cs @@ -0,0 +1,17 @@ +using AutoMapper; +using ModernKeePass.Application.Database.Models; +using ModernKeePass.Application.Entry.Models; +using ModernKeePass.Application.Group.Models; + +namespace ModernKeePass.Application.Common.Mappings +{ + public class MappingProfiles: Profile + { + public void ApplyMappings() + { + new DatabaseVm().Mapping(this); + new EntryVm().Mapping(this); + new GroupVm().Mapping(this); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Database/Commands/CloseDatabase/CloseDatabaseCommand.cs b/ModernKeePass.Application/Database/Commands/CloseDatabase/CloseDatabaseCommand.cs new file mode 100644 index 0000000..904641e --- /dev/null +++ b/ModernKeePass.Application/Database/Commands/CloseDatabase/CloseDatabaseCommand.cs @@ -0,0 +1,31 @@ +using MediatR; +using System.Threading; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Database.Queries.IsDatabaseOpen; +using ModernKeePass.Domain.Exceptions; + +namespace ModernKeePass.Application.Database.Commands.CloseDatabase +{ + public class CloseDatabaseCommand: IRequest + { + public class CloseDatabaseCommandHandler : IRequestHandler + { + private readonly IDatabaseProxy _database; + private readonly IMediator _mediator; + + public CloseDatabaseCommandHandler(IDatabaseProxy database, IMediator mediator) + { + _database = database; + _mediator = mediator; + } + + public async Task Handle(CloseDatabaseCommand message, CancellationToken cancellationToken) + { + var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery(), cancellationToken); + if (isDatabaseOpen) _database.CloseDatabase(); + else throw new DatabaseClosedException(); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Database/Commands/CreateDatabase/CreateDatabaseCommand.cs b/ModernKeePass.Application/Database/Commands/CreateDatabase/CreateDatabaseCommand.cs new file mode 100644 index 0000000..e0e7c44 --- /dev/null +++ b/ModernKeePass.Application/Database/Commands/CreateDatabase/CreateDatabaseCommand.cs @@ -0,0 +1,48 @@ +using MediatR; +using System.Threading; +using System.Threading.Tasks; +using AutoMapper; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Database.Models; +using ModernKeePass.Application.Database.Queries.IsDatabaseOpen; +using ModernKeePass.Application.Group.Models; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Exceptions; + +namespace ModernKeePass.Application.Database.Commands.CreateDatabase +{ + public class CreateDatabaseCommand : IRequest + { + public FileInfo FileInfo { get; set; } + public Credentials Credentials { get; set; } + + public class CreateDatabaseCommandHandler : IRequestHandler + { + private readonly IDatabaseProxy _database; + private readonly IMediator _mediator; + private readonly IMapper _mapper; + + public CreateDatabaseCommandHandler(IDatabaseProxy database, IMediator mediator, IMapper mapper) + { + _database = database; + _mediator = mediator; + _mapper = mapper; + } + + public async Task Handle(CreateDatabaseCommand message, CancellationToken cancellationToken) + { + var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery(), cancellationToken); + if (isDatabaseOpen) throw new DatabaseOpenException(); + + var database = await _database.Create(message.FileInfo, message.Credentials); + var databaseVm = new DatabaseVm + { + IsOpen = true, + Name = database.Name, + RootGroup = _mapper.Map(database.RootGroupEntity) + }; + return databaseVm; + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Database/Commands/SaveDatabase/SaveDatabaseCommand.cs b/ModernKeePass.Application/Database/Commands/SaveDatabase/SaveDatabaseCommand.cs new file mode 100644 index 0000000..3d29159 --- /dev/null +++ b/ModernKeePass.Application/Database/Commands/SaveDatabase/SaveDatabaseCommand.cs @@ -0,0 +1,31 @@ +using MediatR; +using System.Threading; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Database.Queries.IsDatabaseOpen; +using ModernKeePass.Domain.Exceptions; + +namespace ModernKeePass.Application.Database.Commands.SaveDatabase +{ + public class SaveDatabaseCommand : IRequest + { + public class SaveDatabaseCommandHandler : IRequestHandler + { + private readonly IDatabaseProxy _database; + private readonly IMediator _mediator; + + public SaveDatabaseCommandHandler(IDatabaseProxy database, IMediator mediator) + { + _database = database; + _mediator = mediator; + } + + public async Task Handle(SaveDatabaseCommand message, CancellationToken cancellationToken) + { + var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery(), cancellationToken); + if (isDatabaseOpen) await _database.SaveDatabase(); + else throw new DatabaseClosedException(); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Database/Models/DatabaseVm.cs b/ModernKeePass.Application/Database/Models/DatabaseVm.cs new file mode 100644 index 0000000..bc7cbde --- /dev/null +++ b/ModernKeePass.Application/Database/Models/DatabaseVm.cs @@ -0,0 +1,21 @@ +using AutoMapper; +using ModernKeePass.Application.Common.Mappings; +using ModernKeePass.Application.Group.Models; +using ModernKeePass.Domain.Entities; + +namespace ModernKeePass.Application.Database.Models +{ + public class DatabaseVm: IMapFrom + { + public bool IsOpen { get; set; } + public string Name { get; set; } + public GroupVm RootGroup { get; set; } + + public void Mapping(Profile profile) + { + profile.CreateMap() + .ForMember(d => d.Name, opts => opts.MapFrom(s => s.Name)) + .ForMember(d => d.RootGroup, opts => opts.MapFrom(s => s.RootGroupEntity)); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Database/Models/MainVm.cs b/ModernKeePass.Application/Database/Models/MainVm.cs new file mode 100644 index 0000000..e13bb27 --- /dev/null +++ b/ModernKeePass.Application/Database/Models/MainVm.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Application.Database.Models +{ + public class MainVm + { + + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Database/Queries/IsDatabaseOpen/IsDatabaseOpenQuery.cs b/ModernKeePass.Application/Database/Queries/IsDatabaseOpen/IsDatabaseOpenQuery.cs new file mode 100644 index 0000000..0266666 --- /dev/null +++ b/ModernKeePass.Application/Database/Queries/IsDatabaseOpen/IsDatabaseOpenQuery.cs @@ -0,0 +1,24 @@ +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using ModernKeePass.Application.Common.Interfaces; + +namespace ModernKeePass.Application.Database.Queries.IsDatabaseOpen +{ + public class IsDatabaseOpenQuery: IRequest + { + public class IsDatabaseOpenQueryHandler: IRequestHandler + { + private readonly IDatabaseProxy _databaseProxy; + + public IsDatabaseOpenQueryHandler(IDatabaseProxy databaseProxy) + { + _databaseProxy = databaseProxy; + } + public Task Handle(IsDatabaseOpenQuery request, CancellationToken cancellationToken) + { + return Task.FromResult(_databaseProxy.IsOpen); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Database/Queries/OpenDatabase/OpenDatabaseQuery.cs b/ModernKeePass.Application/Database/Queries/OpenDatabase/OpenDatabaseQuery.cs new file mode 100644 index 0000000..0fd8917 --- /dev/null +++ b/ModernKeePass.Application/Database/Queries/OpenDatabase/OpenDatabaseQuery.cs @@ -0,0 +1,48 @@ +using System.Threading; +using System.Threading.Tasks; +using AutoMapper; +using MediatR; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Database.Models; +using ModernKeePass.Application.Database.Queries.IsDatabaseOpen; +using ModernKeePass.Application.Group.Models; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Exceptions; + +namespace ModernKeePass.Application.Database.Queries.OpenDatabase +{ + public class OpenDatabaseQuery: IRequest + { + public FileInfo FileInfo { get; set; } + public Credentials Credentials { get; set; } + + public class OpenDatabaseQueryHandler : IRequestHandler + { + private readonly IMapper _mapper; + private readonly IMediator _mediator; + private readonly IDatabaseProxy _databaseProxy; + + public OpenDatabaseQueryHandler(IMapper mapper, IMediator mediator, IDatabaseProxy databaseProxy) + { + _mapper = mapper; + _mediator = mediator; + _databaseProxy = databaseProxy; + } + + public async Task Handle(OpenDatabaseQuery request, CancellationToken cancellationToken) + { + var isDatabaseOpen = await _mediator.Send(new IsDatabaseOpenQuery(), cancellationToken); + if (isDatabaseOpen) throw new DatabaseOpenException(); + + var database = await _databaseProxy.Open(request.FileInfo, request.Credentials); + var databaseVm = new DatabaseVm + { + IsOpen = true, + Name = database.Name, + RootGroup = _mapper.Map(database.RootGroupEntity) + }; + return databaseVm; + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Database/Queries/OpenDatabase/OpenDatabaseQueryValidator.cs b/ModernKeePass.Application/Database/Queries/OpenDatabase/OpenDatabaseQueryValidator.cs new file mode 100644 index 0000000..d773f08 --- /dev/null +++ b/ModernKeePass.Application/Database/Queries/OpenDatabase/OpenDatabaseQueryValidator.cs @@ -0,0 +1,12 @@ +using FluentValidation; + +namespace ModernKeePass.Application.Database.Queries.OpenDatabase +{ + public class OpenDatabaseQueryValidator : AbstractValidator + { + public OpenDatabaseQueryValidator() + { + RuleFor(v => v.Credentials != null && v.FileInfo != null); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Entry/Models/EntryVm.cs b/ModernKeePass.Application/Entry/Models/EntryVm.cs new file mode 100644 index 0000000..44f6bcd --- /dev/null +++ b/ModernKeePass.Application/Entry/Models/EntryVm.cs @@ -0,0 +1,27 @@ +using System.Drawing; +using AutoMapper; +using ModernKeePass.Application.Common.Mappings; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Enums; + +namespace ModernKeePass.Application.Entry.Models +{ + public class EntryVm: IMapFrom + { + public string Id { get; set; } + public string Title { get; set; } + public Icon Icon { get; set; } + public Color ForegroundColor { get; set; } + public Color BackgroundColor { get; set; } + + public void Mapping(Profile profile) + { + profile.CreateMap() + .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.ForegroundColor, opts => opts.MapFrom(s => s.ForegroundColor)) + .ForMember(d => d.BackgroundColor, opts => opts.MapFrom(s => s.BackgroundColor)); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Group/Models/GroupVm.cs b/ModernKeePass.Application/Group/Models/GroupVm.cs new file mode 100644 index 0000000..3ba48f7 --- /dev/null +++ b/ModernKeePass.Application/Group/Models/GroupVm.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Drawing; +using AutoMapper; +using ModernKeePass.Application.Common.Mappings; +using ModernKeePass.Application.Entry.Models; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Enums; + +namespace ModernKeePass.Application.Group.Models +{ + public class GroupVm: IMapFrom + { + public string Id { get; set; } + public string Title { get; set; } + public Icon Icon { get; set; } + public Color ForegroundColor { get; set; } + public Color BackgroundColor { get; set; } + public List SubGroups { get; set; } = new List(); + public List Entries { get; set; } = new List(); + + public void Mapping(Profile profile) + { + profile.CreateMap() + .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.ForegroundColor, opts => opts.MapFrom(s => s.ForegroundColor)) + .ForMember(d => d.BackgroundColor, opts => opts.MapFrom(s => s.BackgroundColor)) + .ForMember(d => d.Entries, opts => opts.MapFrom(s => s.Entries)) + .ForMember(d => d.SubGroups, opts => opts.MapFrom(s => s.SubGroups)); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/ModernKeePass.Application.csproj b/ModernKeePass.Application/ModernKeePass.Application.csproj new file mode 100644 index 0000000..e90d893 --- /dev/null +++ b/ModernKeePass.Application/ModernKeePass.Application.csproj @@ -0,0 +1,104 @@ + + + + + 14.0 + Debug + AnyCPU + {42353562-5E43-459C-8E3E-2F21E575261D} + Library + Properties + ModernKeePass.Application + ModernKeePass.Application + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + v5.0 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {9a0759f1-9069-4841-99e3-3bec44e17356} + ModernKeePass.Domain + + + + + \ No newline at end of file diff --git a/ModernKeePassLib.Test/Properties/AssemblyInfo.cs b/ModernKeePass.Application/Properties/AssemblyInfo.cs similarity index 76% rename from ModernKeePassLib.Test/Properties/AssemblyInfo.cs rename to ModernKeePass.Application/Properties/AssemblyInfo.cs index b2bfb87..dac2789 100644 --- a/ModernKeePassLib.Test/Properties/AssemblyInfo.cs +++ b/ModernKeePass.Application/Properties/AssemblyInfo.cs @@ -1,18 +1,20 @@ -using System.Reflection; +using System.Resources; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("ModernKeePassLib.Test")] +[assembly: AssemblyTitle("ModernKeePass.Application")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ModernKeePassLib.Test")] -[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyProduct("ModernKeePass.Application")] +[assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] // Version information for an assembly consists of the following four values: // diff --git a/ModernKeePass.Application/Services/CryptographyService.cs b/ModernKeePass.Application/Services/CryptographyService.cs new file mode 100644 index 0000000..caa6a57 --- /dev/null +++ b/ModernKeePass.Application/Services/CryptographyService.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class CryptographyService : ICryptographyService + { + private readonly ICryptographyClient _cryptographyClient; + public IEnumerable Ciphers => _cryptographyClient.Ciphers; + + public IEnumerable KeyDerivations => _cryptographyClient.KeyDerivations; + + public IEnumerable CompressionAlgorithms => _cryptographyClient.CompressionAlgorithms; + + public CryptographyService(ICryptographyClient cryptographyClient) + { + _cryptographyClient = cryptographyClient; + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Services/DatabaseService.cs b/ModernKeePass.Application/Services/DatabaseService.cs new file mode 100644 index 0000000..cbfe4ce --- /dev/null +++ b/ModernKeePass.Application/Services/DatabaseService.cs @@ -0,0 +1,103 @@ +using System; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class DatabaseService: IDatabaseService + { + private readonly IDatabaseProxy _databaseProxy; + + public string Name { get; private set; } + public bool IsOpen { get; private set; } + public Domain.Entities.GroupEntity RootGroupEntity { get; private set; } + public Domain.Entities.GroupEntity RecycleBin + { + get => _databaseProxy.RecycleBin; + set => _databaseProxy.RecycleBin = value; + } + public Entity Cipher + { + get => _databaseProxy.Cipher; + set => _databaseProxy.Cipher = value; + } + public Entity KeyDerivation + { + get => _databaseProxy.KeyDerivation; + set => _databaseProxy.KeyDerivation = value; + } + public string Compression + { + get => _databaseProxy.Compression; + set => _databaseProxy.Compression = value; + } + public bool IsRecycleBinEnabled => RecycleBin != null; + + public DatabaseService(IDatabaseProxy databaseProxy) + { + _databaseProxy = databaseProxy; + } + + public async Task Open(FileInfo fileInfo, Credentials credentials) + { + RootGroupEntity = await _databaseProxy.Open(fileInfo, credentials); + Name = RootGroupEntity?.Name; + IsOpen = true; + } + + public async Task Create(FileInfo fileInfo, Credentials credentials) + { + RootGroupEntity = await _databaseProxy.Create(fileInfo, credentials); + Name = RootGroupEntity?.Name; + IsOpen = true; + } + + public async Task Save() + { + await _databaseProxy.SaveDatabase(); + } + + public async Task SaveAs(FileInfo fileInfo) + { + await _databaseProxy.SaveDatabase(fileInfo); + } + + public Task CreateRecycleBin(Domain.Entities.GroupEntity recycleBinGroupEntity) + { + throw new NotImplementedException(); + } + + public async Task UpdateCredentials(Credentials credentials) + { + await _databaseProxy.UpdateCredentials(credentials); + await Save(); + } + + public void Close() + { + _databaseProxy.CloseDatabase(); + IsOpen = false; + } + + public async Task AddEntity(GroupEntity parentEntity, Entity entity) + { + await _databaseProxy.AddEntity(parentEntity, entity); + //await Save(); + } + + public async Task UpdateEntity(Entity entity) + { + await _databaseProxy.UpdateEntity(entity); + } + + public async Task DeleteEntity(Entity entity) + { + if (IsRecycleBinEnabled) await AddEntity(RecycleBin, entity); + await _databaseProxy.DeleteEntity(entity); + //await Save(); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Services/FileService.cs b/ModernKeePass.Application/Services/FileService.cs new file mode 100644 index 0000000..6d85c01 --- /dev/null +++ b/ModernKeePass.Application/Services/FileService.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class FileService: IFileService + { + private readonly IFileProxy _fileProxy; + + public FileService(IFileProxy fileProxy) + { + _fileProxy = fileProxy; + } + + public Task OpenBinaryFile(string path) + { + return _fileProxy.OpenBinaryFile(path); + } + + public Task WriteBinaryContentsToFile(string path, byte[] contents) + { + return _fileProxy.WriteBinaryContentsToFile(path, contents); + } + + public Task> OpenTextFile(string path) + { + return _fileProxy.OpenTextFile(path); + } + + public void ReleaseFile(string path) + { + _fileProxy.ReleaseFile(path); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Services/ImportService.cs b/ModernKeePass.Application/Services/ImportService.cs new file mode 100644 index 0000000..ca1b40e --- /dev/null +++ b/ModernKeePass.Application/Services/ImportService.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Enums; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class ImportService: IImportService + { + private readonly Func _importFormatProviders; + + public ImportService(Func importFormatProviders) + { + _importFormatProviders = importFormatProviders; + } + + public async Task Import(ImportFormat format, string filePath, Group group) + { + var importProvider = _importFormatProviders(format); + var data = await importProvider.Import(filePath); + + /*foreach (var entity in data) + { + var entry = group.AddNewEntry(); + entry.Name = entity["0"]; + entry.UserName = entity["1"]; + entry.Password = entity["2"]; + if (entity.Count > 3) entry.Url = entity["3"]; + if (entity.Count > 4) entry.Notes = entity["4"]; + }*/ + } + } +} diff --git a/ModernKeePass.Application/Services/RecentService.cs b/ModernKeePass.Application/Services/RecentService.cs new file mode 100644 index 0000000..13f2625 --- /dev/null +++ b/ModernKeePass.Application/Services/RecentService.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class RecentService: IRecentService + { + private readonly IRecentProxy _recentProxy; + + public RecentService(IRecentProxy recentProxy) + { + _recentProxy = recentProxy; + } + + public bool HasEntries => _recentProxy.EntryCount > 0; + + public async Task Get(string token) + { + return await _recentProxy.Get(token); + } + + public async Task> GetAll() + { + return await _recentProxy.GetAll(); + } + + public async Task Add(FileInfo recentItem) + { + await _recentProxy.Add(recentItem); + } + + public void ClearAll() + { + _recentProxy.ClearAll(); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Services/ResourceService.cs b/ModernKeePass.Application/Services/ResourceService.cs new file mode 100644 index 0000000..8f3e920 --- /dev/null +++ b/ModernKeePass.Application/Services/ResourceService.cs @@ -0,0 +1,20 @@ +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class ResourceService: IResourceService + { + private readonly IResourceProxy _resourceProxy; + + public ResourceService(IResourceProxy resourceProxy) + { + _resourceProxy = resourceProxy; + } + + public string GetResourceValue(string key) + { + return _resourceProxy.GetResourceValue(key); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Services/SecurityService.cs b/ModernKeePass.Application/Services/SecurityService.cs new file mode 100644 index 0000000..14918fe --- /dev/null +++ b/ModernKeePass.Application/Services/SecurityService.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class SecurityService: ISecurityService + { + private readonly IPasswordProxy _passwordProxy; + private readonly IFileService _fileService; + + public SecurityService(IPasswordProxy passwordProxy, IFileService fileService) + { + _passwordProxy = passwordProxy; + _fileService = fileService; + } + + public string GeneratePassword(PasswordGenerationOptions options) + { + return _passwordProxy.GeneratePassword(options); + } + + public uint EstimatePasswordComplexity(string password) + { + return _passwordProxy.EstimatePasswordComplexity(password); + } + + public async Task GenerateKeyFile(string filePath) + { + var fileContents = _passwordProxy.GenerateKeyFile(null); + await _fileService.WriteBinaryContentsToFile(filePath, fileContents); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Services/SettingsService.cs b/ModernKeePass.Application/Services/SettingsService.cs new file mode 100644 index 0000000..2c16006 --- /dev/null +++ b/ModernKeePass.Application/Services/SettingsService.cs @@ -0,0 +1,25 @@ +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Interfaces; + +namespace ModernKeePass.Application.Services +{ + public class SettingsService: ISettingsService + { + private readonly ISettingsProxy _settingsProxy; + + public SettingsService(ISettingsProxy settingsProxy) + { + _settingsProxy = settingsProxy; + } + + public T GetSetting(string property, T defaultValue = default) + { + return _settingsProxy.GetSetting(property, defaultValue); + } + + public void PutSetting(string property, T value) + { + _settingsProxy.PutSetting(property, value); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/project.json b/ModernKeePass.Application/project.json new file mode 100644 index 0000000..1118a9b --- /dev/null +++ b/ModernKeePass.Application/project.json @@ -0,0 +1,15 @@ +{ + "supports": {}, + "dependencies": { + "Autofac": "4.9.4", + "AutoMapper": "6.2.2", + "FluentValidation": "8.6.2", + "MediatR": "4.0.0", + "Microsoft.NETCore.Portable.Compatibility": "1.0.1", + "NETStandard.Library": "1.6.1", + "Splat": "3.0.0" + }, + "frameworks": { + "netstandard1.2": {} + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/AOP/NotifyPropertyChangedBase.cs b/ModernKeePass.Domain.12/AOP/NotifyPropertyChangedBase.cs new file mode 100644 index 0000000..c9ab235 --- /dev/null +++ b/ModernKeePass.Domain.12/AOP/NotifyPropertyChangedBase.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace ModernKeePass.Domain.AOP +{ + public class NotifyPropertyChangedBase : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + protected void OnPropertyChanged(string propertyName = "") + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected bool SetProperty(ref T property, T value, [CallerMemberName] string propertyName = "") + { + if (EqualityComparer.Default.Equals(property, value)) + { + return false; + } + + property = value; + OnPropertyChanged(propertyName); + return true; + } + } +} diff --git a/ModernKeePass.Domain.12/Dtos/Credentials.cs b/ModernKeePass.Domain.12/Dtos/Credentials.cs new file mode 100644 index 0000000..bdb3091 --- /dev/null +++ b/ModernKeePass.Domain.12/Dtos/Credentials.cs @@ -0,0 +1,9 @@ +namespace ModernKeePass.Domain.Dtos +{ + public class Credentials + { + public string Password { get; set; } + public string KeyFilePath { get; set; } + // TODO: add Windows Hello + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/Dtos/FileInfo.cs b/ModernKeePass.Domain.12/Dtos/FileInfo.cs new file mode 100644 index 0000000..ad122b6 --- /dev/null +++ b/ModernKeePass.Domain.12/Dtos/FileInfo.cs @@ -0,0 +1,8 @@ +namespace ModernKeePass.Domain.Dtos +{ + public class FileInfo + { + public string Name { get; set; } + public string Path { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/Dtos/PasswordGenerationOptions.cs b/ModernKeePass.Domain.12/Dtos/PasswordGenerationOptions.cs new file mode 100644 index 0000000..bc40931 --- /dev/null +++ b/ModernKeePass.Domain.12/Dtos/PasswordGenerationOptions.cs @@ -0,0 +1,16 @@ +namespace ModernKeePass.Domain.Dtos +{ + public class PasswordGenerationOptions + { + public int PasswordLength { get; set; } + public bool UpperCasePatternSelected { get; set; } + public bool LowerCasePatternSelected { get; set; } + public bool DigitsPatternSelected { get; set; } + public bool SpecialPatternSelected { get; set; } + public bool MinusPatternSelected { get; set; } + public bool UnderscorePatternSelected { get; set; } + public bool SpacePatternSelected { get; set; } + public bool BracketsPatternSelected { get; set; } + public string CustomChars { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/Entities/BaseEntity.cs b/ModernKeePass.Domain.12/Entities/BaseEntity.cs new file mode 100644 index 0000000..0ba8e03 --- /dev/null +++ b/ModernKeePass.Domain.12/Entities/BaseEntity.cs @@ -0,0 +1,14 @@ +using System; +using System.Drawing; + +namespace ModernKeePass.Domain.Entities +{ + public class BaseEntity + { + public string Id { get; set; } + public string Name { get; set; } + public Color ForegroundColor { get; set; } + public Color BackgroundColor { get; set; } + public DateTimeOffset LastModificationDate { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/Entities/DatabaseEntity.cs b/ModernKeePass.Domain.12/Entities/DatabaseEntity.cs new file mode 100644 index 0000000..3c58b65 --- /dev/null +++ b/ModernKeePass.Domain.12/Entities/DatabaseEntity.cs @@ -0,0 +1,9 @@ +namespace ModernKeePass.Domain.Entities +{ + public class DatabaseEntity + { + public string Name { get; set; } + + public GroupEntity RootGroupEntity { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/Entities/EntryEntity.cs b/ModernKeePass.Domain.12/Entities/EntryEntity.cs new file mode 100644 index 0000000..47139bb --- /dev/null +++ b/ModernKeePass.Domain.12/Entities/EntryEntity.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using ModernKeePass.Domain.Enums; + +namespace ModernKeePass.Domain.Entities +{ + public class EntryEntity: BaseEntity + { + public string UserName { get; set; } + public string Password { get; set; } + public Uri Url { get; set; } + public string Notes { get; set; } + public DateTimeOffset ExpirationDate { get; set; } + public Color ForegroundColor { get; set; } + public Color BackgroundColor { get; set; } + public Dictionary AdditionalFields { get; set; } = new Dictionary(); + public IEnumerable History { get; set; } + public Icon Icon { get; set; } + public bool HasExpirationDate { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/Entities/GroupEntity.cs b/ModernKeePass.Domain.12/Entities/GroupEntity.cs new file mode 100644 index 0000000..f538150 --- /dev/null +++ b/ModernKeePass.Domain.12/Entities/GroupEntity.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using ModernKeePass.Domain.Enums; + +namespace ModernKeePass.Domain.Entities +{ + public class GroupEntity : BaseEntity + { + public List SubGroups { get; set; } = new List(); + public List Entries { get; set; } = new List(); + public Icon Icon { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/Enums/CredentialStatusTypes.cs b/ModernKeePass.Domain.12/Enums/CredentialStatusTypes.cs new file mode 100644 index 0000000..7e63087 --- /dev/null +++ b/ModernKeePass.Domain.12/Enums/CredentialStatusTypes.cs @@ -0,0 +1,10 @@ +namespace ModernKeePass.Domain.Enums +{ + public enum CredentialStatusTypes + { + Normal = 0, + Error = 1, + Warning = 3, + Success = 5 + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/Enums/Icon.cs b/ModernKeePass.Domain.12/Enums/Icon.cs new file mode 100644 index 0000000..3584568 --- /dev/null +++ b/ModernKeePass.Domain.12/Enums/Icon.cs @@ -0,0 +1,54 @@ +namespace ModernKeePass.Domain.Enums +{ + public enum Icon + { + Delete, + Edit, + Save, + Cancel, + Accept, + Home, + Camera, + Setting, + Mail, + Find, + Help, + Clock, + Crop, + World, + Flag, + PreviewLink, + Document, + ProtectedDocument, + ContactInfo, + ViewAll, + Rotate, + List, + Shop, + BrowsePhotos, + Caption, + Repair, + Page, + Paste, + Important, + SlideShow, + MapDrive, + ContactPresence, + Contact, + Folder, + View, + Permissions, + Map, + CellPhone, + OutlineStar, + Calculator, + Library, + SyncFolder, + GoToStart, + ZeroBars, + FourBars, + Scan, + ReportHacked, + Stop + } +} diff --git a/ModernKeePass.Domain.12/Enums/ImportFormat.cs b/ModernKeePass.Domain.12/Enums/ImportFormat.cs new file mode 100644 index 0000000..9044d9c --- /dev/null +++ b/ModernKeePass.Domain.12/Enums/ImportFormat.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Domain.Enums +{ + public enum ImportFormat + { + CSV + } +} diff --git a/ModernKeePass.Domain.12/Exceptions/DatabaseClosedException.cs b/ModernKeePass.Domain.12/Exceptions/DatabaseClosedException.cs new file mode 100644 index 0000000..3961243 --- /dev/null +++ b/ModernKeePass.Domain.12/Exceptions/DatabaseClosedException.cs @@ -0,0 +1,7 @@ +using System; + +namespace ModernKeePass.Domain.Exceptions +{ + public class DatabaseClosedException: Exception + { } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/Exceptions/DatabaseOpenException.cs b/ModernKeePass.Domain.12/Exceptions/DatabaseOpenException.cs new file mode 100644 index 0000000..5633409 --- /dev/null +++ b/ModernKeePass.Domain.12/Exceptions/DatabaseOpenException.cs @@ -0,0 +1,7 @@ +using System; + +namespace ModernKeePass.Domain.Exceptions +{ + public class DatabaseOpenException: Exception + { } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/Exceptions/NavigationException.cs b/ModernKeePass.Domain.12/Exceptions/NavigationException.cs new file mode 100644 index 0000000..ea93e00 --- /dev/null +++ b/ModernKeePass.Domain.12/Exceptions/NavigationException.cs @@ -0,0 +1,11 @@ +using System; + +namespace ModernKeePass.Domain.Exceptions +{ + public class NavigationException: Exception + { + public NavigationException(Type pageType) : base($"Failed to load Page {pageType.FullName}") + { + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain.12/Exceptions/SaveException.cs b/ModernKeePass.Domain.12/Exceptions/SaveException.cs new file mode 100644 index 0000000..4ad0818 --- /dev/null +++ b/ModernKeePass.Domain.12/Exceptions/SaveException.cs @@ -0,0 +1,14 @@ +using System; + +namespace ModernKeePass.Domain.Exceptions +{ + public class SaveException : Exception + { + public new Exception InnerException { get; } + + public SaveException(Exception exception) + { + InnerException = exception; + } + } +} diff --git a/ModernKeePass.Domain.12/ModernKeePass.Domain.csproj b/ModernKeePass.Domain.12/ModernKeePass.Domain.csproj new file mode 100644 index 0000000..c2744a9 --- /dev/null +++ b/ModernKeePass.Domain.12/ModernKeePass.Domain.csproj @@ -0,0 +1,11 @@ + + + + netstandard1.2 + + + + + + + diff --git a/ModernKeePass.Domain/AOP/NotifyPropertyChangedBase.cs b/ModernKeePass.Domain/AOP/NotifyPropertyChangedBase.cs new file mode 100644 index 0000000..c9ab235 --- /dev/null +++ b/ModernKeePass.Domain/AOP/NotifyPropertyChangedBase.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace ModernKeePass.Domain.AOP +{ + public class NotifyPropertyChangedBase : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + protected void OnPropertyChanged(string propertyName = "") + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected bool SetProperty(ref T property, T value, [CallerMemberName] string propertyName = "") + { + if (EqualityComparer.Default.Equals(property, value)) + { + return false; + } + + property = value; + OnPropertyChanged(propertyName); + return true; + } + } +} diff --git a/ModernKeePass.Domain/Dtos/Credentials.cs b/ModernKeePass.Domain/Dtos/Credentials.cs new file mode 100644 index 0000000..bdb3091 --- /dev/null +++ b/ModernKeePass.Domain/Dtos/Credentials.cs @@ -0,0 +1,9 @@ +namespace ModernKeePass.Domain.Dtos +{ + public class Credentials + { + public string Password { get; set; } + public string KeyFilePath { get; set; } + // TODO: add Windows Hello + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Dtos/FileInfo.cs b/ModernKeePass.Domain/Dtos/FileInfo.cs new file mode 100644 index 0000000..ad122b6 --- /dev/null +++ b/ModernKeePass.Domain/Dtos/FileInfo.cs @@ -0,0 +1,8 @@ +namespace ModernKeePass.Domain.Dtos +{ + public class FileInfo + { + public string Name { get; set; } + public string Path { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Dtos/PasswordGenerationOptions.cs b/ModernKeePass.Domain/Dtos/PasswordGenerationOptions.cs new file mode 100644 index 0000000..bc40931 --- /dev/null +++ b/ModernKeePass.Domain/Dtos/PasswordGenerationOptions.cs @@ -0,0 +1,16 @@ +namespace ModernKeePass.Domain.Dtos +{ + public class PasswordGenerationOptions + { + public int PasswordLength { get; set; } + public bool UpperCasePatternSelected { get; set; } + public bool LowerCasePatternSelected { get; set; } + public bool DigitsPatternSelected { get; set; } + public bool SpecialPatternSelected { get; set; } + public bool MinusPatternSelected { get; set; } + public bool UnderscorePatternSelected { get; set; } + public bool SpacePatternSelected { get; set; } + public bool BracketsPatternSelected { get; set; } + public string CustomChars { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Entities/BaseEntity.cs b/ModernKeePass.Domain/Entities/BaseEntity.cs new file mode 100644 index 0000000..0ba8e03 --- /dev/null +++ b/ModernKeePass.Domain/Entities/BaseEntity.cs @@ -0,0 +1,14 @@ +using System; +using System.Drawing; + +namespace ModernKeePass.Domain.Entities +{ + public class BaseEntity + { + public string Id { get; set; } + public string Name { get; set; } + public Color ForegroundColor { get; set; } + public Color BackgroundColor { get; set; } + public DateTimeOffset LastModificationDate { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Entities/DatabaseEntity.cs b/ModernKeePass.Domain/Entities/DatabaseEntity.cs new file mode 100644 index 0000000..3c58b65 --- /dev/null +++ b/ModernKeePass.Domain/Entities/DatabaseEntity.cs @@ -0,0 +1,9 @@ +namespace ModernKeePass.Domain.Entities +{ + public class DatabaseEntity + { + public string Name { get; set; } + + public GroupEntity RootGroupEntity { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Entities/EntryEntity.cs b/ModernKeePass.Domain/Entities/EntryEntity.cs new file mode 100644 index 0000000..e675947 --- /dev/null +++ b/ModernKeePass.Domain/Entities/EntryEntity.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using ModernKeePass.Domain.Enums; + +namespace ModernKeePass.Domain.Entities +{ + public class EntryEntity: BaseEntity + { + public string UserName { get; set; } + public string Password { get; set; } + public Uri Url { get; set; } + public string Notes { get; set; } + public DateTimeOffset ExpirationDate { get; set; } + public Dictionary AdditionalFields { get; set; } = new Dictionary(); + public IEnumerable History { get; set; } + public Icon Icon { get; set; } + public bool HasExpirationDate { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Entities/GroupEntity.cs b/ModernKeePass.Domain/Entities/GroupEntity.cs new file mode 100644 index 0000000..f538150 --- /dev/null +++ b/ModernKeePass.Domain/Entities/GroupEntity.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using ModernKeePass.Domain.Enums; + +namespace ModernKeePass.Domain.Entities +{ + public class GroupEntity : BaseEntity + { + public List SubGroups { get; set; } = new List(); + public List Entries { get; set; } = new List(); + public Icon Icon { get; set; } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Enums/CredentialStatusTypes.cs b/ModernKeePass.Domain/Enums/CredentialStatusTypes.cs new file mode 100644 index 0000000..7e63087 --- /dev/null +++ b/ModernKeePass.Domain/Enums/CredentialStatusTypes.cs @@ -0,0 +1,10 @@ +namespace ModernKeePass.Domain.Enums +{ + public enum CredentialStatusTypes + { + Normal = 0, + Error = 1, + Warning = 3, + Success = 5 + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Enums/Icon.cs b/ModernKeePass.Domain/Enums/Icon.cs new file mode 100644 index 0000000..3584568 --- /dev/null +++ b/ModernKeePass.Domain/Enums/Icon.cs @@ -0,0 +1,54 @@ +namespace ModernKeePass.Domain.Enums +{ + public enum Icon + { + Delete, + Edit, + Save, + Cancel, + Accept, + Home, + Camera, + Setting, + Mail, + Find, + Help, + Clock, + Crop, + World, + Flag, + PreviewLink, + Document, + ProtectedDocument, + ContactInfo, + ViewAll, + Rotate, + List, + Shop, + BrowsePhotos, + Caption, + Repair, + Page, + Paste, + Important, + SlideShow, + MapDrive, + ContactPresence, + Contact, + Folder, + View, + Permissions, + Map, + CellPhone, + OutlineStar, + Calculator, + Library, + SyncFolder, + GoToStart, + ZeroBars, + FourBars, + Scan, + ReportHacked, + Stop + } +} diff --git a/ModernKeePass.Domain/Enums/ImportFormat.cs b/ModernKeePass.Domain/Enums/ImportFormat.cs new file mode 100644 index 0000000..9044d9c --- /dev/null +++ b/ModernKeePass.Domain/Enums/ImportFormat.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Domain.Enums +{ + public enum ImportFormat + { + CSV + } +} diff --git a/ModernKeePass.Domain/Exceptions/DatabaseClosedException.cs b/ModernKeePass.Domain/Exceptions/DatabaseClosedException.cs new file mode 100644 index 0000000..3961243 --- /dev/null +++ b/ModernKeePass.Domain/Exceptions/DatabaseClosedException.cs @@ -0,0 +1,7 @@ +using System; + +namespace ModernKeePass.Domain.Exceptions +{ + public class DatabaseClosedException: Exception + { } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Exceptions/DatabaseOpenException.cs b/ModernKeePass.Domain/Exceptions/DatabaseOpenException.cs new file mode 100644 index 0000000..5633409 --- /dev/null +++ b/ModernKeePass.Domain/Exceptions/DatabaseOpenException.cs @@ -0,0 +1,7 @@ +using System; + +namespace ModernKeePass.Domain.Exceptions +{ + public class DatabaseOpenException: Exception + { } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Exceptions/NavigationException.cs b/ModernKeePass.Domain/Exceptions/NavigationException.cs new file mode 100644 index 0000000..ea93e00 --- /dev/null +++ b/ModernKeePass.Domain/Exceptions/NavigationException.cs @@ -0,0 +1,11 @@ +using System; + +namespace ModernKeePass.Domain.Exceptions +{ + public class NavigationException: Exception + { + public NavigationException(Type pageType) : base($"Failed to load Page {pageType.FullName}") + { + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Domain/Exceptions/SaveException.cs b/ModernKeePass.Domain/Exceptions/SaveException.cs new file mode 100644 index 0000000..4ad0818 --- /dev/null +++ b/ModernKeePass.Domain/Exceptions/SaveException.cs @@ -0,0 +1,14 @@ +using System; + +namespace ModernKeePass.Domain.Exceptions +{ + public class SaveException : Exception + { + public new Exception InnerException { get; } + + public SaveException(Exception exception) + { + InnerException = exception; + } + } +} diff --git a/ModernKeePass.Shared/ModernKeePass.Shared.csproj b/ModernKeePass.Domain/ModernKeePass.Domain.csproj similarity index 70% rename from ModernKeePass.Shared/ModernKeePass.Shared.csproj rename to ModernKeePass.Domain/ModernKeePass.Domain.csproj index 7c488ee..90f30a6 100644 --- a/ModernKeePass.Shared/ModernKeePass.Shared.csproj +++ b/ModernKeePass.Domain/ModernKeePass.Domain.csproj @@ -5,11 +5,11 @@ 14.0 Debug AnyCPU - {A3354969-5AAC-4075-8CBF-EA4805B59EFA} + {9A0759F1-9069-4841-99E3-3BEC44E17356} Library Properties - ModernKeePass.Shared - ModernKeePass.Shared + ModernKeePass.Domain + ModernKeePass.Domain en-US 512 {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} @@ -39,6 +39,21 @@ + + + + + + + + + + + + + + + diff --git a/ModernKeePass.Shared/Properties/AssemblyInfo.cs b/ModernKeePass.Domain/Properties/AssemblyInfo.cs similarity index 85% rename from ModernKeePass.Shared/Properties/AssemblyInfo.cs rename to ModernKeePass.Domain/Properties/AssemblyInfo.cs index 0685491..8e6bb49 100644 --- a/ModernKeePass.Shared/Properties/AssemblyInfo.cs +++ b/ModernKeePass.Domain/Properties/AssemblyInfo.cs @@ -6,12 +6,12 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("ModernKeePass.Shared")] +[assembly: AssemblyTitle("ModernKeePass.Domain")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ModernKeePass.Shared")] -[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyProduct("ModernKeePass.Domain")] +[assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/ModernKeePass.Shared/project.json b/ModernKeePass.Domain/project.json similarity index 72% rename from ModernKeePass.Shared/project.json rename to ModernKeePass.Domain/project.json index b737941..942ec30 100644 --- a/ModernKeePass.Shared/project.json +++ b/ModernKeePass.Domain/project.json @@ -2,7 +2,8 @@ "supports": {}, "dependencies": { "Microsoft.NETCore.Portable.Compatibility": "1.0.1", - "NETStandard.Library": "1.6.0" + "NETStandard.Library": "1.6.1", + "Splat": "3.0.0" }, "frameworks": { "netstandard1.2": {} diff --git a/ModernKeePass.Infrastructure/DependencyInjection.cs b/ModernKeePass.Infrastructure/DependencyInjection.cs new file mode 100644 index 0000000..bbebb55 --- /dev/null +++ b/ModernKeePass.Infrastructure/DependencyInjection.cs @@ -0,0 +1,25 @@ +using Autofac; +using AutoMapper; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Infrastructure.KeePass; +using ModernKeePass.Infrastructure.UWP; + +namespace ModernKeePass.Infrastructure +{ + public class DependencyInjection: Module + { + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + + // Register Automapper profiles + builder.RegisterType().As(); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/File/CsvImportFormat.cs b/ModernKeePass.Infrastructure/File/CsvImportFormat.cs new file mode 100644 index 0000000..a240a50 --- /dev/null +++ b/ModernKeePass.Infrastructure/File/CsvImportFormat.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; + +namespace ModernKeePass.Infrastructure.File +{ + public class CsvImportFormat: IImportFormat + { + private readonly IFileProxy _fileService; + private const bool HasHeaderRow = true; + private const char Delimiter = ';'; + private const char LineDelimiter = '\n'; + + public CsvImportFormat(IFileProxy fileService) + { + _fileService = fileService; + } + + public async Task>> Import(string path) + { + var parsedResult = new List>(); + var content = await _fileService.OpenTextFile(path); + foreach (var line in content) + { + var fields = line.Split(Delimiter); + var recordItem = new Dictionary(); + var i = 0; + foreach (var field in fields) + { + recordItem.Add(i.ToString(), field); + i++; + } + parsedResult.Add(recordItem); + } + + return parsedResult; + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/KeePass/EntryMappingProfile.cs b/ModernKeePass.Infrastructure/KeePass/EntryMappingProfile.cs new file mode 100644 index 0000000..a767cf9 --- /dev/null +++ b/ModernKeePass.Infrastructure/KeePass/EntryMappingProfile.cs @@ -0,0 +1,76 @@ +using System; +using System.Linq; +using AutoMapper; +using ModernKeePass.Domain.Entities; +using ModernKeePassLib; +using ModernKeePassLib.Security; + +namespace ModernKeePass.Infrastructure.KeePass +{ + public class EntryMappingProfile: Profile + { + public EntryMappingProfile() + { + FromModelToDto(); + FromDtoToModel(); + } + + private void FromDtoToModel() + { + CreateMap() + .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Uuid.ToHexString())) + .ForMember(dest => dest.Name, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.TitleField))) + .ForMember(dest => dest.UserName, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.UserNameField))) + .ForMember(dest => dest.Password, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.PasswordField))) + .ForMember(dest => dest.Url, opt => + { + opt.PreCondition(src => Uri.TryCreate(GetEntryValue(src, PwDefs.UrlField), UriKind.Absolute, out _)); + opt.MapFrom(src => new Uri(GetEntryValue(src, PwDefs.UrlField))); + }) + .ForMember(dest => dest.Notes, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.NotesField))) + .ForMember(dest => dest.ForegroundColor, opt => opt.MapFrom(src => src.ForegroundColor)) + .ForMember(dest => dest.BackgroundColor, opt => opt.MapFrom(src => src.BackgroundColor)) + .ForMember(dest => dest.ExpirationDate, opt => opt.MapFrom(src => new DateTimeOffset(src.ExpiryTime))) + .ForMember(dest => dest.HasExpirationDate, opt => opt.MapFrom(src => src.Expires)) + .ForMember(dest => dest.Icon, opt => opt.MapFrom(src => IconMapper.MapPwIconToIcon(src.IconId))) + .ForMember(dest => dest.AdditionalFields, opt => opt.MapFrom(src => + src.Strings.Where(s => !PwDefs.GetStandardFields().Contains(s.Key)).ToDictionary(s => s.Key, s => GetEntryValue(src, s.Key)))) + .ForMember(dest => dest.LastModificationDate, opt => opt.MapFrom(src => new DateTimeOffset(src.LastModificationTime))); + } + + private void FromModelToDto() + { + CreateMap().ConvertUsing(); + } + + private string GetEntryValue(PwEntry entry, string key) => entry.Strings.GetSafe(key).ReadString(); + } + + public class EntryToPwEntryDictionaryConverter : ITypeConverter + { + public PwEntry Convert(EntryEntity source, PwEntry destination, ResolutionContext context) + { + //destination.Uuid = new PwUuid(System.Convert.FromBase64String(source.Id)); + destination.ExpiryTime = source.ExpirationDate.DateTime; + destination.Expires = source.HasExpirationDate; + destination.LastModificationTime = source.LastModificationDate.DateTime; + destination.BackgroundColor = source.BackgroundColor; + destination.ForegroundColor = source.ForegroundColor; + destination.IconId = IconMapper.MapIconToPwIcon(source.Icon); + SetEntryValue(destination, PwDefs.TitleField, source.Name); + SetEntryValue(destination, PwDefs.UserNameField, source.UserName); + SetEntryValue(destination, PwDefs.PasswordField, source.Password); + SetEntryValue(destination, PwDefs.UrlField, source.Url?.ToString()); + SetEntryValue(destination, PwDefs.NotesField, source.Notes); + foreach (var additionalField in source.AdditionalFields) + { + SetEntryValue(destination, additionalField.Key, additionalField.Value); + } + return destination; + } + private void SetEntryValue(PwEntry entry, string key, string newValue) + { + if (newValue != null) entry.Strings.Set(key, new ProtectedString(true, newValue)); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/KeePass/IconMapper.cs b/ModernKeePass.Infrastructure/KeePass/IconMapper.cs new file mode 100644 index 0000000..47c254a --- /dev/null +++ b/ModernKeePass.Infrastructure/KeePass/IconMapper.cs @@ -0,0 +1,126 @@ +using ModernKeePass.Domain.Enums; +using ModernKeePassLib; + +namespace ModernKeePass.Infrastructure.KeePass +{ + public static class IconMapper + { + public static Icon MapPwIconToIcon(PwIcon value) + { + switch (value) + { + case PwIcon.Key: return Icon.Permissions; + case PwIcon.WorldSocket: + case PwIcon.World: return Icon.World; + case PwIcon.Warning: return Icon.Important; + case PwIcon.WorldComputer: + case PwIcon.Drive: + case PwIcon.DriveWindows: + case PwIcon.NetworkServer: return Icon.MapDrive; + case PwIcon.MarkedDirectory: return Icon.Map; + case PwIcon.UserCommunication: return Icon.ContactInfo; + case PwIcon.Parts: return Icon.ViewAll; + case PwIcon.Notepad: return Icon.Document; + case PwIcon.Identity: return Icon.Contact; + case PwIcon.PaperReady: return Icon.SyncFolder; + case PwIcon.Digicam: return Icon.Camera; + case PwIcon.IRCommunication: return Icon.View; + case PwIcon.Energy: return Icon.ZeroBars; + case PwIcon.Scanner: return Icon.Scan; + case PwIcon.CDRom: return Icon.Rotate; + case PwIcon.Monitor: return Icon.Caption; + case PwIcon.EMailBox: + case PwIcon.EMail: return Icon.Mail; + case PwIcon.Configuration: return Icon.Setting; + case PwIcon.ClipboardReady: return Icon.Paste; + case PwIcon.PaperNew: return Icon.Page; + case PwIcon.Screen: return Icon.GoToStart; + case PwIcon.EnergyCareful: return Icon.FourBars; + case PwIcon.Disk: return Icon.Save; + case PwIcon.Console: return Icon.SlideShow; + case PwIcon.Printer: return Icon.Scan; + case PwIcon.ProgramIcons: return Icon.GoToStart; + case PwIcon.Settings: + case PwIcon.Tool: return Icon.Repair; + case PwIcon.Archive: return Icon.Crop; + case PwIcon.Count: return Icon.Calculator; + case PwIcon.Clock: return Icon.Clock; + case PwIcon.EMailSearch: return Icon.Find; + case PwIcon.PaperFlag: return Icon.Flag; + case PwIcon.TrashBin: return Icon.Delete; + case PwIcon.Expired: return Icon.ReportHacked; + case PwIcon.Info: return Icon.Help; + case PwIcon.Folder: + case PwIcon.FolderOpen: + case PwIcon.FolderPackage: return Icon.Folder; + case PwIcon.PaperLocked: return Icon.ProtectedDocument; + case PwIcon.Checked: return Icon.Accept; + case PwIcon.Pen: return Icon.Edit; + case PwIcon.Thumbnail: return Icon.BrowsePhotos; + case PwIcon.Book: return Icon.Library; + case PwIcon.List: return Icon.List; + case PwIcon.UserKey: return Icon.ContactPresence; + case PwIcon.Home: return Icon.Home; + case PwIcon.Star: return Icon.OutlineStar; + case PwIcon.Money: return Icon.Shop; + case PwIcon.Certificate: return Icon.PreviewLink; + case PwIcon.BlackBerry: return Icon.CellPhone; + default: return Icon.Stop; + } + } + + public static PwIcon MapIconToPwIcon(Icon value) + { + switch (value) + { + case Icon.Delete: return PwIcon.TrashBin; + case Icon.Edit: return PwIcon.Pen; + case Icon.Save: return PwIcon.Disk; + case Icon.Cancel: return PwIcon.Expired; + case Icon.Accept: return PwIcon.Checked; + case Icon.Home: return PwIcon.Home; + case Icon.Camera: return PwIcon.Digicam; + case Icon.Setting: return PwIcon.Configuration; + case Icon.Mail: return PwIcon.EMail; + case Icon.Find: return PwIcon.EMailSearch; + case Icon.Help: return PwIcon.Info; + case Icon.Clock: return PwIcon.Clock; + case Icon.Crop: return PwIcon.Archive; + case Icon.World: return PwIcon.World; + case Icon.Flag: return PwIcon.PaperFlag; + case Icon.PreviewLink: return PwIcon.Certificate; + case Icon.Document: return PwIcon.Notepad; + case Icon.ProtectedDocument: return PwIcon.PaperLocked; + case Icon.ContactInfo: return PwIcon.UserCommunication; + case Icon.ViewAll: return PwIcon.Parts; + case Icon.Rotate: return PwIcon.CDRom; + case Icon.List: return PwIcon.List; + case Icon.Shop: return PwIcon.Money; + case Icon.BrowsePhotos: return PwIcon.Thumbnail; + case Icon.Caption: return PwIcon.Monitor; + case Icon.Repair: return PwIcon.Tool; + case Icon.Page: return PwIcon.PaperNew; + case Icon.Paste: return PwIcon.ClipboardReady; + case Icon.Important: return PwIcon.Warning; + case Icon.SlideShow: return PwIcon.Console; + case Icon.MapDrive: return PwIcon.NetworkServer; + case Icon.ContactPresence: return PwIcon.UserKey; + case Icon.Contact: return PwIcon.Identity; + case Icon.Folder: return PwIcon.Folder; + case Icon.View: return PwIcon.IRCommunication; + case Icon.Permissions: return PwIcon.Key; + case Icon.Map: return PwIcon.MarkedDirectory; + case Icon.CellPhone: return PwIcon.BlackBerry; + case Icon.OutlineStar: return PwIcon.Star; + case Icon.Calculator: return PwIcon.Count; + case Icon.Library: return PwIcon.Book; + case Icon.SyncFolder: return PwIcon.PaperReady; + case Icon.GoToStart: return PwIcon.Screen; + case Icon.ZeroBars: return PwIcon.Energy; + case Icon.FourBars: return PwIcon.EnergyCareful; + case Icon.Scan: return PwIcon.Scanner; + default: return PwIcon.Key; + } + } + } +} diff --git a/ModernKeePass.Infrastructure/KeePass/KeePassCryptographyClient.cs b/ModernKeePass.Infrastructure/KeePass/KeePassCryptographyClient.cs new file mode 100644 index 0000000..9dfb3b0 --- /dev/null +++ b/ModernKeePass.Infrastructure/KeePass/KeePassCryptographyClient.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Entities; +using ModernKeePassLib; +using ModernKeePassLib.Cryptography.Cipher; +using ModernKeePassLib.Cryptography.KeyDerivation; + +namespace ModernKeePass.Infrastructure.KeePass +{ + public class KeePassCryptographyClient: ICryptographyClient + { + public IEnumerable Ciphers + { + get + { + for (var inx = 0; inx < CipherPool.GlobalPool.EngineCount; inx++) + { + var cipher = CipherPool.GlobalPool[inx]; + yield return new BaseEntity + { + Id = cipher.CipherUuid.ToHexString(), + Name = cipher.DisplayName + }; + } + } + } + + public IEnumerable KeyDerivations => KdfPool.Engines.Select(e => new BaseEntity + { + Id = e.Uuid.ToHexString(), + Name = e.Name + }); + + public IEnumerable CompressionAlgorithms => Enum.GetNames(typeof(PwCompressionAlgorithm)).Take((int) PwCompressionAlgorithm.Count); + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs b/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs new file mode 100644 index 0000000..47aff20 --- /dev/null +++ b/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs @@ -0,0 +1,266 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using AutoMapper; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Exceptions; +using ModernKeePassLib; +using ModernKeePassLib.Cryptography.Cipher; +using ModernKeePassLib.Cryptography.KeyDerivation; +using ModernKeePassLib.Interfaces; +using ModernKeePassLib.Keys; +using ModernKeePassLib.Serialization; +using ModernKeePassLib.Utility; + +namespace ModernKeePass.Infrastructure.KeePass +{ + public class KeePassDatabaseClient: IDatabaseProxy + { + private readonly ISettingsProxy _settings; + private readonly IFileProxy _fileService; + private readonly IMapper _mapper; + private readonly PwDatabase _pwDatabase = new PwDatabase(); + private string _fileAccessToken; + private CompositeKey _compositeKey; + + public bool IsOpen => (_pwDatabase?.IsOpen).GetValueOrDefault(); + + public GroupEntity RecycleBin { get; set; } + + public BaseEntity Cipher + { + get + { + var cipher = CipherPool.GlobalPool.GetCipher(_pwDatabase.DataCipherUuid); + return new BaseEntity + { + Id = cipher.CipherUuid.ToHexString(), + Name = cipher.DisplayName + }; + } + set => _pwDatabase.DataCipherUuid = BuildIdFromString(value.Id); + } + + public BaseEntity KeyDerivation + { + get + { + var keyDerivation = KdfPool.Engines.First(e => e.Uuid.Equals(_pwDatabase.KdfParameters.KdfUuid)); + return new BaseEntity + { + Id = keyDerivation.Uuid.ToHexString(), + Name = keyDerivation.Name + }; + } + set => _pwDatabase.KdfParameters = KdfPool.Engines + .FirstOrDefault(e => e.Uuid.Equals(BuildIdFromString(value.Name)))?.GetDefaultParameters(); + } + + public string Compression + { + get => _pwDatabase.Compression.ToString("G"); + set => _pwDatabase.Compression = (PwCompressionAlgorithm)Enum.Parse(typeof(PwCompressionAlgorithm), value); + } + + public KeePassDatabaseClient(ISettingsProxy settings, IFileProxy fileService, IMapper mapper) + { + _settings = settings; + _fileService = fileService; + _mapper = mapper; + } + + public async Task Open(FileInfo fileInfo, Credentials credentials) + { + try + { + _compositeKey = await CreateCompositeKey(credentials); + var ioConnection = await BuildConnectionInfo(fileInfo); + + _pwDatabase.Open(ioConnection, _compositeKey, new NullStatusLogger()); + + _fileAccessToken = fileInfo.Path; + + return new DatabaseEntity + { + RootGroupEntity = BuildHierarchy(_pwDatabase.RootGroup) + }; + } + catch (InvalidCompositeKeyException ex) + { + throw new ArgumentException(ex.Message, ex); + } + } + + public async Task Create(FileInfo fileInfo, Credentials credentials) + { + _compositeKey = await CreateCompositeKey(credentials); + var ioConnection = await BuildConnectionInfo(fileInfo); + + _pwDatabase.New(ioConnection, _compositeKey); + + var fileFormat = _settings.GetSetting("DefaultFileFormat"); + switch (fileFormat) + { + case "4": + _pwDatabase.KdfParameters = KdfPool.Get("Argon2").GetDefaultParameters(); + break; + } + + _fileAccessToken = fileInfo.Path; + + // TODO: create sample data depending on settings + return new DatabaseEntity + { + RootGroupEntity = BuildHierarchy(_pwDatabase.RootGroup) + }; + } + + public async Task SaveDatabase() + { + if (!_pwDatabase.IsOpen) return; + try + { + _pwDatabase.Save(new NullStatusLogger()); + await _fileService.WriteBinaryContentsToFile(_fileAccessToken, _pwDatabase.IOConnectionInfo.Bytes); + } + catch (Exception e) + { + throw new SaveException(e); + } + } + + public async Task SaveDatabase(FileInfo fileInfo) + { + try + { + var newFileContents = await _fileService.OpenBinaryFile(fileInfo.Path); + _pwDatabase.SaveAs(IOConnectionInfo.FromByteArray(newFileContents), true, new NullStatusLogger()); + await _fileService.WriteBinaryContentsToFile(fileInfo.Path, _pwDatabase.IOConnectionInfo.Bytes); + + _fileService.ReleaseFile(_fileAccessToken); + _fileAccessToken = fileInfo.Path; + } + catch (Exception e) + { + throw new SaveException(e); + } + } + + public void CloseDatabase() + { + _pwDatabase?.Close(); + _fileService.ReleaseFile(_fileAccessToken); + } + + public async Task AddEntry(GroupEntity parentGroupEntity, EntryEntity entry) + { + await Task.Run(() => + { + var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupEntity.Id), true); + + var pwEntry = new PwEntry(true, true); + _mapper.Map(entry, pwEntry); + parentPwGroup.AddEntry(pwEntry, true); + entry.Id = pwEntry.Uuid.ToHexString(); + }); + } + public async Task AddGroup(GroupEntity parentGroupEntity, GroupEntity group) + { + await Task.Run(() => + { + var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupEntity.Id), true); + + var pwGroup = new PwGroup(true, true) + { + Name = group.Name + }; + parentPwGroup.AddGroup(pwGroup, true); + group.Id = pwGroup.Uuid.ToHexString(); + + }); + } + + public Task UpdateEntry(EntryEntity entry) + { + throw new NotImplementedException(); + } + + public Task UpdateGroup(GroupEntity group) + { + throw new NotImplementedException(); + } + + public async Task DeleteEntry(EntryEntity entry) + { + await Task.Run(() => + { + var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entry.Id), true); + var id = pwEntry.Uuid; + pwEntry.ParentGroup.Entries.Remove(pwEntry); + + if (_pwDatabase.RecycleBinEnabled) + { + _pwDatabase.DeletedObjects.Add(new PwDeletedObject(id, DateTime.UtcNow)); + } + }); + } + public async Task DeleteGroup(GroupEntity group) + { + await Task.Run(() => + { + var pwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(group.Id), true); + var id = pwGroup.Uuid; + pwGroup.ParentGroup.Groups.Remove(pwGroup); + + if (_pwDatabase.RecycleBinEnabled) + { + _pwDatabase.DeletedObjects.Add(new PwDeletedObject(id, DateTime.UtcNow)); + } + }); + } + + public async Task UpdateCredentials(Credentials credentials) + { + _pwDatabase.MasterKey = await CreateCompositeKey(credentials); + } + + private async Task CreateCompositeKey(Credentials credentials) + { + var compositeKey = new CompositeKey(); + if (!string.IsNullOrEmpty(credentials.Password)) compositeKey.AddUserKey(new KcpPassword(credentials.Password)); + if (!string.IsNullOrEmpty(credentials.KeyFilePath)) + { + var kcpFileContents = await _fileService.OpenBinaryFile(credentials.KeyFilePath); + compositeKey.AddUserKey(new KcpKeyFile(IOConnectionInfo.FromByteArray(kcpFileContents))); + } + return compositeKey; + } + + private async Task BuildConnectionInfo(FileInfo fileInfo) + { + var fileContents = await _fileService.OpenBinaryFile(fileInfo.Path); + return IOConnectionInfo.FromByteArray(fileContents); + } + + private GroupEntity BuildHierarchy(PwGroup pwGroup) + { + // TODO: build entity hierarchy in an iterative way or implement lazy loading + var group = new GroupEntity + { + Id = pwGroup.Uuid.ToHexString(), + Name = pwGroup.Name, + Icon = IconMapper.MapPwIconToIcon(pwGroup.IconId), + Entries = pwGroup.Entries.Select(e => _mapper.Map(e)).ToList(), + SubGroups = pwGroup.Groups.Select(BuildHierarchy).ToList() + }; + return group; + } + + private PwUuid BuildIdFromString(string id) + { + return new PwUuid(MemUtil.HexStringToByteArray(id)); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/KeePass/KeePassPasswordClient.cs b/ModernKeePass.Infrastructure/KeePass/KeePassPasswordClient.cs new file mode 100644 index 0000000..199ae47 --- /dev/null +++ b/ModernKeePass.Infrastructure/KeePass/KeePassPasswordClient.cs @@ -0,0 +1,46 @@ +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; +using ModernKeePassLib.Cryptography; +using ModernKeePassLib.Cryptography.PasswordGenerator; +using ModernKeePassLib.Keys; + +namespace ModernKeePass.Infrastructure.KeePass +{ + public class KeePassPasswordClient: IPasswordProxy + { + public string GeneratePassword(PasswordGenerationOptions options) + { + var pwProfile = new PwProfile + { + GeneratorType = PasswordGeneratorType.CharSet, + Length = (uint)options.PasswordLength, + CharSet = new PwCharSet() + }; + + if (options.UpperCasePatternSelected) pwProfile.CharSet.Add(PwCharSet.UpperCase); + if (options.LowerCasePatternSelected) pwProfile.CharSet.Add(PwCharSet.LowerCase); + if (options.DigitsPatternSelected) pwProfile.CharSet.Add(PwCharSet.Digits); + if (options.SpecialPatternSelected) pwProfile.CharSet.Add(PwCharSet.Special); + if (options.MinusPatternSelected) pwProfile.CharSet.Add('-'); + if (options.UnderscorePatternSelected) pwProfile.CharSet.Add('_'); + if (options.SpacePatternSelected) pwProfile.CharSet.Add(' '); + if (options.BracketsPatternSelected) pwProfile.CharSet.Add(PwCharSet.Brackets); + + pwProfile.CharSet.Add(options.CustomChars); + + PwGenerator.Generate(out var password, pwProfile, null, new CustomPwGeneratorPool()); + + return password.ReadString(); + } + + public uint EstimatePasswordComplexity(string password) + { + return QualityEstimation.EstimatePasswordBits(password?.ToCharArray()); + } + + public byte[] GenerateKeyFile(byte[] additionalEntropy) + { + return KcpKeyFile.Create(additionalEntropy); + } + } +} \ No newline at end of file diff --git a/ModernKeePassLib/Libs/Windows.winmd b/ModernKeePass.Infrastructure/Libs/Windows.winmd similarity index 100% rename from ModernKeePassLib/Libs/Windows.winmd rename to ModernKeePass.Infrastructure/Libs/Windows.winmd diff --git a/ModernKeePass.Infrastructure/ModernKeePass.Infrastructure.csproj b/ModernKeePass.Infrastructure/ModernKeePass.Infrastructure.csproj new file mode 100644 index 0000000..bac34e7 --- /dev/null +++ b/ModernKeePass.Infrastructure/ModernKeePass.Infrastructure.csproj @@ -0,0 +1,80 @@ + + + + + 14.0 + Debug + AnyCPU + {09577E4C-4899-45B9-BF80-1803D617CCAE} + Library + Properties + ModernKeePass.Infrastructure + ModernKeePass.Infrastructure + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + v5.0 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + {42353562-5e43-459c-8e3e-2f21e575261d} + ModernKeePass.Application + + + {9a0759f1-9069-4841-99e3-3bec44e17356} + ModernKeePass.Domain + + + + + False + Libs\Windows.winmd + + + + + \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/Properties/AssemblyInfo.cs b/ModernKeePass.Infrastructure/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..437fcf1 --- /dev/null +++ b/ModernKeePass.Infrastructure/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System.Resources; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ModernKeePass.Infrastructure")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ModernKeePass.Infrastructure")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ModernKeePass.Infrastructure/UWP/StorageFileClient.cs b/ModernKeePass.Infrastructure/UWP/StorageFileClient.cs new file mode 100644 index 0000000..4337d42 --- /dev/null +++ b/ModernKeePass.Infrastructure/UWP/StorageFileClient.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Threading.Tasks; +using Windows.Storage; +using Windows.Storage.AccessCache; +using ModernKeePass.Application.Common.Interfaces; + +namespace ModernKeePass.Infrastructure.UWP +{ + public class StorageFileClient: IFileProxy + { + public async Task OpenBinaryFile(string path) + { + var file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(path); + var result = await FileIO.ReadBufferAsync(file); + return result.ToArray(); + } + + public async Task> OpenTextFile(string path) + { + var file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(path); + var result = await FileIO.ReadLinesAsync(file); + return result; + } + + public void ReleaseFile(string path) + { + StorageApplicationPermissions.FutureAccessList.Remove(path); + } + + public async Task WriteBinaryContentsToFile(string path, byte[] contents) + { + var file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(path); + await FileIO.WriteBytesAsync(file, contents); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/UWP/UwpRecentFilesClient.cs b/ModernKeePass.Infrastructure/UWP/UwpRecentFilesClient.cs new file mode 100644 index 0000000..7dd750a --- /dev/null +++ b/ModernKeePass.Infrastructure/UWP/UwpRecentFilesClient.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Windows.Storage.AccessCache; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; + +namespace ModernKeePass.Infrastructure.UWP +{ + public class UwpRecentFilesClient: IRecentProxy + { + private readonly StorageItemMostRecentlyUsedList _mru = StorageApplicationPermissions.MostRecentlyUsedList; + + public int EntryCount => _mru.Entries.Count; + + public async Task Get(string token) + { + var recentEntry = _mru.Entries.FirstOrDefault(e => e.Token == token); + var file = await _mru.GetFileAsync(token); + StorageApplicationPermissions.FutureAccessList.AddOrReplace(recentEntry.Metadata, file); + return new FileInfo + { + Name = file.DisplayName, + Path = recentEntry.Metadata + }; + } + + public async Task> GetAll() + { + var result = new List(); + foreach (var entry in _mru.Entries) + { + try + { + var recentItem = await Get(entry.Token); + result.Add(recentItem); + } + catch (Exception) + { + _mru.Remove(entry.Token); + } + } + return result; + } + + public async Task Add(FileInfo recentItem) + { + var file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(recentItem.Path); + _mru.Add(file, recentItem.Path); + } + + public void ClearAll() + { + for (var i = _mru.Entries.Count; i > 0; i--) + { + var entry = _mru.Entries[i]; + StorageApplicationPermissions.FutureAccessList.Remove(entry.Metadata); + _mru.Remove(entry.Token); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/UWP/UwpResourceClient.cs b/ModernKeePass.Infrastructure/UWP/UwpResourceClient.cs new file mode 100644 index 0000000..6ddf960 --- /dev/null +++ b/ModernKeePass.Infrastructure/UWP/UwpResourceClient.cs @@ -0,0 +1,17 @@ +using Windows.ApplicationModel.Resources; +using ModernKeePass.Application.Common.Interfaces; + +namespace ModernKeePass.Infrastructure.UWP +{ + public class UwpResourceClient: IResourceProxy + { + private const string ResourceFileName = "CodeBehind"; + private readonly ResourceLoader _resourceLoader = ResourceLoader.GetForCurrentView(); + + public string GetResourceValue(string key) + { + var resource = _resourceLoader.GetString($"/{ResourceFileName}/{key}"); + return resource; + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/UWP/UwpSettingsClient.cs b/ModernKeePass.Infrastructure/UWP/UwpSettingsClient.cs new file mode 100644 index 0000000..612f1d7 --- /dev/null +++ b/ModernKeePass.Infrastructure/UWP/UwpSettingsClient.cs @@ -0,0 +1,31 @@ +using System; +using Windows.Foundation.Collections; +using Windows.Storage; +using ModernKeePass.Application.Common.Interfaces; + +namespace ModernKeePass.Infrastructure.UWP +{ + public class UwpSettingsClient : ISettingsProxy + { + private readonly IPropertySet _values = ApplicationData.Current.LocalSettings.Values; + + public T GetSetting(string property, T defaultValue = default) + { + try + { + return (T)Convert.ChangeType(_values[property], typeof(T)); + } + catch (InvalidCastException) + { + return defaultValue; + } + } + + public void PutSetting(string property, T value) + { + if (_values.ContainsKey(property)) + _values[property] = value; + else _values.Add(property, value); + } + } +} diff --git a/ModernKeePass.Infrastructure/project.json b/ModernKeePass.Infrastructure/project.json new file mode 100644 index 0000000..450d6f3 --- /dev/null +++ b/ModernKeePass.Infrastructure/project.json @@ -0,0 +1,11 @@ +{ + "supports": {}, + "dependencies": { + "Microsoft.NETCore.Portable.Compatibility": "1.0.1", + "ModernKeePassLib": "2.44.1", + "NETStandard.Library": "1.6.1" + }, + "frameworks": { + "netstandard1.2": {} + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastucture.12/DependencyInjection.cs b/ModernKeePass.Infrastucture.12/DependencyInjection.cs new file mode 100644 index 0000000..bbebb55 --- /dev/null +++ b/ModernKeePass.Infrastucture.12/DependencyInjection.cs @@ -0,0 +1,25 @@ +using Autofac; +using AutoMapper; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Infrastructure.KeePass; +using ModernKeePass.Infrastructure.UWP; + +namespace ModernKeePass.Infrastructure +{ + public class DependencyInjection: Module + { + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + + // Register Automapper profiles + builder.RegisterType().As(); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastucture.12/File/CsvImportFormat.cs b/ModernKeePass.Infrastucture.12/File/CsvImportFormat.cs new file mode 100644 index 0000000..a240a50 --- /dev/null +++ b/ModernKeePass.Infrastucture.12/File/CsvImportFormat.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ModernKeePass.Application.Common.Interfaces; + +namespace ModernKeePass.Infrastructure.File +{ + public class CsvImportFormat: IImportFormat + { + private readonly IFileProxy _fileService; + private const bool HasHeaderRow = true; + private const char Delimiter = ';'; + private const char LineDelimiter = '\n'; + + public CsvImportFormat(IFileProxy fileService) + { + _fileService = fileService; + } + + public async Task>> Import(string path) + { + var parsedResult = new List>(); + var content = await _fileService.OpenTextFile(path); + foreach (var line in content) + { + var fields = line.Split(Delimiter); + var recordItem = new Dictionary(); + var i = 0; + foreach (var field in fields) + { + recordItem.Add(i.ToString(), field); + i++; + } + parsedResult.Add(recordItem); + } + + return parsedResult; + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastucture.12/KeePass/EntryMappingProfile.cs b/ModernKeePass.Infrastucture.12/KeePass/EntryMappingProfile.cs new file mode 100644 index 0000000..a767cf9 --- /dev/null +++ b/ModernKeePass.Infrastucture.12/KeePass/EntryMappingProfile.cs @@ -0,0 +1,76 @@ +using System; +using System.Linq; +using AutoMapper; +using ModernKeePass.Domain.Entities; +using ModernKeePassLib; +using ModernKeePassLib.Security; + +namespace ModernKeePass.Infrastructure.KeePass +{ + public class EntryMappingProfile: Profile + { + public EntryMappingProfile() + { + FromModelToDto(); + FromDtoToModel(); + } + + private void FromDtoToModel() + { + CreateMap() + .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Uuid.ToHexString())) + .ForMember(dest => dest.Name, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.TitleField))) + .ForMember(dest => dest.UserName, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.UserNameField))) + .ForMember(dest => dest.Password, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.PasswordField))) + .ForMember(dest => dest.Url, opt => + { + opt.PreCondition(src => Uri.TryCreate(GetEntryValue(src, PwDefs.UrlField), UriKind.Absolute, out _)); + opt.MapFrom(src => new Uri(GetEntryValue(src, PwDefs.UrlField))); + }) + .ForMember(dest => dest.Notes, opt => opt.MapFrom(src => GetEntryValue(src, PwDefs.NotesField))) + .ForMember(dest => dest.ForegroundColor, opt => opt.MapFrom(src => src.ForegroundColor)) + .ForMember(dest => dest.BackgroundColor, opt => opt.MapFrom(src => src.BackgroundColor)) + .ForMember(dest => dest.ExpirationDate, opt => opt.MapFrom(src => new DateTimeOffset(src.ExpiryTime))) + .ForMember(dest => dest.HasExpirationDate, opt => opt.MapFrom(src => src.Expires)) + .ForMember(dest => dest.Icon, opt => opt.MapFrom(src => IconMapper.MapPwIconToIcon(src.IconId))) + .ForMember(dest => dest.AdditionalFields, opt => opt.MapFrom(src => + src.Strings.Where(s => !PwDefs.GetStandardFields().Contains(s.Key)).ToDictionary(s => s.Key, s => GetEntryValue(src, s.Key)))) + .ForMember(dest => dest.LastModificationDate, opt => opt.MapFrom(src => new DateTimeOffset(src.LastModificationTime))); + } + + private void FromModelToDto() + { + CreateMap().ConvertUsing(); + } + + private string GetEntryValue(PwEntry entry, string key) => entry.Strings.GetSafe(key).ReadString(); + } + + public class EntryToPwEntryDictionaryConverter : ITypeConverter + { + public PwEntry Convert(EntryEntity source, PwEntry destination, ResolutionContext context) + { + //destination.Uuid = new PwUuid(System.Convert.FromBase64String(source.Id)); + destination.ExpiryTime = source.ExpirationDate.DateTime; + destination.Expires = source.HasExpirationDate; + destination.LastModificationTime = source.LastModificationDate.DateTime; + destination.BackgroundColor = source.BackgroundColor; + destination.ForegroundColor = source.ForegroundColor; + destination.IconId = IconMapper.MapIconToPwIcon(source.Icon); + SetEntryValue(destination, PwDefs.TitleField, source.Name); + SetEntryValue(destination, PwDefs.UserNameField, source.UserName); + SetEntryValue(destination, PwDefs.PasswordField, source.Password); + SetEntryValue(destination, PwDefs.UrlField, source.Url?.ToString()); + SetEntryValue(destination, PwDefs.NotesField, source.Notes); + foreach (var additionalField in source.AdditionalFields) + { + SetEntryValue(destination, additionalField.Key, additionalField.Value); + } + return destination; + } + private void SetEntryValue(PwEntry entry, string key, string newValue) + { + if (newValue != null) entry.Strings.Set(key, new ProtectedString(true, newValue)); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastucture.12/KeePass/IconMapper.cs b/ModernKeePass.Infrastucture.12/KeePass/IconMapper.cs new file mode 100644 index 0000000..47c254a --- /dev/null +++ b/ModernKeePass.Infrastucture.12/KeePass/IconMapper.cs @@ -0,0 +1,126 @@ +using ModernKeePass.Domain.Enums; +using ModernKeePassLib; + +namespace ModernKeePass.Infrastructure.KeePass +{ + public static class IconMapper + { + public static Icon MapPwIconToIcon(PwIcon value) + { + switch (value) + { + case PwIcon.Key: return Icon.Permissions; + case PwIcon.WorldSocket: + case PwIcon.World: return Icon.World; + case PwIcon.Warning: return Icon.Important; + case PwIcon.WorldComputer: + case PwIcon.Drive: + case PwIcon.DriveWindows: + case PwIcon.NetworkServer: return Icon.MapDrive; + case PwIcon.MarkedDirectory: return Icon.Map; + case PwIcon.UserCommunication: return Icon.ContactInfo; + case PwIcon.Parts: return Icon.ViewAll; + case PwIcon.Notepad: return Icon.Document; + case PwIcon.Identity: return Icon.Contact; + case PwIcon.PaperReady: return Icon.SyncFolder; + case PwIcon.Digicam: return Icon.Camera; + case PwIcon.IRCommunication: return Icon.View; + case PwIcon.Energy: return Icon.ZeroBars; + case PwIcon.Scanner: return Icon.Scan; + case PwIcon.CDRom: return Icon.Rotate; + case PwIcon.Monitor: return Icon.Caption; + case PwIcon.EMailBox: + case PwIcon.EMail: return Icon.Mail; + case PwIcon.Configuration: return Icon.Setting; + case PwIcon.ClipboardReady: return Icon.Paste; + case PwIcon.PaperNew: return Icon.Page; + case PwIcon.Screen: return Icon.GoToStart; + case PwIcon.EnergyCareful: return Icon.FourBars; + case PwIcon.Disk: return Icon.Save; + case PwIcon.Console: return Icon.SlideShow; + case PwIcon.Printer: return Icon.Scan; + case PwIcon.ProgramIcons: return Icon.GoToStart; + case PwIcon.Settings: + case PwIcon.Tool: return Icon.Repair; + case PwIcon.Archive: return Icon.Crop; + case PwIcon.Count: return Icon.Calculator; + case PwIcon.Clock: return Icon.Clock; + case PwIcon.EMailSearch: return Icon.Find; + case PwIcon.PaperFlag: return Icon.Flag; + case PwIcon.TrashBin: return Icon.Delete; + case PwIcon.Expired: return Icon.ReportHacked; + case PwIcon.Info: return Icon.Help; + case PwIcon.Folder: + case PwIcon.FolderOpen: + case PwIcon.FolderPackage: return Icon.Folder; + case PwIcon.PaperLocked: return Icon.ProtectedDocument; + case PwIcon.Checked: return Icon.Accept; + case PwIcon.Pen: return Icon.Edit; + case PwIcon.Thumbnail: return Icon.BrowsePhotos; + case PwIcon.Book: return Icon.Library; + case PwIcon.List: return Icon.List; + case PwIcon.UserKey: return Icon.ContactPresence; + case PwIcon.Home: return Icon.Home; + case PwIcon.Star: return Icon.OutlineStar; + case PwIcon.Money: return Icon.Shop; + case PwIcon.Certificate: return Icon.PreviewLink; + case PwIcon.BlackBerry: return Icon.CellPhone; + default: return Icon.Stop; + } + } + + public static PwIcon MapIconToPwIcon(Icon value) + { + switch (value) + { + case Icon.Delete: return PwIcon.TrashBin; + case Icon.Edit: return PwIcon.Pen; + case Icon.Save: return PwIcon.Disk; + case Icon.Cancel: return PwIcon.Expired; + case Icon.Accept: return PwIcon.Checked; + case Icon.Home: return PwIcon.Home; + case Icon.Camera: return PwIcon.Digicam; + case Icon.Setting: return PwIcon.Configuration; + case Icon.Mail: return PwIcon.EMail; + case Icon.Find: return PwIcon.EMailSearch; + case Icon.Help: return PwIcon.Info; + case Icon.Clock: return PwIcon.Clock; + case Icon.Crop: return PwIcon.Archive; + case Icon.World: return PwIcon.World; + case Icon.Flag: return PwIcon.PaperFlag; + case Icon.PreviewLink: return PwIcon.Certificate; + case Icon.Document: return PwIcon.Notepad; + case Icon.ProtectedDocument: return PwIcon.PaperLocked; + case Icon.ContactInfo: return PwIcon.UserCommunication; + case Icon.ViewAll: return PwIcon.Parts; + case Icon.Rotate: return PwIcon.CDRom; + case Icon.List: return PwIcon.List; + case Icon.Shop: return PwIcon.Money; + case Icon.BrowsePhotos: return PwIcon.Thumbnail; + case Icon.Caption: return PwIcon.Monitor; + case Icon.Repair: return PwIcon.Tool; + case Icon.Page: return PwIcon.PaperNew; + case Icon.Paste: return PwIcon.ClipboardReady; + case Icon.Important: return PwIcon.Warning; + case Icon.SlideShow: return PwIcon.Console; + case Icon.MapDrive: return PwIcon.NetworkServer; + case Icon.ContactPresence: return PwIcon.UserKey; + case Icon.Contact: return PwIcon.Identity; + case Icon.Folder: return PwIcon.Folder; + case Icon.View: return PwIcon.IRCommunication; + case Icon.Permissions: return PwIcon.Key; + case Icon.Map: return PwIcon.MarkedDirectory; + case Icon.CellPhone: return PwIcon.BlackBerry; + case Icon.OutlineStar: return PwIcon.Star; + case Icon.Calculator: return PwIcon.Count; + case Icon.Library: return PwIcon.Book; + case Icon.SyncFolder: return PwIcon.PaperReady; + case Icon.GoToStart: return PwIcon.Screen; + case Icon.ZeroBars: return PwIcon.Energy; + case Icon.FourBars: return PwIcon.EnergyCareful; + case Icon.Scan: return PwIcon.Scanner; + default: return PwIcon.Key; + } + } + } +} diff --git a/ModernKeePass.Infrastucture.12/KeePass/KeePassCryptographyClient.cs b/ModernKeePass.Infrastucture.12/KeePass/KeePassCryptographyClient.cs new file mode 100644 index 0000000..9dfb3b0 --- /dev/null +++ b/ModernKeePass.Infrastucture.12/KeePass/KeePassCryptographyClient.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Entities; +using ModernKeePassLib; +using ModernKeePassLib.Cryptography.Cipher; +using ModernKeePassLib.Cryptography.KeyDerivation; + +namespace ModernKeePass.Infrastructure.KeePass +{ + public class KeePassCryptographyClient: ICryptographyClient + { + public IEnumerable Ciphers + { + get + { + for (var inx = 0; inx < CipherPool.GlobalPool.EngineCount; inx++) + { + var cipher = CipherPool.GlobalPool[inx]; + yield return new BaseEntity + { + Id = cipher.CipherUuid.ToHexString(), + Name = cipher.DisplayName + }; + } + } + } + + public IEnumerable KeyDerivations => KdfPool.Engines.Select(e => new BaseEntity + { + Id = e.Uuid.ToHexString(), + Name = e.Name + }); + + public IEnumerable CompressionAlgorithms => Enum.GetNames(typeof(PwCompressionAlgorithm)).Take((int) PwCompressionAlgorithm.Count); + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastucture.12/KeePass/KeePassDatabaseClient.cs b/ModernKeePass.Infrastucture.12/KeePass/KeePassDatabaseClient.cs new file mode 100644 index 0000000..47aff20 --- /dev/null +++ b/ModernKeePass.Infrastucture.12/KeePass/KeePassDatabaseClient.cs @@ -0,0 +1,266 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using AutoMapper; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; +using ModernKeePass.Domain.Entities; +using ModernKeePass.Domain.Exceptions; +using ModernKeePassLib; +using ModernKeePassLib.Cryptography.Cipher; +using ModernKeePassLib.Cryptography.KeyDerivation; +using ModernKeePassLib.Interfaces; +using ModernKeePassLib.Keys; +using ModernKeePassLib.Serialization; +using ModernKeePassLib.Utility; + +namespace ModernKeePass.Infrastructure.KeePass +{ + public class KeePassDatabaseClient: IDatabaseProxy + { + private readonly ISettingsProxy _settings; + private readonly IFileProxy _fileService; + private readonly IMapper _mapper; + private readonly PwDatabase _pwDatabase = new PwDatabase(); + private string _fileAccessToken; + private CompositeKey _compositeKey; + + public bool IsOpen => (_pwDatabase?.IsOpen).GetValueOrDefault(); + + public GroupEntity RecycleBin { get; set; } + + public BaseEntity Cipher + { + get + { + var cipher = CipherPool.GlobalPool.GetCipher(_pwDatabase.DataCipherUuid); + return new BaseEntity + { + Id = cipher.CipherUuid.ToHexString(), + Name = cipher.DisplayName + }; + } + set => _pwDatabase.DataCipherUuid = BuildIdFromString(value.Id); + } + + public BaseEntity KeyDerivation + { + get + { + var keyDerivation = KdfPool.Engines.First(e => e.Uuid.Equals(_pwDatabase.KdfParameters.KdfUuid)); + return new BaseEntity + { + Id = keyDerivation.Uuid.ToHexString(), + Name = keyDerivation.Name + }; + } + set => _pwDatabase.KdfParameters = KdfPool.Engines + .FirstOrDefault(e => e.Uuid.Equals(BuildIdFromString(value.Name)))?.GetDefaultParameters(); + } + + public string Compression + { + get => _pwDatabase.Compression.ToString("G"); + set => _pwDatabase.Compression = (PwCompressionAlgorithm)Enum.Parse(typeof(PwCompressionAlgorithm), value); + } + + public KeePassDatabaseClient(ISettingsProxy settings, IFileProxy fileService, IMapper mapper) + { + _settings = settings; + _fileService = fileService; + _mapper = mapper; + } + + public async Task Open(FileInfo fileInfo, Credentials credentials) + { + try + { + _compositeKey = await CreateCompositeKey(credentials); + var ioConnection = await BuildConnectionInfo(fileInfo); + + _pwDatabase.Open(ioConnection, _compositeKey, new NullStatusLogger()); + + _fileAccessToken = fileInfo.Path; + + return new DatabaseEntity + { + RootGroupEntity = BuildHierarchy(_pwDatabase.RootGroup) + }; + } + catch (InvalidCompositeKeyException ex) + { + throw new ArgumentException(ex.Message, ex); + } + } + + public async Task Create(FileInfo fileInfo, Credentials credentials) + { + _compositeKey = await CreateCompositeKey(credentials); + var ioConnection = await BuildConnectionInfo(fileInfo); + + _pwDatabase.New(ioConnection, _compositeKey); + + var fileFormat = _settings.GetSetting("DefaultFileFormat"); + switch (fileFormat) + { + case "4": + _pwDatabase.KdfParameters = KdfPool.Get("Argon2").GetDefaultParameters(); + break; + } + + _fileAccessToken = fileInfo.Path; + + // TODO: create sample data depending on settings + return new DatabaseEntity + { + RootGroupEntity = BuildHierarchy(_pwDatabase.RootGroup) + }; + } + + public async Task SaveDatabase() + { + if (!_pwDatabase.IsOpen) return; + try + { + _pwDatabase.Save(new NullStatusLogger()); + await _fileService.WriteBinaryContentsToFile(_fileAccessToken, _pwDatabase.IOConnectionInfo.Bytes); + } + catch (Exception e) + { + throw new SaveException(e); + } + } + + public async Task SaveDatabase(FileInfo fileInfo) + { + try + { + var newFileContents = await _fileService.OpenBinaryFile(fileInfo.Path); + _pwDatabase.SaveAs(IOConnectionInfo.FromByteArray(newFileContents), true, new NullStatusLogger()); + await _fileService.WriteBinaryContentsToFile(fileInfo.Path, _pwDatabase.IOConnectionInfo.Bytes); + + _fileService.ReleaseFile(_fileAccessToken); + _fileAccessToken = fileInfo.Path; + } + catch (Exception e) + { + throw new SaveException(e); + } + } + + public void CloseDatabase() + { + _pwDatabase?.Close(); + _fileService.ReleaseFile(_fileAccessToken); + } + + public async Task AddEntry(GroupEntity parentGroupEntity, EntryEntity entry) + { + await Task.Run(() => + { + var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupEntity.Id), true); + + var pwEntry = new PwEntry(true, true); + _mapper.Map(entry, pwEntry); + parentPwGroup.AddEntry(pwEntry, true); + entry.Id = pwEntry.Uuid.ToHexString(); + }); + } + public async Task AddGroup(GroupEntity parentGroupEntity, GroupEntity group) + { + await Task.Run(() => + { + var parentPwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(parentGroupEntity.Id), true); + + var pwGroup = new PwGroup(true, true) + { + Name = group.Name + }; + parentPwGroup.AddGroup(pwGroup, true); + group.Id = pwGroup.Uuid.ToHexString(); + + }); + } + + public Task UpdateEntry(EntryEntity entry) + { + throw new NotImplementedException(); + } + + public Task UpdateGroup(GroupEntity group) + { + throw new NotImplementedException(); + } + + public async Task DeleteEntry(EntryEntity entry) + { + await Task.Run(() => + { + var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entry.Id), true); + var id = pwEntry.Uuid; + pwEntry.ParentGroup.Entries.Remove(pwEntry); + + if (_pwDatabase.RecycleBinEnabled) + { + _pwDatabase.DeletedObjects.Add(new PwDeletedObject(id, DateTime.UtcNow)); + } + }); + } + public async Task DeleteGroup(GroupEntity group) + { + await Task.Run(() => + { + var pwGroup = _pwDatabase.RootGroup.FindGroup(BuildIdFromString(group.Id), true); + var id = pwGroup.Uuid; + pwGroup.ParentGroup.Groups.Remove(pwGroup); + + if (_pwDatabase.RecycleBinEnabled) + { + _pwDatabase.DeletedObjects.Add(new PwDeletedObject(id, DateTime.UtcNow)); + } + }); + } + + public async Task UpdateCredentials(Credentials credentials) + { + _pwDatabase.MasterKey = await CreateCompositeKey(credentials); + } + + private async Task CreateCompositeKey(Credentials credentials) + { + var compositeKey = new CompositeKey(); + if (!string.IsNullOrEmpty(credentials.Password)) compositeKey.AddUserKey(new KcpPassword(credentials.Password)); + if (!string.IsNullOrEmpty(credentials.KeyFilePath)) + { + var kcpFileContents = await _fileService.OpenBinaryFile(credentials.KeyFilePath); + compositeKey.AddUserKey(new KcpKeyFile(IOConnectionInfo.FromByteArray(kcpFileContents))); + } + return compositeKey; + } + + private async Task BuildConnectionInfo(FileInfo fileInfo) + { + var fileContents = await _fileService.OpenBinaryFile(fileInfo.Path); + return IOConnectionInfo.FromByteArray(fileContents); + } + + private GroupEntity BuildHierarchy(PwGroup pwGroup) + { + // TODO: build entity hierarchy in an iterative way or implement lazy loading + var group = new GroupEntity + { + Id = pwGroup.Uuid.ToHexString(), + Name = pwGroup.Name, + Icon = IconMapper.MapPwIconToIcon(pwGroup.IconId), + Entries = pwGroup.Entries.Select(e => _mapper.Map(e)).ToList(), + SubGroups = pwGroup.Groups.Select(BuildHierarchy).ToList() + }; + return group; + } + + private PwUuid BuildIdFromString(string id) + { + return new PwUuid(MemUtil.HexStringToByteArray(id)); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastucture.12/KeePass/KeePassPasswordClient.cs b/ModernKeePass.Infrastucture.12/KeePass/KeePassPasswordClient.cs new file mode 100644 index 0000000..199ae47 --- /dev/null +++ b/ModernKeePass.Infrastucture.12/KeePass/KeePassPasswordClient.cs @@ -0,0 +1,46 @@ +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; +using ModernKeePassLib.Cryptography; +using ModernKeePassLib.Cryptography.PasswordGenerator; +using ModernKeePassLib.Keys; + +namespace ModernKeePass.Infrastructure.KeePass +{ + public class KeePassPasswordClient: IPasswordProxy + { + public string GeneratePassword(PasswordGenerationOptions options) + { + var pwProfile = new PwProfile + { + GeneratorType = PasswordGeneratorType.CharSet, + Length = (uint)options.PasswordLength, + CharSet = new PwCharSet() + }; + + if (options.UpperCasePatternSelected) pwProfile.CharSet.Add(PwCharSet.UpperCase); + if (options.LowerCasePatternSelected) pwProfile.CharSet.Add(PwCharSet.LowerCase); + if (options.DigitsPatternSelected) pwProfile.CharSet.Add(PwCharSet.Digits); + if (options.SpecialPatternSelected) pwProfile.CharSet.Add(PwCharSet.Special); + if (options.MinusPatternSelected) pwProfile.CharSet.Add('-'); + if (options.UnderscorePatternSelected) pwProfile.CharSet.Add('_'); + if (options.SpacePatternSelected) pwProfile.CharSet.Add(' '); + if (options.BracketsPatternSelected) pwProfile.CharSet.Add(PwCharSet.Brackets); + + pwProfile.CharSet.Add(options.CustomChars); + + PwGenerator.Generate(out var password, pwProfile, null, new CustomPwGeneratorPool()); + + return password.ReadString(); + } + + public uint EstimatePasswordComplexity(string password) + { + return QualityEstimation.EstimatePasswordBits(password?.ToCharArray()); + } + + public byte[] GenerateKeyFile(byte[] additionalEntropy) + { + return KcpKeyFile.Create(additionalEntropy); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastucture.12/Libs/Windows.winmd b/ModernKeePass.Infrastucture.12/Libs/Windows.winmd new file mode 100644 index 0000000..d6498e8 Binary files /dev/null and b/ModernKeePass.Infrastucture.12/Libs/Windows.winmd differ diff --git a/ModernKeePass.Infrastucture.12/ModernKeePass.Infrastructure.csproj b/ModernKeePass.Infrastucture.12/ModernKeePass.Infrastructure.csproj new file mode 100644 index 0000000..a4a5bf1 --- /dev/null +++ b/ModernKeePass.Infrastucture.12/ModernKeePass.Infrastructure.csproj @@ -0,0 +1,24 @@ + + + + netstandard1.2 + + + + + + + + + + + + + + + Libs\Windows.winmd + true + + + + diff --git a/ModernKeePass.Infrastucture.12/UWP/StorageFileClient.cs b/ModernKeePass.Infrastucture.12/UWP/StorageFileClient.cs new file mode 100644 index 0000000..4337d42 --- /dev/null +++ b/ModernKeePass.Infrastucture.12/UWP/StorageFileClient.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Threading.Tasks; +using Windows.Storage; +using Windows.Storage.AccessCache; +using ModernKeePass.Application.Common.Interfaces; + +namespace ModernKeePass.Infrastructure.UWP +{ + public class StorageFileClient: IFileProxy + { + public async Task OpenBinaryFile(string path) + { + var file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(path); + var result = await FileIO.ReadBufferAsync(file); + return result.ToArray(); + } + + public async Task> OpenTextFile(string path) + { + var file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(path); + var result = await FileIO.ReadLinesAsync(file); + return result; + } + + public void ReleaseFile(string path) + { + StorageApplicationPermissions.FutureAccessList.Remove(path); + } + + public async Task WriteBinaryContentsToFile(string path, byte[] contents) + { + var file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(path); + await FileIO.WriteBytesAsync(file, contents); + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastucture.12/UWP/UwpRecentFilesClient.cs b/ModernKeePass.Infrastucture.12/UWP/UwpRecentFilesClient.cs new file mode 100644 index 0000000..7dd750a --- /dev/null +++ b/ModernKeePass.Infrastucture.12/UWP/UwpRecentFilesClient.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Windows.Storage.AccessCache; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Dtos; + +namespace ModernKeePass.Infrastructure.UWP +{ + public class UwpRecentFilesClient: IRecentProxy + { + private readonly StorageItemMostRecentlyUsedList _mru = StorageApplicationPermissions.MostRecentlyUsedList; + + public int EntryCount => _mru.Entries.Count; + + public async Task Get(string token) + { + var recentEntry = _mru.Entries.FirstOrDefault(e => e.Token == token); + var file = await _mru.GetFileAsync(token); + StorageApplicationPermissions.FutureAccessList.AddOrReplace(recentEntry.Metadata, file); + return new FileInfo + { + Name = file.DisplayName, + Path = recentEntry.Metadata + }; + } + + public async Task> GetAll() + { + var result = new List(); + foreach (var entry in _mru.Entries) + { + try + { + var recentItem = await Get(entry.Token); + result.Add(recentItem); + } + catch (Exception) + { + _mru.Remove(entry.Token); + } + } + return result; + } + + public async Task Add(FileInfo recentItem) + { + var file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(recentItem.Path); + _mru.Add(file, recentItem.Path); + } + + public void ClearAll() + { + for (var i = _mru.Entries.Count; i > 0; i--) + { + var entry = _mru.Entries[i]; + StorageApplicationPermissions.FutureAccessList.Remove(entry.Metadata); + _mru.Remove(entry.Token); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastucture.12/UWP/UwpResourceClient.cs b/ModernKeePass.Infrastucture.12/UWP/UwpResourceClient.cs new file mode 100644 index 0000000..6ddf960 --- /dev/null +++ b/ModernKeePass.Infrastucture.12/UWP/UwpResourceClient.cs @@ -0,0 +1,17 @@ +using Windows.ApplicationModel.Resources; +using ModernKeePass.Application.Common.Interfaces; + +namespace ModernKeePass.Infrastructure.UWP +{ + public class UwpResourceClient: IResourceProxy + { + private const string ResourceFileName = "CodeBehind"; + private readonly ResourceLoader _resourceLoader = ResourceLoader.GetForCurrentView(); + + public string GetResourceValue(string key) + { + var resource = _resourceLoader.GetString($"/{ResourceFileName}/{key}"); + return resource; + } + } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastucture.12/UWP/UwpSettingsClient.cs b/ModernKeePass.Infrastucture.12/UWP/UwpSettingsClient.cs new file mode 100644 index 0000000..612f1d7 --- /dev/null +++ b/ModernKeePass.Infrastucture.12/UWP/UwpSettingsClient.cs @@ -0,0 +1,31 @@ +using System; +using Windows.Foundation.Collections; +using Windows.Storage; +using ModernKeePass.Application.Common.Interfaces; + +namespace ModernKeePass.Infrastructure.UWP +{ + public class UwpSettingsClient : ISettingsProxy + { + private readonly IPropertySet _values = ApplicationData.Current.LocalSettings.Values; + + public T GetSetting(string property, T defaultValue = default) + { + try + { + return (T)Convert.ChangeType(_values[property], typeof(T)); + } + catch (InvalidCastException) + { + return defaultValue; + } + } + + public void PutSetting(string property, T value) + { + if (_values.ContainsKey(property)) + _values[property] = value; + else _values.Add(property, value); + } + } +} diff --git a/ModernKeePass.sln b/ModernKeePass.sln index 9c214f3..e1f0c0b 100644 --- a/ModernKeePass.sln +++ b/ModernKeePass.sln @@ -5,12 +5,27 @@ VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.App", "ModernKeePass\ModernKeePass.App.csproj", "{A0CFC681-769B-405A-8482-0CDEE595A91F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.Lib", "ModernKeePassLib\ModernKeePass.Lib.csproj", "{2E710089-9559-4967-846C-E763DD1F3ACB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.LibTest", "ModernKeePassLib.Test\ModernKeePass.LibTest.csproj", "{0A4279CF-2A67-4868-9906-052E50C25F3B}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.AppTest", "ModernKeePassApp.Test\ModernKeePass.AppTest.csproj", "{7E80F5E7-724A-4668-9333-B10F5D75C6D0}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{107C7C00-56F4-41B0-A8CC-0156C46A3650}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution items", "solution items", "{3779FC26-0435-4823-81F5-3F27A525E991}" + ProjectSection(SolutionItems) = preProject + PRIVACY = PRIVACY + README.md = README.md + UpdateVersion.ps1 = UpdateVersion.ps1 + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0B30588B-07B8-4A88-A268-F58D06EA1627}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "presentation", "presentation", "{C7DB9A6F-77A8-4FE5-83CB-9C11F7100647}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.Application", "ModernKeePass.Application\ModernKeePass.Application.csproj", "{42353562-5E43-459C-8E3E-2F21E575261D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.Domain", "ModernKeePass.Domain\ModernKeePass.Domain.csproj", "{9A0759F1-9069-4841-99E3-3BEC44E17356}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.Infrastructure", "ModernKeePass.Infrastructure\ModernKeePass.Infrastructure.csproj", "{09577E4C-4899-45B9-BF80-1803D617CCAE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -47,46 +62,6 @@ Global {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|x86.ActiveCfg = Release|x86 {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|x86.Build.0 = Release|x86 {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|x86.Deploy.0 = Release|x86 - {2E710089-9559-4967-846C-E763DD1F3ACB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Debug|ARM.ActiveCfg = Debug|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Debug|ARM.Build.0 = Debug|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Debug|x64.ActiveCfg = Debug|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Debug|x64.Build.0 = Debug|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Debug|x86.ActiveCfg = Debug|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Debug|x86.Build.0 = Debug|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Release|Any CPU.Build.0 = Release|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Release|ARM.ActiveCfg = Release|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Release|ARM.Build.0 = Release|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Release|x64.ActiveCfg = Release|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Release|x64.Build.0 = Release|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Release|x86.ActiveCfg = Release|Any CPU - {2E710089-9559-4967-846C-E763DD1F3ACB}.Release|x86.Build.0 = Release|Any CPU - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|ARM.ActiveCfg = Debug|ARM - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|ARM.Build.0 = Debug|ARM - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|ARM.Deploy.0 = Debug|ARM - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|x64.ActiveCfg = Debug|x64 - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|x64.Build.0 = Debug|x64 - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|x64.Deploy.0 = Debug|x64 - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|x86.ActiveCfg = Debug|x86 - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|x86.Build.0 = Debug|x86 - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Debug|x86.Deploy.0 = Debug|x86 - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|Any CPU.Build.0 = Release|Any CPU - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|Any CPU.Deploy.0 = Release|Any CPU - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|ARM.ActiveCfg = Release|ARM - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|ARM.Build.0 = Release|ARM - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|ARM.Deploy.0 = Release|ARM - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x64.ActiveCfg = Release|x64 - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x64.Build.0 = Release|x64 - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x64.Deploy.0 = Release|x64 - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.ActiveCfg = Release|x86 - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.Build.0 = Release|x86 - {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.Deploy.0 = Release|x86 {7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.Build.0 = Debug|Any CPU {7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU @@ -111,8 +86,67 @@ Global {7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|x86.ActiveCfg = Release|x86 {7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|x86.Build.0 = Release|x86 {7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|x86.Deploy.0 = Release|x86 + {42353562-5E43-459C-8E3E-2F21E575261D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Debug|ARM.ActiveCfg = Debug|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Debug|ARM.Build.0 = Debug|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Debug|x64.ActiveCfg = Debug|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Debug|x64.Build.0 = Debug|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Debug|x86.ActiveCfg = Debug|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Debug|x86.Build.0 = Debug|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Release|Any CPU.Build.0 = Release|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Release|ARM.ActiveCfg = Release|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Release|ARM.Build.0 = Release|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Release|x64.ActiveCfg = Release|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Release|x64.Build.0 = Release|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Release|x86.ActiveCfg = Release|Any CPU + {42353562-5E43-459C-8E3E-2F21E575261D}.Release|x86.Build.0 = Release|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Debug|ARM.ActiveCfg = Debug|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Debug|ARM.Build.0 = Debug|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Debug|x64.ActiveCfg = Debug|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Debug|x64.Build.0 = Debug|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Debug|x86.ActiveCfg = Debug|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Debug|x86.Build.0 = Debug|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Release|Any CPU.Build.0 = Release|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Release|ARM.ActiveCfg = Release|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Release|ARM.Build.0 = Release|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Release|x64.ActiveCfg = Release|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Release|x64.Build.0 = Release|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Release|x86.ActiveCfg = Release|Any CPU + {9A0759F1-9069-4841-99E3-3BEC44E17356}.Release|x86.Build.0 = Release|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Debug|ARM.ActiveCfg = Debug|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Debug|ARM.Build.0 = Debug|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Debug|x64.ActiveCfg = Debug|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Debug|x64.Build.0 = Debug|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Debug|x86.ActiveCfg = Debug|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Debug|x86.Build.0 = Debug|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Release|Any CPU.Build.0 = Release|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Release|ARM.ActiveCfg = Release|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Release|ARM.Build.0 = Release|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Release|x64.ActiveCfg = Release|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Release|x64.Build.0 = Release|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Release|x86.ActiveCfg = Release|Any CPU + {09577E4C-4899-45B9-BF80-1803D617CCAE}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {A0CFC681-769B-405A-8482-0CDEE595A91F} = {C7DB9A6F-77A8-4FE5-83CB-9C11F7100647} + {7E80F5E7-724A-4668-9333-B10F5D75C6D0} = {107C7C00-56F4-41B0-A8CC-0156C46A3650} + {C7DB9A6F-77A8-4FE5-83CB-9C11F7100647} = {0B30588B-07B8-4A88-A268-F58D06EA1627} + {42353562-5E43-459C-8E3E-2F21E575261D} = {0B30588B-07B8-4A88-A268-F58D06EA1627} + {9A0759F1-9069-4841-99E3-3BEC44E17356} = {0B30588B-07B8-4A88-A268-F58D06EA1627} + {09577E4C-4899-45B9-BF80-1803D617CCAE} = {0B30588B-07B8-4A88-A268-F58D06EA1627} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0ADC1BC6-B1CA-427D-A97C-3CA40AAB0428} + EndGlobalSection EndGlobal diff --git a/ModernKeePass/Interfaces/IDatabaseService.cs b/ModernKeePass/Interfaces/IDatabaseService.cs index f527c3b..6931207 100644 --- a/ModernKeePass/Interfaces/IDatabaseService.cs +++ b/ModernKeePass/Interfaces/IDatabaseService.cs @@ -1,4 +1,5 @@ -using Windows.Storage; +using System.Threading.Tasks; +using Windows.Storage; using ModernKeePass.ViewModels; using ModernKeePassLib; using ModernKeePassLib.Cryptography.KeyDerivation; @@ -18,10 +19,10 @@ namespace ModernKeePass.Interfaces bool IsOpen { get; } bool HasChanged { get; set; } - void Open(StorageFile databaseFile, CompositeKey key, bool createNew = false); + Task Open(StorageFile databaseFile, CompositeKey key, bool createNew = false); void ReOpen(); void Save(); - void Save(StorageFile file); + Task Save(StorageFile file); void CreateRecycleBin(string title); void AddDeletedItem(PwUuid id); void Close(bool releaseFile = true); diff --git a/ModernKeePass/ModernKeePass.App.csproj b/ModernKeePass/ModernKeePass.App.csproj index 725b170..7027814 100644 --- a/ModernKeePass/ModernKeePass.App.csproj +++ b/ModernKeePass/ModernKeePass.App.csproj @@ -393,8 +393,8 @@ - - ..\packages\Portable.BouncyCastle.1.8.3\lib\netstandard1.0\BouncyCastle.Crypto.dll + + ..\packages\Portable.BouncyCastle.1.8.5\lib\netstandard1.0\BouncyCastle.Crypto.dll True @@ -409,52 +409,56 @@ ..\packages\Microsoft.Toolkit.Uwp.Notifications.2.0.0\lib\dotnet\Microsoft.Toolkit.Uwp.Notifications.dll True - - ..\packages\ModernKeePassLib.2.39.1\lib\netstandard1.2\ModernKeePassLib.dll + + ..\packages\ModernKeePassLib.2.44.1\lib\netstandard1.2\ModernKeePassLib.dll + True + + + ..\packages\SixLabors.Core.1.0.0-beta0006\lib\netstandard1.1\SixLabors.Core.dll + True + + + ..\packages\SixLabors.ImageSharp.1.0.0-beta0005\lib\netstandard1.1\SixLabors.ImageSharp.dll True ..\packages\Splat.3.0.0\lib\netstandard1.1\Splat.dll True + + ..\packages\System.Buffers.4.5.0\lib\netstandard1.1\System.Buffers.dll + True + ..\packages\System.Collections.Immutable.1.5.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll True - - ..\packages\System.Composition.AttributedModel.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll - True - - - ..\packages\System.Composition.Convention.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll - True - - - ..\packages\System.Composition.Hosting.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll - True - - - ..\packages\System.Composition.Runtime.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll - True - - - ..\packages\System.Composition.TypedParts.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll - True - ..\packages\System.Drawing.Primitives.4.3.0\lib\netstandard1.1\System.Drawing.Primitives.dll True + + ..\packages\System.Memory.4.5.1\lib\netstandard1.1\System.Memory.dll + True + + + ..\packages\System.Numerics.Vectors.4.4.0\lib\portable-net45+win8+wp8+wpa81\System.Numerics.Vectors.dll + True + ..\packages\System.Reflection.Metadata.1.6.0\lib\portable-net45+win8\System.Reflection.Metadata.dll True + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.1\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll + True + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\win8\System.Runtime.InteropServices.RuntimeInformation.dll True - - ..\packages\Validation.2.4.18\lib\portable-net45+win8+wp8+wpa81\Validation.dll + + ..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll True diff --git a/ModernKeePass/Services/DatabaseService.cs b/ModernKeePass/Services/DatabaseService.cs index edc4cc9..f79bbc3 100644 --- a/ModernKeePass/Services/DatabaseService.cs +++ b/ModernKeePass/Services/DatabaseService.cs @@ -1,4 +1,6 @@ using System; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Threading.Tasks; using Windows.Storage; using Microsoft.HockeyApp; using ModernKeePass.Exceptions; @@ -80,7 +82,7 @@ namespace ModernKeePass.Services /// The database composite key /// True to create a new database before opening it /// An error message, if any - public void Open(StorageFile databaseFile, CompositeKey key, bool createNew = false) + public async Task Open(StorageFile databaseFile, CompositeKey key, bool createNew = false) { try { @@ -94,7 +96,8 @@ namespace ModernKeePass.Services } _compositeKey = key; - var ioConnection = IOConnectionInfo.FromFile(databaseFile); + var fileContents = await FileIO.ReadBufferAsync(databaseFile); + var ioConnection = IOConnectionInfo.FromByteArray(fileContents.ToArray()); if (createNew) { _pwDatabase.New(ioConnection, key); @@ -144,13 +147,14 @@ namespace ModernKeePass.Services /// Save the current database to another file and open it /// /// The new database file - public void Save(StorageFile file) + public async Task Save(StorageFile file) { var oldFile = _databaseFile; _databaseFile = file; try { - _pwDatabase.SaveAs(IOConnectionInfo.FromFile(_databaseFile), true, new NullStatusLogger()); + var fileContents = await FileIO.ReadBufferAsync(file); + _pwDatabase.SaveAs(IOConnectionInfo.FromByteArray(fileContents.ToArray()), true, new NullStatusLogger()); } catch { diff --git a/ModernKeePass/ViewModels/CompositeKeyVm.cs b/ModernKeePass/ViewModels/CompositeKeyVm.cs index f6e7437..6bf5ac4 100644 --- a/ModernKeePass/ViewModels/CompositeKeyVm.cs +++ b/ModernKeePass/ViewModels/CompositeKeyVm.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.InteropServices.WindowsRuntime; using System.Text; using System.Threading.Tasks; using Windows.Storage; @@ -126,7 +127,7 @@ namespace ModernKeePass.ViewModels { _isOpening = true; OnPropertyChanged("IsValid"); - Database.Open(databaseFile, CreateCompositeKey(), createNew); + await Database.Open(databaseFile, await CreateCompositeKey(), createNew); await Task.Run(() => RootGroup = Database.RootGroup); return true; } @@ -151,16 +152,17 @@ namespace ModernKeePass.ViewModels return false; } - public void UpdateKey() + public async Task UpdateKey() { - Database.UpdateCompositeKey(CreateCompositeKey()); + Database.UpdateCompositeKey(await CreateCompositeKey()); UpdateStatus(_resource.GetResourceValue("CompositeKeyUpdated"), StatusTypes.Success); } - public void CreateKeyFile(StorageFile file) + public async Task CreateKeyFile(StorageFile file) { // TODO: implement entropy generator - KcpKeyFile.Create(file, null); + var fileContents = await FileIO.ReadBufferAsync(file); + KcpKeyFile.Create(fileContents.ToArray()); KeyFile = file; } @@ -170,11 +172,15 @@ namespace ModernKeePass.ViewModels StatusType = (int)type; } - private CompositeKey CreateCompositeKey() + private async Task CreateCompositeKey() { var compositeKey = new CompositeKey(); if (HasPassword) compositeKey.AddUserKey(new KcpPassword(Password)); - if (HasKeyFile && KeyFile != null) compositeKey.AddUserKey(new KcpKeyFile(IOConnectionInfo.FromFile(KeyFile))); + if (HasKeyFile && KeyFile != null) + { + var fileContents = await FileIO.ReadBufferAsync(KeyFile); + compositeKey.AddUserKey(new KcpKeyFile(IOConnectionInfo.FromByteArray(fileContents.ToArray()))); + } if (HasUserAccount) compositeKey.AddUserKey(new KcpUserAccount()); return compositeKey; } diff --git a/ModernKeePass/packages.config b/ModernKeePass/packages.config index 87f3852..13303fe 100644 --- a/ModernKeePass/packages.config +++ b/ModernKeePass/packages.config @@ -3,35 +3,35 @@ - - + - + - + + + + - - - - - - + + + + @@ -39,7 +39,7 @@ - + + - \ No newline at end of file diff --git a/ModernKeePassLib.Test/Cryptography/Cipher/Chacha20Tests.cs b/ModernKeePassLib.Test/Cryptography/Cipher/Chacha20Tests.cs deleted file mode 100644 index de211be..0000000 --- a/ModernKeePassLib.Test/Cryptography/Cipher/Chacha20Tests.cs +++ /dev/null @@ -1,204 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Cryptography.Cipher; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Cryptography.Cipher -{ - [TestClass] - public class Chacha20Tests - { - [TestMethod] - public void TestChacha20() - { - // ====================================================== - // Test vector from RFC 7539, section 2.3.2 - - byte[] pbKey = new byte[32]; - for (int i = 0; i < 32; ++i) pbKey[i] = (byte)i; - - byte[] pbIV = new byte[12]; - pbIV[3] = 0x09; - pbIV[7] = 0x4A; - - byte[] pbExpc = new byte[64] { - 0x10, 0xF1, 0xE7, 0xE4, 0xD1, 0x3B, 0x59, 0x15, - 0x50, 0x0F, 0xDD, 0x1F, 0xA3, 0x20, 0x71, 0xC4, - 0xC7, 0xD1, 0xF4, 0xC7, 0x33, 0xC0, 0x68, 0x03, - 0x04, 0x22, 0xAA, 0x9A, 0xC3, 0xD4, 0x6C, 0x4E, - 0xD2, 0x82, 0x64, 0x46, 0x07, 0x9F, 0xAA, 0x09, - 0x14, 0xC2, 0xD7, 0x05, 0xD9, 0x8B, 0x02, 0xA2, - 0xB5, 0x12, 0x9C, 0xD1, 0xDE, 0x16, 0x4E, 0xB9, - 0xCB, 0xD0, 0x83, 0xE8, 0xA2, 0x50, 0x3C, 0x4E - }; - - byte[] pb = new byte[64]; - - using (ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV)) - { - c.Seek(64, SeekOrigin.Begin); // Skip first block - c.Encrypt(pb, 0, pb.Length); - - Assert.IsTrue(MemUtil.ArraysEqual(pb, pbExpc)); - } - -#if DEBUG - // ====================================================== - // Test vector from RFC 7539, section 2.4.2 - - pbIV[3] = 0; - - pb = StrUtil.Utf8.GetBytes("Ladies and Gentlemen of the clas" + - @"s of '99: If I could offer you only one tip for " + - @"the future, sunscreen would be it."); - - pbExpc = new byte[] { - 0x6E, 0x2E, 0x35, 0x9A, 0x25, 0x68, 0xF9, 0x80, - 0x41, 0xBA, 0x07, 0x28, 0xDD, 0x0D, 0x69, 0x81, - 0xE9, 0x7E, 0x7A, 0xEC, 0x1D, 0x43, 0x60, 0xC2, - 0x0A, 0x27, 0xAF, 0xCC, 0xFD, 0x9F, 0xAE, 0x0B, - 0xF9, 0x1B, 0x65, 0xC5, 0x52, 0x47, 0x33, 0xAB, - 0x8F, 0x59, 0x3D, 0xAB, 0xCD, 0x62, 0xB3, 0x57, - 0x16, 0x39, 0xD6, 0x24, 0xE6, 0x51, 0x52, 0xAB, - 0x8F, 0x53, 0x0C, 0x35, 0x9F, 0x08, 0x61, 0xD8, - 0x07, 0xCA, 0x0D, 0xBF, 0x50, 0x0D, 0x6A, 0x61, - 0x56, 0xA3, 0x8E, 0x08, 0x8A, 0x22, 0xB6, 0x5E, - 0x52, 0xBC, 0x51, 0x4D, 0x16, 0xCC, 0xF8, 0x06, - 0x81, 0x8C, 0xE9, 0x1A, 0xB7, 0x79, 0x37, 0x36, - 0x5A, 0xF9, 0x0B, 0xBF, 0x74, 0xA3, 0x5B, 0xE6, - 0xB4, 0x0B, 0x8E, 0xED, 0xF2, 0x78, 0x5E, 0x42, - 0x87, 0x4D - }; - - byte[] pb64 = new byte[64]; - - using (ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV)) - { - c.Encrypt(pb64, 0, pb64.Length); // Skip first block - c.Encrypt(pb, 0, pb.Length); - - Assert.IsTrue(MemUtil.ArraysEqual(pb, pbExpc)); - } - - // ====================================================== - // Test vector from RFC 7539, appendix A.2 #2 - - Array.Clear(pbKey, 0, pbKey.Length); - pbKey[31] = 1; - - Array.Clear(pbIV, 0, pbIV.Length); - pbIV[11] = 2; - - pb = StrUtil.Utf8.GetBytes("Any submission to the IETF inten" + - "ded by the Contributor for publication as all or" + - " part of an IETF Internet-Draft or RFC and any s" + - "tatement made within the context of an IETF acti" + - "vity is considered an \"IETF Contribution\". Such " + - "statements include oral statements in IETF sessi" + - "ons, as well as written and electronic communica" + - "tions made at any time or place, which are addressed to"); - - pbExpc = MemUtil.HexStringToByteArray( - "A3FBF07DF3FA2FDE4F376CA23E82737041605D9F4F4F57BD8CFF2C1D4B7955EC" + - "2A97948BD3722915C8F3D337F7D370050E9E96D647B7C39F56E031CA5EB6250D" + - "4042E02785ECECFA4B4BB5E8EAD0440E20B6E8DB09D881A7C6132F420E527950" + - "42BDFA7773D8A9051447B3291CE1411C680465552AA6C405B7764D5E87BEA85A" + - "D00F8449ED8F72D0D662AB052691CA66424BC86D2DF80EA41F43ABF937D3259D" + - "C4B2D0DFB48A6C9139DDD7F76966E928E635553BA76C5C879D7B35D49EB2E62B" + - "0871CDAC638939E25E8A1E0EF9D5280FA8CA328B351C3C765989CBCF3DAA8B6C" + - "CC3AAF9F3979C92B3720FC88DC95ED84A1BE059C6499B9FDA236E7E818B04B0B" + - "C39C1E876B193BFE5569753F88128CC08AAA9B63D1A16F80EF2554D7189C411F" + - "5869CA52C5B83FA36FF216B9C1D30062BEBCFD2DC5BCE0911934FDA79A86F6E6" + - "98CED759C3FF9B6477338F3DA4F9CD8514EA9982CCAFB341B2384DD902F3D1AB" + - "7AC61DD29C6F21BA5B862F3730E37CFDC4FD806C22F221"); - - using (MemoryStream msEnc = new MemoryStream()) - { - using (ChaCha20Stream c = new ChaCha20Stream(msEnc, true, pbKey, pbIV)) - { - Random r = CryptoRandom.NewWeakRandom(); - r.NextBytes(pb64); - c.Write(pb64, 0, pb64.Length); // Skip first block - - int p = 0; - while (p < pb.Length) - { - int cb = r.Next(1, pb.Length - p + 1); - c.Write(pb, p, cb); - p += cb; - } - Debug.Assert(p == pb.Length); - } - - byte[] pbEnc0 = msEnc.ToArray(); - byte[] pbEnc = MemUtil.Mid(pbEnc0, 64, pbEnc0.Length - 64); - Assert.IsTrue(MemUtil.ArraysEqual(pbEnc, pbExpc)); - - using (MemoryStream msCT = new MemoryStream(pbEnc0, false)) - { - using (ChaCha20Stream cDec = new ChaCha20Stream(msCT, false, - pbKey, pbIV)) - { - byte[] pbPT = MemUtil.Read(cDec, pbEnc0.Length); - - Assert.IsTrue(cDec.ReadByte() < 0); - Assert.IsTrue(MemUtil.ArraysEqual(MemUtil.Mid(pbPT, 0, 64), pb64)); - Assert.IsTrue(MemUtil.ArraysEqual(MemUtil.Mid(pbPT, 64, pbEnc.Length), pb)); - } - } - } - - // ====================================================== - // Test vector TC8 from RFC draft by J. Strombergson: - // https://tools.ietf.org/html/draft-strombergson-chacha-test-vectors-01 - - pbKey = new byte[32] { - 0xC4, 0x6E, 0xC1, 0xB1, 0x8C, 0xE8, 0xA8, 0x78, - 0x72, 0x5A, 0x37, 0xE7, 0x80, 0xDF, 0xB7, 0x35, - 0x1F, 0x68, 0xED, 0x2E, 0x19, 0x4C, 0x79, 0xFB, - 0xC6, 0xAE, 0xBE, 0xE1, 0xA6, 0x67, 0x97, 0x5D - }; - - // The first 4 bytes are set to zero and a large counter - // is used; this makes the RFC 7539 version of ChaCha20 - // compatible with the original specification by - // D. J. Bernstein. - pbIV = new byte[12] { 0x00, 0x00, 0x00, 0x00, - 0x1A, 0xDA, 0x31, 0xD5, 0xCF, 0x68, 0x82, 0x21 - }; - - pb = new byte[128]; - - pbExpc = new byte[128] { - 0xF6, 0x3A, 0x89, 0xB7, 0x5C, 0x22, 0x71, 0xF9, - 0x36, 0x88, 0x16, 0x54, 0x2B, 0xA5, 0x2F, 0x06, - 0xED, 0x49, 0x24, 0x17, 0x92, 0x30, 0x2B, 0x00, - 0xB5, 0xE8, 0xF8, 0x0A, 0xE9, 0xA4, 0x73, 0xAF, - 0xC2, 0x5B, 0x21, 0x8F, 0x51, 0x9A, 0xF0, 0xFD, - 0xD4, 0x06, 0x36, 0x2E, 0x8D, 0x69, 0xDE, 0x7F, - 0x54, 0xC6, 0x04, 0xA6, 0xE0, 0x0F, 0x35, 0x3F, - 0x11, 0x0F, 0x77, 0x1B, 0xDC, 0xA8, 0xAB, 0x92, - - 0xE5, 0xFB, 0xC3, 0x4E, 0x60, 0xA1, 0xD9, 0xA9, - 0xDB, 0x17, 0x34, 0x5B, 0x0A, 0x40, 0x27, 0x36, - 0x85, 0x3B, 0xF9, 0x10, 0xB0, 0x60, 0xBD, 0xF1, - 0xF8, 0x97, 0xB6, 0x29, 0x0F, 0x01, 0xD1, 0x38, - 0xAE, 0x2C, 0x4C, 0x90, 0x22, 0x5B, 0xA9, 0xEA, - 0x14, 0xD5, 0x18, 0xF5, 0x59, 0x29, 0xDE, 0xA0, - 0x98, 0xCA, 0x7A, 0x6C, 0xCF, 0xE6, 0x12, 0x27, - 0x05, 0x3C, 0x84, 0xE4, 0x9A, 0x4A, 0x33, 0x32 - }; - - using (ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV, true)) - { - c.Decrypt(pb, 0, pb.Length); - - Assert.IsTrue(MemUtil.ArraysEqual(pb, pbExpc)); - } -#endif - } - } -} \ No newline at end of file diff --git a/ModernKeePassLib.Test/Cryptography/Cipher/StandardAesEngineTests.cs b/ModernKeePassLib.Test/Cryptography/Cipher/StandardAesEngineTests.cs deleted file mode 100644 index 0719418..0000000 --- a/ModernKeePassLib.Test/Cryptography/Cipher/StandardAesEngineTests.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.IO; -using System.Text; -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Serialization; -using ModernKeePassLib.Cryptography.Cipher; -using ModernKeePassLib.Utility; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Parameters; - -namespace ModernKeePassLib.Test.Cryptography.Cipher -{ - [TestClass()] - public class StandardAesEngineTests - { - // Test vector (official ECB test vector #356) - private readonly byte[] _pbReferenceCt = - { - 0x75, 0xD1, 0x1B, 0x0E, 0x3A, 0x68, 0xC4, 0x22, - 0x3D, 0x88, 0xDB, 0xF0, 0x17, 0x97, 0x7D, 0xD7 - }; - private readonly byte[] _pbIv = new byte[16]; - private readonly byte[] _pbTestKey = new byte[32]; - private readonly byte[] _pbTestData = - { - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - [TestMethod] - public void TestEncryptStream() - { - using (var outStream = new MemoryStream(new byte[16])) - { - var aes = new StandardAesEngine(); - using (var inStream = aes.EncryptStream(outStream, _pbTestKey, _pbIv)) - { - new BinaryWriter(inStream).Write(_pbTestData); - Assert.AreEqual(16, outStream.Position); - outStream.Position = 0; - var outBytes = new BinaryReaderEx(outStream, Encoding.UTF8, string.Empty).ReadBytes(16); - Assert.IsTrue(MemUtil.ArraysEqual(outBytes, _pbReferenceCt)); - } - } - } - - [TestMethod] - public void TestDecryptStream() - { - // Possible Mono Bug? This only works with size >= 48 - using (var inStream = new MemoryStream(new byte[32])) - { - inStream.Write(_pbReferenceCt, 0, _pbReferenceCt.Length); - inStream.Position = 0; - var aes = new StandardAesEngine(); - using (var outStream = aes.DecryptStream(inStream, _pbTestKey, _pbIv)) - { - var outBytes = new BinaryReaderEx(outStream, Encoding.UTF8, string.Empty).ReadBytes(16); - Assert.IsTrue(MemUtil.ArraysEqual(outBytes, _pbTestData)); - } - } - } - - [TestMethod] - public void TestBouncyCastleAes() - { - var aesEngine = new AesEngine(); - //var parametersWithIv = new ParametersWithIV(new KeyParameter(pbTestKey), pbIV); - aesEngine.Init(true, new KeyParameter(_pbTestKey)); - Assert.AreEqual(aesEngine.GetBlockSize(), _pbTestData.Length); - aesEngine.ProcessBlock(_pbTestData, 0, _pbTestData, 0); - Assert.IsTrue(MemUtil.ArraysEqual(_pbTestData, _pbReferenceCt)); - } - } -} diff --git a/ModernKeePassLib.Test/Cryptography/CryptoRandomStreamTests.cs b/ModernKeePassLib.Test/Cryptography/CryptoRandomStreamTests.cs deleted file mode 100644 index 1a3a48e..0000000 --- a/ModernKeePassLib.Test/Cryptography/CryptoRandomStreamTests.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; - -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Cryptography -{ - [TestClass] - public class CryptoRandomStreamTests - { - private void TestGetRandomBytes(CryptoRandomStream stream) - { - const uint length = 16; - var bytes1 = stream.GetRandomBytes(length); - Assert.AreEqual(bytes1.Length, (int)length); - var bytes2 = stream.GetRandomBytes(length); - Assert.IsFalse(MemUtil.ArraysEqual(bytes2, bytes1)); - } - - [TestMethod] - public void TestGetRandomBytesCrsAlgorithmSalsa20() - { - var stream = new CryptoRandomStream(CrsAlgorithm.Salsa20, new byte[16]); - TestGetRandomBytes(stream); - } - - [TestMethod] - public void TestGetRandomBytesCrsAlgorithmArcFourVariant() - { - var stream = new CryptoRandomStream(CrsAlgorithm.ArcFourVariant, new byte[16]); - TestGetRandomBytes(stream); - } - - private void TestGetRandomInt64(CryptoRandomStream stream) - { - var value1 = stream.GetRandomUInt64(); - var value2 = stream.GetRandomUInt64(); - Assert.AreNotEqual(value2, value1); - } - - [TestMethod] - public void TestGetRandomInt64AlgorithmSalsa20() - { - var stream = new CryptoRandomStream(CrsAlgorithm.Salsa20, new byte[16]); - TestGetRandomInt64(stream); - } - - [TestMethod] - public void TestGetRandomInt64AlgorithmArcFourVariant() - { - var stream = new CryptoRandomStream(CrsAlgorithm.ArcFourVariant, new byte[16]); - TestGetRandomInt64(stream); - } - } -} - diff --git a/ModernKeePassLib.Test/Cryptography/CryptoRandomTests.cs b/ModernKeePassLib.Test/Cryptography/CryptoRandomTests.cs deleted file mode 100644 index 9a95d2e..0000000 --- a/ModernKeePassLib.Test/Cryptography/CryptoRandomTests.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Cryptography; - -namespace ModernKeePassLib.Test.Cryptography -{ - [TestClass()] - public class CryptoRandomTests - { - [TestMethod] - public void TestAddEntropy() - { - // just making sure it does not throw an exception - CryptoRandom.Instance.AddEntropy(new byte[1]); - } - - [TestMethod] - public void TestGetRandomBytes() - { - const int length = 32; - var bytes1 = CryptoRandom.Instance.GetRandomBytes(length); - Assert.AreEqual(bytes1.Length, length); - var bytes2 = CryptoRandom.Instance.GetRandomBytes(length); - Assert.AreNotEqual(bytes2, bytes1); - } - - [TestMethod] - public void TestGeneratedBytesCount() - { - const int length = 1; - CryptoRandom.Instance.GetRandomBytes(length); - var count1 = CryptoRandom.Instance.GeneratedBytesCount; - CryptoRandom.Instance.GetRandomBytes(length); - var count2 = CryptoRandom.Instance.GeneratedBytesCount; - Assert.IsTrue(count2 > count1); - } - } -} - diff --git a/ModernKeePassLib.Test/Cryptography/Hash/Blake2bTests.cs b/ModernKeePassLib.Test/Cryptography/Hash/Blake2bTests.cs deleted file mode 100644 index fc0fc25..0000000 --- a/ModernKeePassLib.Test/Cryptography/Hash/Blake2bTests.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using System.Text; -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Cryptography.Hash; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Cryptography.Hash -{ - [TestClass] - public class Blake2bTests - { - [TestMethod] - public void TestBlake2bUtf8() - { - Blake2b h = new Blake2b(); - - // ====================================================== - // From https://tools.ietf.org/html/rfc7693 - - byte[] pbData = StrUtil.Utf8.GetBytes("abc"); - byte[] pbExpc = new byte[64] - { - 0xBA, 0x80, 0xA5, 0x3F, 0x98, 0x1C, 0x4D, 0x0D, - 0x6A, 0x27, 0x97, 0xB6, 0x9F, 0x12, 0xF6, 0xE9, - 0x4C, 0x21, 0x2F, 0x14, 0x68, 0x5A, 0xC4, 0xB7, - 0x4B, 0x12, 0xBB, 0x6F, 0xDB, 0xFF, 0xA2, 0xD1, - 0x7D, 0x87, 0xC5, 0x39, 0x2A, 0xAB, 0x79, 0x2D, - 0xC2, 0x52, 0xD5, 0xDE, 0x45, 0x33, 0xCC, 0x95, - 0x18, 0xD3, 0x8A, 0xA8, 0xDB, 0xF1, 0x92, 0x5A, - 0xB9, 0x23, 0x86, 0xED, 0xD4, 0x00, 0x99, 0x23 - }; - - byte[] pbC = h.ComputeHash(pbData); - Assert.IsTrue(MemUtil.ArraysEqual(pbC, pbExpc)); - } - - [TestMethod] - public void TestBlake2bEmpty() - { - // ====================================================== - // Computed using the official b2sum tool - Blake2b h = new Blake2b(); - - var pbExpc = new byte[64] - { - 0x78, 0x6A, 0x02, 0xF7, 0x42, 0x01, 0x59, 0x03, - 0xC6, 0xC6, 0xFD, 0x85, 0x25, 0x52, 0xD2, 0x72, - 0x91, 0x2F, 0x47, 0x40, 0xE1, 0x58, 0x47, 0x61, - 0x8A, 0x86, 0xE2, 0x17, 0xF7, 0x1F, 0x54, 0x19, - 0xD2, 0x5E, 0x10, 0x31, 0xAF, 0xEE, 0x58, 0x53, - 0x13, 0x89, 0x64, 0x44, 0x93, 0x4E, 0xB0, 0x4B, - 0x90, 0x3A, 0x68, 0x5B, 0x14, 0x48, 0xB7, 0x55, - 0xD5, 0x6F, 0x70, 0x1A, 0xFE, 0x9B, 0xE2, 0xCE - }; - - var pbC = h.ComputeHash(new byte[0]); - Assert.IsTrue(MemUtil.ArraysEqual(pbC, pbExpc)); - } - - [TestMethod] - public void TestBlake2bString() - { - // ====================================================== - // Computed using the official b2sum tool - Blake2b h = new Blake2b(); - - string strS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:,;_-\r\n"; - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 1000; ++i) sb.Append(strS); - var pbData = StrUtil.Utf8.GetBytes(sb.ToString()); - - var pbExpc = new byte[64] { - 0x59, 0x69, 0x8D, 0x3B, 0x83, 0xF4, 0x02, 0x4E, - 0xD8, 0x99, 0x26, 0x0E, 0xF4, 0xE5, 0x9F, 0x20, - 0xDC, 0x31, 0xEE, 0x5B, 0x45, 0xEA, 0xBB, 0xFC, - 0x1C, 0x0A, 0x8E, 0xED, 0xAA, 0x7A, 0xFF, 0x50, - 0x82, 0xA5, 0x8F, 0xBC, 0x4A, 0x46, 0xFC, 0xC5, - 0xEF, 0x44, 0x4E, 0x89, 0x80, 0x7D, 0x3F, 0x1C, - 0xC1, 0x94, 0x45, 0xBB, 0xC0, 0x2C, 0x95, 0xAA, - 0x3F, 0x08, 0x8A, 0x93, 0xF8, 0x75, 0x91, 0xB0 - }; - - Random r = CryptoRandom.NewWeakRandom(); - int p = 0; - while (p < pbData.Length) - { - int cb = r.Next(1, pbData.Length - p + 1); - h.TransformBlock(pbData, p, cb, pbData, p); - p += cb; - } - Assert.AreEqual(p, pbData.Length); - - h.TransformFinalBlock(new byte[0], 0, 0); - - Assert.IsTrue(MemUtil.ArraysEqual(h.Hash, pbExpc)); - - h.Clear(); - } - } -} \ No newline at end of file diff --git a/ModernKeePassLib.Test/Cryptography/Hash/HmacTests.cs b/ModernKeePassLib.Test/Cryptography/Hash/HmacTests.cs deleted file mode 100644 index 8f42feb..0000000 --- a/ModernKeePassLib.Test/Cryptography/Hash/HmacTests.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Cryptography.Hash; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Cryptography.Hash -{ - [TestClass] - public class HmacTests - { - [TestMethod] - public void TestHmac1() - { - // Test vectors from RFC 4231 - - var pbKey = new byte[20]; - for (var i = 0; i < pbKey.Length; ++i) pbKey[i] = 0x0B; - var pbMsg = StrUtil.Utf8.GetBytes("Hi There"); - var pbExpc = new byte[] - { - 0xB0, 0x34, 0x4C, 0x61, 0xD8, 0xDB, 0x38, 0x53, - 0x5C, 0xA8, 0xAF, 0xCE, 0xAF, 0x0B, 0xF1, 0x2B, - 0x88, 0x1D, 0xC2, 0x00, 0xC9, 0x83, 0x3D, 0xA7, - 0x26, 0xE9, 0x37, 0x6C, 0x2E, 0x32, 0xCF, 0xF7 - }; - HmacEval(pbKey, pbMsg, pbExpc); - } - - [TestMethod] - public void TestHmac2() - { - var pbKey = new byte[131]; - for (var i = 0; i < pbKey.Length; ++i) pbKey[i] = 0xAA; - var pbMsg = StrUtil.Utf8.GetBytes( - "This is a test using a larger than block-size key and " + - "a larger than block-size data. The key needs to be " + - "hashed before being used by the HMAC algorithm."); - var pbExpc = new byte[] { - 0x9B, 0x09, 0xFF, 0xA7, 0x1B, 0x94, 0x2F, 0xCB, - 0x27, 0x63, 0x5F, 0xBC, 0xD5, 0xB0, 0xE9, 0x44, - 0xBF, 0xDC, 0x63, 0x64, 0x4F, 0x07, 0x13, 0x93, - 0x8A, 0x7F, 0x51, 0x53, 0x5C, 0x3A, 0x35, 0xE2 - }; - HmacEval(pbKey, pbMsg, pbExpc); - } - - [TestMethod] - public void TestHmacSha1ComputeHash() - { - var expectedHash = "AC2C2E614882CE7158F69B7E3B12114465945D01"; - var message = StrUtil.Utf8.GetBytes("testing123"); - var key = StrUtil.Utf8.GetBytes("hello"); - using (var result = new HMACSHA1(key)) - { - Assert.AreEqual(ByteToString(result.ComputeHash(message)), expectedHash); - } - } - - [TestMethod] - public void TestHmacSha256ComputeHash() - { - var expectedHash = "09C1BD2DE4E5659C0EFAF9E6AE4723E9CF96B69609B4E562F6AFF1745D7BF4E0"; - var message = StrUtil.Utf8.GetBytes("testing123"); - var key = StrUtil.Utf8.GetBytes("hello"); - using (var result = new HMACSHA256(key)) - { - Assert.AreEqual(ByteToString(result.ComputeHash(message)), expectedHash); - } - } - - private static string ByteToString(byte[] buff) - { - string sbinary = ""; - - for (int i = 0; i < buff.Length; i++) - { - sbinary += buff[i].ToString("X2"); // hex format - } - return (sbinary); - } - - [TestMethod] - public void TestHmacOtp() - { - var pbSecret = StrUtil.Utf8.GetBytes("12345678901234567890"); - var vExp = new []{ "755224", "287082", "359152", - "969429", "338314", "254676", "287922", "162583", "399871", - "520489" }; - - for (var i = 0; i < vExp.Length; ++i) - { - Assert.AreEqual(HmacOtp.Generate(pbSecret, (ulong)i, 6, false, -1), vExp[i]); - } - } - - private static void HmacEval(byte[] pbKey, byte[] pbMsg, - byte[] pbExpc) - { - using (var h = new HMACSHA256(pbKey)) - { - h.TransformBlock(pbMsg, 0, pbMsg.Length, pbMsg, 0); - h.TransformFinalBlock(new byte[0], 0, 0); - - byte[] pbHash = h.Hash; - Assert.IsTrue(MemUtil.ArraysEqual(pbHash, pbExpc)); - - // Reuse the object - h.Initialize(); - h.TransformBlock(pbMsg, 0, pbMsg.Length, pbMsg, 0); - h.TransformFinalBlock(new byte[0], 0, 0); - - pbHash = h.Hash; - Assert.IsTrue(MemUtil.ArraysEqual(pbHash, pbExpc)); - } - } - } -} \ No newline at end of file diff --git a/ModernKeePassLib.Test/Cryptography/Hash/SHAManagedTests.cs b/ModernKeePassLib.Test/Cryptography/Hash/SHAManagedTests.cs deleted file mode 100644 index 7f543b4..0000000 --- a/ModernKeePassLib.Test/Cryptography/Hash/SHAManagedTests.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Cryptography.Hash; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Cryptography.Hash -{ - [TestClass] - public class SHAManagedTests - { - [TestMethod] - public void TestSha256ComputeHash() - { - var expectedHash = "B822F1CD2DCFC685B47E83E3980289FD5D8E3FF3A82DEF24D7D1D68BB272EB32"; - var message = StrUtil.Utf8.GetBytes("testing123"); - using (var result = new SHA256Managed()) - { - Assert.AreEqual(ByteToString(result.ComputeHash(message)), expectedHash); - } - } - - [TestMethod] - public void TestSha512ComputeHash() - { - var expectedHash = "4120117B3190BA5E24044732B0B09AA9ED50EB1567705ABCBFA78431A4E0A96B1152ED7F4925966B1C82325E186A8100E692E6D2FCB6702572765820D25C7E9E"; - var message = StrUtil.Utf8.GetBytes("testing123"); - using (var result = new SHA512Managed()) - { - Assert.AreEqual(ByteToString(result.ComputeHash(message)), expectedHash); - } - } - private static string ByteToString(byte[] buff) - { - string sbinary = ""; - - for (int i = 0; i < buff.Length; i++) - { - sbinary += buff[i].ToString("X2"); // hex format - } - return (sbinary); - } - } -} \ No newline at end of file diff --git a/ModernKeePassLib.Test/Cryptography/HashingStreamExTests.cs b/ModernKeePassLib.Test/Cryptography/HashingStreamExTests.cs deleted file mode 100644 index ad8b0bb..0000000 --- a/ModernKeePassLib.Test/Cryptography/HashingStreamExTests.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System.IO; -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; - -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Cryptography -{ - [TestClass()] - public class HashingStreamExTests - { - const string data = "test"; - - // The expected hash includes the \n added by WriteLine - static readonly byte[] sha256HashOfData = - { - 0xf2, 0xca, 0x1b, 0xb6, 0xc7, 0xe9, 0x07, 0xd0, - 0x6d, 0xaf, 0xe4, 0x68, 0x7e, 0x57, 0x9f, 0xce, - 0x76, 0xb3, 0x7e, 0x4e, 0x93, 0xb7, 0x60, 0x50, - 0x22, 0xda, 0x52, 0xe6, 0xcc, 0xc2, 0x6f, 0xd2 - }; - - [TestMethod] - public void TestRead() - { - // if we use larger size, StreamReader will read past newline and cause bad hash - var bytes = new byte[data.Length + 1]; - using (var ms = new MemoryStream(bytes)) - { - using (var sw = new StreamWriter(ms)) - { - // set NewLine to ensure we don't run into cross-platform issues on Windows - sw.NewLine = "\n"; - sw.WriteLine(data); - } - } - using (var ms = new MemoryStream(bytes)) - { - using (var hs = new HashingStreamEx(ms, false, null)) - { - using (var sr = new StreamReader(hs)) - { - var read = sr.ReadLine(); - Assert.AreEqual(read, data); - } - // When the StreamReader is disposed, it calls Dispose on the - //HasingStreamEx, which computes the hash. - Assert.IsTrue(MemUtil.ArraysEqual(hs.Hash, sha256HashOfData)); - } - } - } - - [TestMethod] - public void TestWrite() - { - var bytes = new byte[16]; - using (var ms = new MemoryStream(bytes)) - { - using (var hs = new HashingStreamEx(ms, true, null)) - { - using (var sw = new StreamWriter(hs)) - { - // set NewLine to ensure we don't run into cross-platform issues on Windows - sw.NewLine = "\n"; - sw.WriteLine(data); - } - // When the StreamWriter is disposed, it calls Dispose on the - //HasingStreamEx, which computes the hash. - Assert.IsTrue(MemUtil.ArraysEqual(hs.Hash, sha256HashOfData)); - } - } - using (var ms = new MemoryStream(bytes)) - { - using (var sr = new StreamReader(ms)) - { - var read = sr.ReadLine(); - Assert.AreEqual(read, data); - } - } - } - } -} - diff --git a/ModernKeePassLib.Test/Cryptography/HmacOtpTests.cs b/ModernKeePassLib.Test/Cryptography/HmacOtpTests.cs deleted file mode 100644 index 6ea1a17..0000000 --- a/ModernKeePassLib.Test/Cryptography/HmacOtpTests.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Text; -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Cryptography; - -namespace ModernKeePassLib.Test.Cryptography -{ - [TestClass()] - public class HmacOtpTests - { - // Using the test case from Appendix D of RFC 4226 - - const string secret = "12345678901234567890"; - - static readonly string[] expectedHOTP = new string[] - { - "755224", "287082", "359152", "969429", "338314", - "254676", "287922", "162583", "399871", "520489" - }; - - [TestMethod] - public void TestGenerate() - { - var secretBytes = Encoding.UTF8.GetBytes(secret); - - for (ulong i = 0; i < 10; i++) - { - var hotp = HmacOtp.Generate(secretBytes, i, 6, false, -1); - Assert.AreEqual(hotp, expectedHOTP[i]); - } - } - } -} diff --git a/ModernKeePassLib.Test/Cryptography/KeyDerivation/AesKdfTests.cs b/ModernKeePassLib.Test/Cryptography/KeyDerivation/AesKdfTests.cs deleted file mode 100644 index 790c1ec..0000000 --- a/ModernKeePassLib.Test/Cryptography/KeyDerivation/AesKdfTests.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Cryptography.KeyDerivation; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Cryptography.KeyDerivation -{ - [TestClass] - public class AesKdfTests - { - [TestMethod] - public void TestAesKdf() - { - // Up to KeePass 2.34, the OtpKeyProv plugin used the public - // CompositeKey.TransformKeyManaged method (and a finalizing - // SHA-256 computation), which became an internal method of - // the AesKdf class in KeePass 2.35, thus OtpKeyProv now - // uses the AesKdf class; here we ensure that the results - // are the same - var r = CryptoRandom.NewWeakRandom(); - var pbKey = new byte[32]; - r.NextBytes(pbKey); - var pbSeed = new byte[32]; - r.NextBytes(pbSeed); - var uRounds = (ulong)r.Next(1, 0x7FFF); - - var pbMan = new byte[pbKey.Length]; - Array.Copy(pbKey, pbMan, pbKey.Length); - Assert.IsTrue(AesKdf.TransformKeyManaged(pbMan, pbSeed, uRounds)); - pbMan = CryptoUtil.HashSha256(pbMan); - - var kdf = new AesKdf(); - var p = kdf.GetDefaultParameters(); - p.SetUInt64(AesKdf.ParamRounds, uRounds); - p.SetByteArray(AesKdf.ParamSeed, pbSeed); - var pbKdf = kdf.Transform(pbKey, p); - - Assert.IsTrue(MemUtil.ArraysEqual(pbMan, pbKdf)); - } - } -} \ No newline at end of file diff --git a/ModernKeePassLib.Test/Cryptography/KeyDerivation/Argon2Tests.cs b/ModernKeePassLib.Test/Cryptography/KeyDerivation/Argon2Tests.cs deleted file mode 100644 index 2b66292..0000000 --- a/ModernKeePassLib.Test/Cryptography/KeyDerivation/Argon2Tests.cs +++ /dev/null @@ -1,146 +0,0 @@ -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Cryptography.KeyDerivation; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Cryptography.KeyDerivation -{ - [TestClass] - public class Argon2Tests - { - [TestMethod] - public void TestArgon2() - { - Argon2Kdf kdf = new Argon2Kdf(); - - // ====================================================== - // From the official Argon2 1.3 reference code package - // (test vector for Argon2d 1.3); also on - // https://tools.ietf.org/html/draft-irtf-cfrg-argon2-00 - - var p = kdf.GetDefaultParameters(); - kdf.Randomize(p); - - Assert.AreEqual(p.GetUInt32(Argon2Kdf.ParamVersion, 0), 0x13U); - - byte[] pbMsg = new byte[32]; - for (int i = 0; i < pbMsg.Length; ++i) pbMsg[i] = 1; - - p.SetUInt64(Argon2Kdf.ParamMemory, 32 * 1024); - p.SetUInt64(Argon2Kdf.ParamIterations, 3); - p.SetUInt32(Argon2Kdf.ParamParallelism, 4); - - byte[] pbSalt = new byte[16]; - for (int i = 0; i < pbSalt.Length; ++i) pbSalt[i] = 2; - p.SetByteArray(Argon2Kdf.ParamSalt, pbSalt); - - byte[] pbKey = new byte[8]; - for (int i = 0; i < pbKey.Length; ++i) pbKey[i] = 3; - p.SetByteArray(Argon2Kdf.ParamSecretKey, pbKey); - - byte[] pbAssoc = new byte[12]; - for (int i = 0; i < pbAssoc.Length; ++i) pbAssoc[i] = 4; - p.SetByteArray(Argon2Kdf.ParamAssocData, pbAssoc); - - byte[] pbExpc = new byte[32] { - 0x51, 0x2B, 0x39, 0x1B, 0x6F, 0x11, 0x62, 0x97, - 0x53, 0x71, 0xD3, 0x09, 0x19, 0x73, 0x42, 0x94, - 0xF8, 0x68, 0xE3, 0xBE, 0x39, 0x84, 0xF3, 0xC1, - 0xA1, 0x3A, 0x4D, 0xB9, 0xFA, 0xBE, 0x4A, 0xCB - }; - - byte[] pb = kdf.Transform(pbMsg, p); - - Assert.IsTrue(MemUtil.ArraysEqual(pb, pbExpc)); - - // ====================================================== - // From the official Argon2 1.3 reference code package - // (test vector for Argon2d 1.0) - - p.SetUInt32(Argon2Kdf.ParamVersion, 0x10); - - pbExpc = new byte[32] { - 0x96, 0xA9, 0xD4, 0xE5, 0xA1, 0x73, 0x40, 0x92, - 0xC8, 0x5E, 0x29, 0xF4, 0x10, 0xA4, 0x59, 0x14, - 0xA5, 0xDD, 0x1F, 0x5C, 0xBF, 0x08, 0xB2, 0x67, - 0x0D, 0xA6, 0x8A, 0x02, 0x85, 0xAB, 0xF3, 0x2B - }; - - pb = kdf.Transform(pbMsg, p); - - Assert.IsTrue(MemUtil.ArraysEqual(pb, pbExpc)); - - // ====================================================== - // From the official 'phc-winner-argon2-20151206.zip' - // (test vector for Argon2d 1.0) - - p.SetUInt64(Argon2Kdf.ParamMemory, 16 * 1024); - - pbExpc = new byte[32] { - 0x57, 0xB0, 0x61, 0x3B, 0xFD, 0xD4, 0x13, 0x1A, - 0x0C, 0x34, 0x88, 0x34, 0xC6, 0x72, 0x9C, 0x2C, - 0x72, 0x29, 0x92, 0x1E, 0x6B, 0xBA, 0x37, 0x66, - 0x5D, 0x97, 0x8C, 0x4F, 0xE7, 0x17, 0x5E, 0xD2 - }; - - pb = kdf.Transform(pbMsg, p); - - Assert.IsTrue(MemUtil.ArraysEqual(pb, pbExpc)); - - // ====================================================== - // Computed using the official 'argon2' application - // (test vectors for Argon2d 1.3) - - p = kdf.GetDefaultParameters(); - - pbMsg = StrUtil.Utf8.GetBytes("ABC1234"); - - p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 11) * 1024); // 2 MB - p.SetUInt64(Argon2Kdf.ParamIterations, 2); - p.SetUInt32(Argon2Kdf.ParamParallelism, 2); - - pbSalt = StrUtil.Utf8.GetBytes("somesalt"); - p.SetByteArray(Argon2Kdf.ParamSalt, pbSalt); - - pbExpc = new byte[32] { - 0x29, 0xCB, 0xD3, 0xA1, 0x93, 0x76, 0xF7, 0xA2, - 0xFC, 0xDF, 0xB0, 0x68, 0xAC, 0x0B, 0x99, 0xBA, - 0x40, 0xAC, 0x09, 0x01, 0x73, 0x42, 0xCE, 0xF1, - 0x29, 0xCC, 0xA1, 0x4F, 0xE1, 0xC1, 0xB7, 0xA3 - }; - - pb = kdf.Transform(pbMsg, p); - - Assert.IsTrue(MemUtil.ArraysEqual(pb, pbExpc)); - - p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 10) * 1024); // 1 MB - p.SetUInt64(Argon2Kdf.ParamIterations, 3); - - pbExpc = new byte[32] { - 0x7A, 0xBE, 0x1C, 0x1C, 0x8D, 0x7F, 0xD6, 0xDC, - 0x7C, 0x94, 0x06, 0x3E, 0xD8, 0xBC, 0xD8, 0x1C, - 0x2F, 0x87, 0x84, 0x99, 0x12, 0x83, 0xFE, 0x76, - 0x00, 0x64, 0xC4, 0x58, 0xA4, 0xDA, 0x35, 0x70 - }; - - pb = kdf.Transform(pbMsg, p); - - Assert.IsTrue(MemUtil.ArraysEqual(pb, pbExpc)); - - // TODO: Out of memory exception - /*p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 20) * 1024); // 1 GB - p.SetUInt64(Argon2Kdf.ParamIterations, 2); - p.SetUInt32(Argon2Kdf.ParamParallelism, 3); - - pbExpc = new byte[32] { - 0xE6, 0xE7, 0xCB, 0xF5, 0x5A, 0x06, 0x93, 0x05, - 0x32, 0xBA, 0x86, 0xC6, 0x1F, 0x45, 0x17, 0x99, - 0x65, 0x41, 0x77, 0xF9, 0x30, 0x55, 0x9A, 0xE8, - 0x3D, 0x21, 0x48, 0xC6, 0x2D, 0x0C, 0x49, 0x11 - }; - - pb = kdf.Transform(pbMsg, p); - - Assert.IsTrue(MemUtil.ArraysEqual(pb, pbExpc));*/ - } - } -} \ No newline at end of file diff --git a/ModernKeePassLib.Test/Images/UnitTestLogo.scale-100.png b/ModernKeePassLib.Test/Images/UnitTestLogo.scale-100.png deleted file mode 100644 index ebd735a..0000000 Binary files a/ModernKeePassLib.Test/Images/UnitTestLogo.scale-100.png and /dev/null differ diff --git a/ModernKeePassLib.Test/Images/UnitTestSmallLogo.scale-100.png b/ModernKeePassLib.Test/Images/UnitTestSmallLogo.scale-100.png deleted file mode 100644 index 92dd105..0000000 Binary files a/ModernKeePassLib.Test/Images/UnitTestSmallLogo.scale-100.png and /dev/null differ diff --git a/ModernKeePassLib.Test/Images/UnitTestSplashScreen.scale-100.png b/ModernKeePassLib.Test/Images/UnitTestSplashScreen.scale-100.png deleted file mode 100644 index 193187f..0000000 Binary files a/ModernKeePassLib.Test/Images/UnitTestSplashScreen.scale-100.png and /dev/null differ diff --git a/ModernKeePassLib.Test/Images/UnitTestStoreLogo.scale-100.png b/ModernKeePassLib.Test/Images/UnitTestStoreLogo.scale-100.png deleted file mode 100644 index 3765186..0000000 Binary files a/ModernKeePassLib.Test/Images/UnitTestStoreLogo.scale-100.png and /dev/null differ diff --git a/ModernKeePassLib.Test/Keys/CompositeKeyTests.cs b/ModernKeePassLib.Test/Keys/CompositeKeyTests.cs deleted file mode 100644 index 4d32a49..0000000 --- a/ModernKeePassLib.Test/Keys/CompositeKeyTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Cryptography.KeyDerivation; -using ModernKeePassLib.Keys; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Keys -{ - [TestClass()] - public class CompositeKeyTests - { - [TestMethod] - public void TestGenerateKey32() - { - var originalKey = new byte[32]; - var expectedKey = new byte[32] - { - 0xF0, 0xED, 0x57, 0xD5, 0xF0, 0xDA, 0xF3, 0x47, - 0x90, 0xD0, 0xDB, 0x43, 0x25, 0xC6, 0x81, 0x2C, - 0x81, 0x6A, 0x0D, 0x94, 0x96, 0xA9, 0x03, 0xE1, - 0x20, 0xD4, 0x3A, 0x3E, 0x45, 0xAD, 0x02, 0x65 - }; - const ulong rounds = 1; - - var composite = new CompositeKey(); - AesKdf kdf = new AesKdf(); - KdfParameters p = kdf.GetDefaultParameters(); - p.SetUInt64(AesKdf.ParamRounds, rounds); - p.SetByteArray(AesKdf.ParamSeed, originalKey); - var key = composite.GenerateKey32(p); - Assert.IsNotNull(key); - var keyData = key.ReadData(); - Assert.IsTrue(MemUtil.ArraysEqual(keyData, expectedKey)); - } - } -} diff --git a/ModernKeePassLib.Test/Keys/KcpCustomKeyTests.cs b/ModernKeePassLib.Test/Keys/KcpCustomKeyTests.cs deleted file mode 100644 index 0fe6080..0000000 --- a/ModernKeePassLib.Test/Keys/KcpCustomKeyTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Keys; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Keys -{ - [TestClass()] - public class KcpCustomKeyTests - { - static readonly byte[] testData = - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - [TestMethod] - public void TestConstruct() - { - var expectedHash = new byte[32] - { - 0xAF, 0x55, 0x70, 0xF5, 0xA1, 0x81, 0x0B, 0x7A, - 0xF7, 0x8C, 0xAF, 0x4B, 0xC7, 0x0A, 0x66, 0x0F, - 0x0D, 0xF5, 0x1E, 0x42, 0xBA, 0xF9, 0x1D, 0x4D, - 0xE5, 0xB2, 0x32, 0x8D, 0xE0, 0xE8, 0x3D, 0xFC - }; - - var key = new KcpCustomKey("test1", testData, false); - var keyData = key.KeyData.ReadData(); - Assert.IsTrue(MemUtil.ArraysEqual(keyData, testData)); - - key = new KcpCustomKey("test2", testData, true); - keyData = key.KeyData.ReadData(); - Assert.IsTrue(MemUtil.ArraysEqual(keyData, expectedHash)); - } - } -} diff --git a/ModernKeePassLib.Test/Keys/KcpKeyFileTests.cs b/ModernKeePassLib.Test/Keys/KcpKeyFileTests.cs deleted file mode 100644 index f2d5e8d..0000000 --- a/ModernKeePassLib.Test/Keys/KcpKeyFileTests.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.IO; -using Windows.Storage; -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Keys; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Keys -{ - [TestClass] - public class KcpKeyFileTests - { - private const string TestCreateFile = "TestCreate.xml"; - private const string TestKey = "0123456789"; - - private const string ExpectedFileStart = - "\r\n" + - "\r\n" + - "\t\r\n" + - "\t\t1.00\r\n" + - "\t\r\n" + - "\t\r\n" + - "\t\t"; - - private const string ExpectedFileEnd = "\t\r\n" + - ""; - - [TestMethod] - public void TestConstruct() - { - var expectedKeyData = new byte[32] - { - 0xC1, 0xB1, 0x12, 0x77, 0x23, 0xB8, 0x99, 0xB8, - 0xB9, 0x3B, 0x1B, 0xFF, 0x6C, 0xBE, 0xA1, 0x5B, - 0x8B, 0x99, 0xAC, 0xBD, 0x99, 0x51, 0x85, 0x95, - 0x31, 0xAA, 0x14, 0x3D, 0x95, 0xBF, 0x63, 0xFF - }; - - //var fullPath = Path.Combine(ApplicationData.Current.TemporaryFolder.Path, TestCreateFile); - var file = ApplicationData.Current.TemporaryFolder.CreateFileAsync(TestCreateFile).GetAwaiter().GetResult(); - using (var fs = file.OpenStreamForWriteAsync().GetAwaiter().GetResult()) - { - using (var sw = new StreamWriter(fs)) - { - sw.Write(ExpectedFileStart); - sw.Write(TestKey); - sw.Write(ExpectedFileEnd); - } - } - - try - { - var keyFile = new KcpKeyFile(file); - var keyData = keyFile.KeyData.ReadData(); - Assert.IsTrue(MemUtil.ArraysEqual(keyData, expectedKeyData)); - } - finally - { - file.DeleteAsync().GetAwaiter().GetResult(); - } - } - - [TestMethod] - public void TestCreate() - { - //var fullPath = Path.Combine(ApplicationData.Current.TemporaryFolder.Path, TestCreateFile); - var file = ApplicationData.Current.TemporaryFolder.CreateFileAsync(TestCreateFile).GetAwaiter().GetResult(); - KcpKeyFile.Create(file, null); - try - { - var fileContents = FileIO.ReadTextAsync(file).GetAwaiter().GetResult(); - - Assert.AreEqual(185, fileContents.Length); - Assert.IsTrue(fileContents.StartsWith(ExpectedFileStart)); - Assert.IsTrue(fileContents.EndsWith(ExpectedFileEnd)); - } - finally - { - file.DeleteAsync().GetAwaiter().GetResult(); - } - } - } -} - diff --git a/ModernKeePassLib.Test/Keys/KcpPasswordTests.cs b/ModernKeePassLib.Test/Keys/KcpPasswordTests.cs deleted file mode 100644 index 30e17ef..0000000 --- a/ModernKeePassLib.Test/Keys/KcpPasswordTests.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Keys; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Keys -{ - [TestClass()] - public class KcpPasswordTests - { - const string testPassword = "password"; - - [TestMethod] - public void TestConstruct() - { - var expectedHash = new byte[32] - { - 0x5E, 0x88, 0x48, 0x98, 0xDA, 0x28, 0x04, 0x71, - 0x51, 0xD0, 0xE5, 0x6F, 0x8D, 0xC6, 0x29, 0x27, - 0x73, 0x60, 0x3D, 0x0D, 0x6A, 0xAB, 0xBD, 0xD6, - 0x2A, 0x11, 0xEF, 0x72, 0x1D, 0x15, 0x42, 0xD8 - }; - - var key = new KcpPassword(testPassword); - var keyData = key.KeyData.ReadData(); - Assert.IsTrue(MemUtil.ArraysEqual(keyData, expectedHash)); - } - } -} - diff --git a/ModernKeePassLib.Test/ModernKeePass.LibTest.csproj b/ModernKeePassLib.Test/ModernKeePass.LibTest.csproj deleted file mode 100644 index 6ccaa1e..0000000 --- a/ModernKeePassLib.Test/ModernKeePass.LibTest.csproj +++ /dev/null @@ -1,201 +0,0 @@ - - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {0A4279CF-2A67-4868-9906-052E50C25F3B} - Library - Properties - ModernKeePassLib.Test - ModernKeePassLib.Test - en-US - 8.1 - 14 - 512 - {BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - - Never - False - - - ED3AA34F46D03498F989901C5DB2742B65D72F60 - True - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE;NETFX_CORE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE;NETFX_CORE - prompt - 4 - - - true - bin\ARM\Debug\ - DEBUG;TRACE;NETFX_CORE - ;2008 - full - ARM - false - prompt - true - - - bin\ARM\Release\ - TRACE;NETFX_CORE - true - ;2008 - pdbonly - ARM - false - prompt - true - - - true - bin\x64\Debug\ - DEBUG;TRACE;NETFX_CORE - ;2008 - full - x64 - false - prompt - true - - - bin\x64\Release\ - TRACE;NETFX_CORE - true - ;2008 - pdbonly - x64 - false - prompt - true - - - true - bin\x86\Debug\ - DEBUG;TRACE;NETFX_CORE - ;2008 - full - x86 - false - prompt - true - - - bin\x86\Release\ - TRACE;NETFX_CORE - true - ;2008 - pdbonly - x86 - false - prompt - true - - - True - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Designer - - - - - - ..\packages\Portable.BouncyCastle.1.8.3\lib\netstandard1.0\BouncyCastle.Crypto.dll - True - - - ..\packages\ModernKeePassLib.2.39.1\lib\netstandard1.2\ModernKeePassLib.dll - True - - - ..\packages\Splat.3.0.0\lib\netstandard1.1\Splat.dll - True - - - ..\packages\System.Drawing.Primitives.4.3.0\lib\netstandard1.1\System.Drawing.Primitives.dll - True - - - ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\win8\System.Runtime.InteropServices.RuntimeInformation.dll - True - - - ..\packages\Validation.2.4.18\lib\portable-net45+win8+wp8+wpa81\Validation.dll - True - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - 14.0 - - - - \ No newline at end of file diff --git a/ModernKeePassLib.Test/Package.appxmanifest b/ModernKeePassLib.Test/Package.appxmanifest deleted file mode 100644 index 82d3b80..0000000 --- a/ModernKeePassLib.Test/Package.appxmanifest +++ /dev/null @@ -1,32 +0,0 @@ - - - - - ModernKeePassLib.Test - wismna - Images\UnitTestStoreLogo.png - ModernKeePassLib.Test - - - 6.3.0 - 6.3.0 - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ModernKeePassLib.Test/Serialization/HashedBlockStreamTests.cs b/ModernKeePassLib.Test/Serialization/HashedBlockStreamTests.cs deleted file mode 100644 index 4956281..0000000 --- a/ModernKeePassLib.Test/Serialization/HashedBlockStreamTests.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.IO; -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Serialization; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Serialization -{ - [TestClass()] - public class HashedBlockStreamTests - { - static readonly byte[] data = new byte[16]; - - static readonly byte[] hashStreamData = new byte[] - { - // The first 4 bytes are an integer indicating the block index - 0x00, 0x00, 0x00, 0x00, - // Then the SHA-256 hash of the data - 0x37, 0x47, 0x08, 0xFF, 0xF7, 0x71, 0x9D, 0xD5, - 0x97, 0x9E, 0xC8, 0x75, 0xD5, 0x6C, 0xD2, 0x28, - 0x6F, 0x6D, 0x3C, 0xF7, 0xEC, 0x31, 0x7A, 0x3B, - 0x25, 0x63, 0x2A, 0xAB, 0x28, 0xEC, 0x37, 0xBB, - // then an integer that is the length of the data - 0x10, 0x00, 0x00, 0x00, - // and finally the data itself - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // Next, a terminating block - 0x01, 0x00, 0x00, 0x00, - // terminating block is indicated by a hash of all 0s... - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // ...and by a size of 0 - 0x00, 0x00, 0x00, 0x00 - }; - - [TestMethod] - public void TestRead() - { - using (var ms = new MemoryStream(hashStreamData)) - { - using (var hbs = new HashedBlockStream(ms, false)) - { - using (var br = new BinaryReader(hbs)) - { - var bytes = br.ReadBytes(data.Length); - Assert.IsTrue(MemUtil.ArraysEqual(bytes, data)); - Assert.ThrowsException(() => br.ReadByte()); - } - } - } - } - - [TestMethod] - public void TestWrite() - { - var buffer = new byte[hashStreamData.Length]; - using (var ms = new MemoryStream(buffer)) - { - using (var hbs = new HashedBlockStream(ms, true)) - { - using (var bw = new BinaryWriter(hbs)) - { - bw.Write(data); - } - } - Assert.IsTrue(MemUtil.ArraysEqual(buffer, hashStreamData)); - } - } - } -} - diff --git a/ModernKeePassLib.Test/Serialization/KdbxFileTests.cs b/ModernKeePassLib.Test/Serialization/KdbxFileTests.cs deleted file mode 100644 index 03face6..0000000 --- a/ModernKeePassLib.Test/Serialization/KdbxFileTests.cs +++ /dev/null @@ -1,171 +0,0 @@ -using System; -using System.Globalization; -using System.IO; -using System.Text; -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Keys; -using ModernKeePassLib.Security; -using ModernKeePassLib.Serialization; -using ModernKeePassLib.Collections; - -namespace ModernKeePassLib.Test.Serialization -{ - [TestClass()] - public class KdbxFileTests - { - const string TestLocalizedAppName = "My Localized App Name"; - - const string TestDatabaseName = "My Database Name"; - const string TestDatabaseDescription = "My Database Description"; - const string TestDefaultUserName = "My Default User Name"; - const string TestColor = "#FF0000"; // Red - - const string TestRootGroupName = "My Root Group Name"; - const string TestRootGroupNotes = "My Root Group Notes"; - const string TestRootGroupDefaultAutoTypeSequence = "My Root Group Default Auto Type Sequence"; - - const string TestDatabase = "\r\n" + - "\r\n" + - "\t\r\n" + - "\t\t" + TestLocalizedAppName + "\r\n" + - "\t\t" + TestDatabaseName + "\r\n" + - "\t\t2017-10-23T08:03:55Z\r\n" + - "\t\t" + TestDatabaseDescription + "\r\n" + - "\t\t2017-10-23T08:03:55Z\r\n" + - "\t\t" + TestDefaultUserName + "\r\n" + - "\t\t2017-10-23T08:03:55Z\r\n" + - "\t\t365\r\n" + - //"\t\t" + testColor + "\r\n" + - "\t\t\r\n" + - "\t\t2017-10-23T08:03:55Z\r\n" + - "\t\t-1\r\n" + - "\t\t-1\r\n" + - "\t\t\r\n" + - "\t\t\tFalse\r\n" + - "\t\t\tFalse\r\n" + - "\t\t\tTrue\r\n" + - "\t\t\tFalse\r\n" + - "\t\t\tFalse\r\n" + - "\t\t\r\n" + - "\t\tTrue\r\n" + - "\t\tAAAAAAAAAAAAAAAAAAAAAA==\r\n" + - "\t\t2017-10-23T08:03:55Z\r\n" + - "\t\tAAAAAAAAAAAAAAAAAAAAAA==\r\n" + - "\t\t2017-10-23T08:03:55Z\r\n" + - "\t\t10\r\n" + - "\t\t6291456\r\n" + - "\t\tAAAAAAAAAAAAAAAAAAAAAA==\r\n" + - "\t\tAAAAAAAAAAAAAAAAAAAAAA==\r\n" + - "\t\t\r\n" + - "\t\t\r\n" + - "\t\r\n" + - "\t\r\n" + - "\t\t\r\n" + - "\t\t\tAAAAAAAAAAAAAAAAAAAAAA==\r\n" + - "\t\t\t" + TestRootGroupName + "\r\n" + - "\t\t\t" + TestRootGroupNotes + "\r\n" + - "\t\t\t49\r\n" + - "\t\t\t\r\n" + - "\t\t\t\t2017-10-23T08:03:55Z\r\n" + - "\t\t\t\t2017-10-23T08:03:55Z\r\n" + - "\t\t\t\t2017-10-23T08:03:55Z\r\n" + - "\t\t\t\t2017-10-23T08:03:55Z\r\n" + - "\t\t\t\tFalse\r\n" + - "\t\t\t\t0\r\n" + - "\t\t\t\t2017-10-23T08:03:55Z\r\n" + - "\t\t\t\r\n" + - "\t\t\tTrue\r\n" + - "\t\t\t" + TestRootGroupDefaultAutoTypeSequence + "\r\n" + - "\t\t\tnull\r\n" + - "\t\t\tnull\r\n" + - "\t\t\tAAAAAAAAAAAAAAAAAAAAAA==\r\n" + - "\t\t\r\n" + - "\t\t\r\n" + - "\t\r\n" + - ""; - - const string TestDate = "2017-10-23T08:03:55Z"; - - [TestMethod] - public void TestLoad() - { - var database = new PwDatabase(); - using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(TestDatabase))) - { - var file = new KdbxFile(database); - file.Load(ms, KdbxFormat.PlainXml, null); - } - //Assert.That(database.Color.ToArgb(), Is.EqualTo(Color.Red.ToArgb())); - Assert.AreEqual(database.Compression, PwCompressionAlgorithm.GZip); - //Assert.That (database.CustomData, Is.EqualTo ()); - Assert.IsTrue(database.CustomIcons.Count == 0); - } - - [TestMethod] - public void TestSave() - { - var buffer = new byte[4096]; - using (var ms = new MemoryStream(buffer)) - { - var database = new PwDatabase(); - database.New(new IOConnectionInfo(), new CompositeKey()); - var date = DateTime.Parse(TestDate, CultureInfo.CurrentCulture, DateTimeStyles.AdjustToUniversal); - //var date = DateTime.UtcNow; - PwDatabase.LocalizedAppName = TestLocalizedAppName; - database.Name = TestDatabaseName; - database.NameChanged = date; - database.Description = TestDatabaseDescription; - database.DescriptionChanged = date; - database.DefaultUserName = TestDefaultUserName; - database.DefaultUserNameChanged = date; - //database.Color = Color.Red; - database.MasterKeyChanged = date; - database.RecycleBinChanged = date; - database.EntryTemplatesGroupChanged = date; - database.RootGroup.Uuid = PwUuid.Zero; - database.RootGroup.Name = TestRootGroupName; - database.RootGroup.Notes = TestRootGroupNotes; - database.RootGroup.DefaultAutoTypeSequence = TestRootGroupDefaultAutoTypeSequence; - database.RootGroup.CreationTime = date; - database.RootGroup.LastModificationTime = date; - database.RootGroup.LastAccessTime = date; - database.RootGroup.ExpiryTime = date; - database.RootGroup.LocationChanged = date; - var file = new KdbxFile(database); - file.Save(ms, null, KdbxFormat.PlainXml, null); - } - var fileContents = Encoding.UTF8.GetString(buffer, 0, buffer.Length).Replace("\0", ""); - if (typeof(KdbxFile).Namespace.StartsWith("KeePassLib.")) - { - // Upstream KeePassLib does not specify line endings for XmlTextWriter, - // so it uses native line endings. - fileContents = fileContents.Replace("\n", "\r\n"); - } - Assert.AreEqual(fileContents, TestDatabase); - } - - [TestMethod] - public void TestSearch() - { - var database = new PwDatabase(); - using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(TestDatabase))) - { - var file = new KdbxFile(database); - file.Load(ms, KdbxFormat.PlainXml, null); - } - var sp = new SearchParameters() - { - SearchString = "sfsoiwsefsi" - }; - var listStorage = new PwObjectList(); - database.RootGroup.SearchEntries(sp, listStorage); - Assert.AreEqual(0U, listStorage.UCount); - var entry = new PwEntry(true, true); - entry.Strings.Set("Title", new ProtectedString(false, "NaMe")); - database.RootGroup.AddEntry(entry, true); - sp.SearchString = "name"; - database.RootGroup.SearchEntries(sp, listStorage); - Assert.AreEqual(1U, listStorage.UCount); - } - } -} diff --git a/ModernKeePassLib.Test/Utility/GfxUtilTests.cs b/ModernKeePassLib.Test/Utility/GfxUtilTests.cs deleted file mode 100644 index fe28430..0000000 --- a/ModernKeePassLib.Test/Utility/GfxUtilTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Utility -{ - [TestClass] - public class GfxUtilTests - { - // 16x16 all white PNG file, base64 encoded - const string testImageData = - "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsTAAA" + - "LEwEAmpwYAAAAB3RJTUUH3wMOFgIgmTCUMQAAABl0RVh0Q29tbWVudABDcmVhdG" + - "VkIHdpdGggR0lNUFeBDhcAAAAaSURBVCjPY/z//z8DKYCJgUQwqmFUw9DRAABVb" + - "QMdny4VogAAAABJRU5ErkJggg=="; - - [TestMethod] - public void TestLoadImage () - { - var testData = Convert.FromBase64String (testImageData); - var image = GfxUtil.ScaleImage(testData, 16, 16); - //var image = GfxUtil.LoadImage(testData); - Assert.AreEqual(image.Width, 16); - Assert.AreEqual(image.Height, 16); - } - } -} diff --git a/ModernKeePassLib.Test/Utility/MemUtilTests.cs b/ModernKeePassLib.Test/Utility/MemUtilTests.cs deleted file mode 100644 index eccf514..0000000 --- a/ModernKeePassLib.Test/Utility/MemUtilTests.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Text; -using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Test.Utility -{ - [TestClass] - public class MemUtilTests - { - private byte[] _pb = CryptoRandom.Instance.GetRandomBytes((uint)CryptoRandom.NewWeakRandom().Next(0, 0x2FFFF)); - - [TestMethod] - public void TestGzip() - { - var pbCompressed = MemUtil.Compress(_pb); - Assert.IsTrue(MemUtil.ArraysEqual(MemUtil.Decompress(pbCompressed), _pb)); - } - - [TestMethod] - public void TestMemUtil() - { - Encoding enc = StrUtil.Utf8; - _pb = enc.GetBytes("012345678901234567890a"); - byte[] pbN = enc.GetBytes("9012"); - Assert.AreEqual(MemUtil.IndexOf(_pb, pbN), 9); - - pbN = enc.GetBytes("01234567890123"); - Assert.AreEqual(MemUtil.IndexOf(_pb, pbN), 0); - - pbN = enc.GetBytes("a"); - Assert.AreEqual(MemUtil.IndexOf(_pb, pbN), 21); - - pbN = enc.GetBytes("0a"); - Assert.AreEqual(MemUtil.IndexOf(_pb, pbN), 20); - - pbN = enc.GetBytes("1"); - Assert.AreEqual(MemUtil.IndexOf(_pb, pbN), 1); - - pbN = enc.GetBytes("b"); - Assert.IsTrue(MemUtil.IndexOf(_pb, pbN) < 0); - - pbN = enc.GetBytes("012b"); - Assert.IsTrue(MemUtil.IndexOf(_pb, pbN) < 0); - } - - [TestMethod] - public void TestBase32() - { - byte[] pbRes = MemUtil.ParseBase32("MY======"); - byte[] pbExp = Encoding.UTF8.GetBytes("f"); - Assert.IsTrue(MemUtil.ArraysEqual(pbRes, pbExp)); - - pbRes = MemUtil.ParseBase32("MZXQ===="); - pbExp = Encoding.UTF8.GetBytes("fo"); - Assert.IsTrue(MemUtil.ArraysEqual(pbRes, pbExp)); - - pbRes = MemUtil.ParseBase32("MZXW6==="); - pbExp = Encoding.UTF8.GetBytes("foo"); - Assert.IsTrue(MemUtil.ArraysEqual(pbRes, pbExp)); - - pbRes = MemUtil.ParseBase32("MZXW6YQ="); - pbExp = Encoding.UTF8.GetBytes("foob"); - Assert.IsTrue(MemUtil.ArraysEqual(pbRes, pbExp)); - - pbRes = MemUtil.ParseBase32("MZXW6YTB"); - pbExp = Encoding.UTF8.GetBytes("fooba"); - Assert.IsTrue(MemUtil.ArraysEqual(pbRes, pbExp)); - - pbRes = MemUtil.ParseBase32("MZXW6YTBOI======"); - pbExp = Encoding.UTF8.GetBytes("foobar"); - Assert.IsTrue(MemUtil.ArraysEqual(pbRes, pbExp)); - - pbRes = MemUtil.ParseBase32("JNSXSIDQOJXXM2LEMVZCAYTBONSWIIDPNYQG63TFFV2GS3LFEBYGC43TO5XXEZDTFY======"); - pbExp = Encoding.UTF8.GetBytes("Key provider based on one-time passwords."); - Assert.IsTrue(MemUtil.ArraysEqual(pbRes, pbExp)); - } - - [TestMethod] - public void TestMemUtil2() - { - var i = 0 - 0x10203040; - var pbRes = MemUtil.Int32ToBytes(i); - Assert.AreEqual(MemUtil.ByteArrayToHexString(pbRes), "C0CFDFEF"); - Assert.AreEqual(MemUtil.BytesToUInt32(pbRes), (uint)i); - Assert.AreEqual(MemUtil.BytesToInt32(pbRes), i); - } - } -} \ No newline at end of file diff --git a/ModernKeePassLib.Test/packages.config b/ModernKeePassLib.Test/packages.config deleted file mode 100644 index 0a38eab..0000000 --- a/ModernKeePassLib.Test/packages.config +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ModernKeePassLib/Collections/AutoTypeConfig.cs b/ModernKeePassLib/Collections/AutoTypeConfig.cs deleted file mode 100644 index b53f9b7..0000000 --- a/ModernKeePassLib/Collections/AutoTypeConfig.cs +++ /dev/null @@ -1,244 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -using ModernKeePassLib.Interfaces; - -namespace ModernKeePassLib.Collections -{ - [Flags] - public enum AutoTypeObfuscationOptions - { - None = 0, - UseClipboard = 1 - } - - public sealed class AutoTypeAssociation : IEquatable, - IDeepCloneable - { - private string m_strWindow = string.Empty; - public string WindowName - { - get { return m_strWindow; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_strWindow = value; - } - } - - private string m_strSequence = string.Empty; - public string Sequence - { - get { return m_strSequence; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_strSequence = value; - } - } - - public AutoTypeAssociation() { } - - public AutoTypeAssociation(string strWindow, string strSeq) - { - if(strWindow == null) throw new ArgumentNullException("strWindow"); - if(strSeq == null) throw new ArgumentNullException("strSeq"); - - m_strWindow = strWindow; - m_strSequence = strSeq; - } - - public bool Equals(AutoTypeAssociation other) - { - if(other == null) return false; - - if(m_strWindow != other.m_strWindow) return false; - if(m_strSequence != other.m_strSequence) return false; - - return true; - } - - public AutoTypeAssociation CloneDeep() - { - return (AutoTypeAssociation)this.MemberwiseClone(); - } - } - - /// - /// A list of auto-type associations. - /// - public sealed class AutoTypeConfig : IEquatable, - IDeepCloneable - { - private bool m_bEnabled = true; - private AutoTypeObfuscationOptions m_atooObfuscation = - AutoTypeObfuscationOptions.None; - private string m_strDefaultSequence = string.Empty; - private List m_lWindowAssocs = - new List(); - - /// - /// Specify whether auto-type is enabled or not. - /// - public bool Enabled - { - get { return m_bEnabled; } - set { m_bEnabled = value; } - } - - /// - /// Specify whether the typing should be obfuscated. - /// - public AutoTypeObfuscationOptions ObfuscationOptions - { - get { return m_atooObfuscation; } - set { m_atooObfuscation = value; } - } - - /// - /// The default keystroke sequence that is auto-typed if - /// no matching window is found in the Associations - /// container. - /// - public string DefaultSequence - { - get { return m_strDefaultSequence; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_strDefaultSequence = value; - } - } - - /// - /// Get all auto-type window/keystroke sequence pairs. - /// - public IEnumerable Associations - { - get { return m_lWindowAssocs; } - } - - public int AssociationsCount - { - get { return m_lWindowAssocs.Count; } - } - - /// - /// Construct a new auto-type associations list. - /// - public AutoTypeConfig() - { - } - - /// - /// Remove all associations. - /// - public void Clear() - { - m_lWindowAssocs.Clear(); - } - - /// - /// Clone the auto-type associations list. - /// - /// New, cloned object. - public AutoTypeConfig CloneDeep() - { - AutoTypeConfig newCfg = new AutoTypeConfig(); - - newCfg.m_bEnabled = m_bEnabled; - newCfg.m_atooObfuscation = m_atooObfuscation; - newCfg.m_strDefaultSequence = m_strDefaultSequence; - - foreach(AutoTypeAssociation a in m_lWindowAssocs) - newCfg.Add(a.CloneDeep()); - - return newCfg; - } - - public bool Equals(AutoTypeConfig other) - { - if(other == null) { Debug.Assert(false); return false; } - - if(m_bEnabled != other.m_bEnabled) return false; - if(m_atooObfuscation != other.m_atooObfuscation) return false; - if(m_strDefaultSequence != other.m_strDefaultSequence) return false; - - if(m_lWindowAssocs.Count != other.m_lWindowAssocs.Count) return false; - for(int i = 0; i < m_lWindowAssocs.Count; ++i) - { - if(!m_lWindowAssocs[i].Equals(other.m_lWindowAssocs[i])) - return false; - } - - return true; - } - - public AutoTypeAssociation GetAt(int iIndex) - { - if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count)) - throw new ArgumentOutOfRangeException("iIndex"); - - return m_lWindowAssocs[iIndex]; - } - - public void Add(AutoTypeAssociation a) - { - if(a == null) { Debug.Assert(false); throw new ArgumentNullException("a"); } - - m_lWindowAssocs.Add(a); - } - - public void Insert(int iIndex, AutoTypeAssociation a) - { - if((iIndex < 0) || (iIndex > m_lWindowAssocs.Count)) - throw new ArgumentOutOfRangeException("iIndex"); - if(a == null) { Debug.Assert(false); throw new ArgumentNullException("a"); } - - m_lWindowAssocs.Insert(iIndex, a); - } - - public void RemoveAt(int iIndex) - { - if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count)) - throw new ArgumentOutOfRangeException("iIndex"); - - m_lWindowAssocs.RemoveAt(iIndex); - } - - // public void Sort() - // { - // m_lWindowAssocs.Sort(AutoTypeConfig.AssocCompareFn); - // } - - // private static int AssocCompareFn(AutoTypeAssociation x, - // AutoTypeAssociation y) - // { - // if(x == null) { Debug.Assert(false); return ((y == null) ? 0 : -1); } - // if(y == null) { Debug.Assert(false); return 1; } - // int cn = x.WindowName.CompareTo(y.WindowName); - // if(cn != 0) return cn; - // return x.Sequence.CompareTo(y.Sequence); - // } - } -} diff --git a/ModernKeePassLib/Collections/ProtectedBinaryDictionary.cs b/ModernKeePassLib/Collections/ProtectedBinaryDictionary.cs deleted file mode 100644 index 927d35c..0000000 --- a/ModernKeePassLib/Collections/ProtectedBinaryDictionary.cs +++ /dev/null @@ -1,172 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Security; - -#if KeePassLibSD -using KeePassLibSD; -#endif - -namespace ModernKeePassLib.Collections -{ - /// - /// A list of ProtectedBinary objects (dictionary). - /// - public sealed class ProtectedBinaryDictionary : - IDeepCloneable, - IEnumerable> - { - private SortedDictionary m_vBinaries = - new SortedDictionary(); - - /// - /// Get the number of binaries in this entry. - /// - public uint UCount - { - get { return (uint)m_vBinaries.Count; } - } - - /// - /// Construct a new list of protected binaries. - /// - public ProtectedBinaryDictionary() - { - } - - IEnumerator IEnumerable.GetEnumerator() - { - return m_vBinaries.GetEnumerator(); - } - - public IEnumerator> GetEnumerator() - { - return m_vBinaries.GetEnumerator(); - } - - public void Clear() - { - m_vBinaries.Clear(); - } - - /// - /// Clone the current ProtectedBinaryList object, including all - /// stored protected strings. - /// - /// New ProtectedBinaryList object. - public ProtectedBinaryDictionary CloneDeep() - { - ProtectedBinaryDictionary plNew = new ProtectedBinaryDictionary(); - - foreach(KeyValuePair kvpBin in m_vBinaries) - { - // ProtectedBinary objects are immutable - plNew.Set(kvpBin.Key, kvpBin.Value); - } - - return plNew; - } - - public bool EqualsDictionary(ProtectedBinaryDictionary dict) - { - if(dict == null) { Debug.Assert(false); return false; } - - if(m_vBinaries.Count != dict.m_vBinaries.Count) return false; - - foreach(KeyValuePair kvp in m_vBinaries) - { - ProtectedBinary pb = dict.Get(kvp.Key); - if(pb == null) return false; - if(!pb.Equals(kvp.Value)) return false; - } - - return true; - } - - /// - /// Get one of the stored binaries. - /// - /// Binary identifier. - /// Protected binary. If the binary identified by - /// cannot be found, the function - /// returns null. - /// Thrown if the input - /// parameter is null. - public ProtectedBinary Get(string strName) - { - Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); - - ProtectedBinary pb; - if(m_vBinaries.TryGetValue(strName, out pb)) return pb; - - return null; - } - - /// - /// Set a binary object. - /// - /// Identifier of the binary field to modify. - /// New value. This parameter must not be null. - /// Thrown if any of the input - /// parameters is null. - public void Set(string strField, ProtectedBinary pbNewValue) - { - Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField"); - Debug.Assert(pbNewValue != null); if(pbNewValue == null) throw new ArgumentNullException("pbNewValue"); - - m_vBinaries[strField] = pbNewValue; - } - - /// - /// Remove a binary object. - /// - /// Identifier of the binary field to remove. - /// Returns true if the object has been successfully - /// removed, otherwise false. - /// Thrown if the input parameter - /// is null. - public bool Remove(string strField) - { - Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField"); - - return m_vBinaries.Remove(strField); - } - - public string KeysToString() - { - if(m_vBinaries.Count == 0) return string.Empty; - - StringBuilder sb = new StringBuilder(); - foreach(KeyValuePair kvp in m_vBinaries) - { - if(sb.Length > 0) sb.Append(", "); - sb.Append(kvp.Key); - } - - return sb.ToString(); - } - } -} diff --git a/ModernKeePassLib/Collections/ProtectedBinarySet.cs b/ModernKeePassLib/Collections/ProtectedBinarySet.cs deleted file mode 100644 index 9cfac59..0000000 --- a/ModernKeePassLib/Collections/ProtectedBinarySet.cs +++ /dev/null @@ -1,174 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Delegates; -using ModernKeePassLib.Security; - -namespace ModernKeePassLib.Collections -{ - internal sealed class ProtectedBinarySet : IEnumerable> - { - private Dictionary m_d = - new Dictionary(); - - public ProtectedBinarySet() - { - } - - IEnumerator IEnumerable.GetEnumerator() - { - return m_d.GetEnumerator(); - } - - public IEnumerator> GetEnumerator() - { - return m_d.GetEnumerator(); - } - - public void Clear() - { - m_d.Clear(); - } - - private int GetFreeID() - { - int i = m_d.Count; - while(m_d.ContainsKey(i)) { ++i; } - Debug.Assert(i == m_d.Count); // m_d.Count should be free - return i; - } - - public ProtectedBinary Get(int iID) - { - ProtectedBinary pb; - if(m_d.TryGetValue(iID, out pb)) return pb; - - // Debug.Assert(false); // No assert - return null; - } - - public int Find(ProtectedBinary pb) - { - if(pb == null) { Debug.Assert(false); return -1; } - - // Fast search by reference - foreach(KeyValuePair kvp in m_d) - { - if(object.ReferenceEquals(pb, kvp.Value)) - { - Debug.Assert(pb.Equals(kvp.Value)); - return kvp.Key; - } - } - - // Slow search by content - foreach(KeyValuePair kvp in m_d) - { - if(pb.Equals(kvp.Value)) return kvp.Key; - } - - // Debug.Assert(false); // No assert - return -1; - } - - public void Set(int iID, ProtectedBinary pb) - { - if(iID < 0) { Debug.Assert(false); return; } - if(pb == null) { Debug.Assert(false); return; } - - m_d[iID] = pb; - } - - public void Add(ProtectedBinary pb) - { - if(pb == null) { Debug.Assert(false); return; } - - int i = Find(pb); - if(i >= 0) return; // Exists already - - i = GetFreeID(); - m_d[i] = pb; - } - - public void AddFrom(ProtectedBinaryDictionary d) - { - if(d == null) { Debug.Assert(false); return; } - - foreach(KeyValuePair kvp in d) - { - Add(kvp.Value); - } - } - - public void AddFrom(PwGroup pg) - { - if(pg == null) { Debug.Assert(false); return; } - - EntryHandler eh = delegate(PwEntry pe) - { - if(pe == null) { Debug.Assert(false); return true; } - - AddFrom(pe.Binaries); - foreach(PwEntry peHistory in pe.History) - { - if(peHistory == null) { Debug.Assert(false); continue; } - AddFrom(peHistory.Binaries); - } - - return true; - }; - - pg.TraverseTree(TraversalMethod.PreOrder, null, eh); - } - - public ProtectedBinary[] ToArray() - { - int n = m_d.Count; - ProtectedBinary[] v = new ProtectedBinary[n]; - - foreach(KeyValuePair kvp in m_d) - { - if((kvp.Key < 0) || (kvp.Key >= n)) - { - Debug.Assert(false); - throw new InvalidOperationException(); - } - - v[kvp.Key] = kvp.Value; - } - - for(int i = 0; i < n; ++i) - { - if(v[i] == null) - { - Debug.Assert(false); - throw new InvalidOperationException(); - } - } - - return v; - } - } -} diff --git a/ModernKeePassLib/Collections/ProtectedStringDictionary.cs b/ModernKeePassLib/Collections/ProtectedStringDictionary.cs deleted file mode 100644 index b60b8aa..0000000 --- a/ModernKeePassLib/Collections/ProtectedStringDictionary.cs +++ /dev/null @@ -1,298 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -#if KeePassLibSD -using KeePassLibSD; -#endif - -namespace ModernKeePassLib.Collections -{ - /// - /// A list of ProtectedString objects (dictionary). - /// - public sealed class ProtectedStringDictionary : - IDeepCloneable, - IEnumerable> - { - private SortedDictionary m_vStrings = - new SortedDictionary(); - - /// - /// Get the number of strings in this entry. - /// - public uint UCount - { - get { return (uint)m_vStrings.Count; } - } - - /// - /// Construct a new list of protected strings. - /// - public ProtectedStringDictionary() - { - } - - IEnumerator IEnumerable.GetEnumerator() - { - return m_vStrings.GetEnumerator(); - } - - public IEnumerator> GetEnumerator() - { - return m_vStrings.GetEnumerator(); - } - - public void Clear() - { - m_vStrings.Clear(); - } - - /// - /// Clone the current ProtectedStringList object, including all - /// stored protected strings. - /// - /// New ProtectedStringList object. - public ProtectedStringDictionary CloneDeep() - { - ProtectedStringDictionary plNew = new ProtectedStringDictionary(); - - foreach(KeyValuePair kvpStr in m_vStrings) - { - // ProtectedString objects are immutable - plNew.Set(kvpStr.Key, kvpStr.Value); - } - - return plNew; - } - - [Obsolete] - public bool EqualsDictionary(ProtectedStringDictionary dict) - { - return EqualsDictionary(dict, PwCompareOptions.None, MemProtCmpMode.None); - } - - [Obsolete] - public bool EqualsDictionary(ProtectedStringDictionary dict, - MemProtCmpMode mpCompare) - { - return EqualsDictionary(dict, PwCompareOptions.None, mpCompare); - } - - public bool EqualsDictionary(ProtectedStringDictionary dict, - PwCompareOptions pwOpt, MemProtCmpMode mpCompare) - { - if(dict == null) { Debug.Assert(false); return false; } - - bool bNeEqStd = ((pwOpt & PwCompareOptions.NullEmptyEquivStd) != - PwCompareOptions.None); - if(!bNeEqStd) - { - if(m_vStrings.Count != dict.m_vStrings.Count) return false; - } - - foreach(KeyValuePair kvp in m_vStrings) - { - bool bStdField = PwDefs.IsStandardField(kvp.Key); - ProtectedString ps = dict.Get(kvp.Key); - - if(bNeEqStd && (ps == null) && bStdField) - ps = ProtectedString.Empty; - - if(ps == null) return false; - - if(mpCompare == MemProtCmpMode.Full) - { - if(ps.IsProtected != kvp.Value.IsProtected) return false; - } - else if(mpCompare == MemProtCmpMode.CustomOnly) - { - if(!bStdField && (ps.IsProtected != kvp.Value.IsProtected)) - return false; - } - - if(!ps.Equals(kvp.Value, false)) return false; - } - - if(bNeEqStd) - { - foreach(KeyValuePair kvp in dict.m_vStrings) - { - ProtectedString ps = Get(kvp.Key); - - if(ps != null) continue; // Compared previously - if(!PwDefs.IsStandardField(kvp.Key)) return false; - if(!kvp.Value.IsEmpty) return false; - } - } - - return true; - } - - /// - /// Get one of the protected strings. - /// - /// String identifier. - /// Protected string. If the string identified by - /// cannot be found, the function - /// returns null. - /// Thrown if the input parameter - /// is null. - public ProtectedString Get(string strName) - { - Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); - - ProtectedString ps; - if(m_vStrings.TryGetValue(strName, out ps)) return ps; - - return null; - } - - /// - /// Get one of the protected strings. The return value is never null. - /// If the requested string cannot be found, an empty protected string - /// object is returned. - /// - /// String identifier. - /// Returns a protected string object. If the standard string - /// has not been set yet, the return value is an empty string (""). - /// Thrown if the input - /// parameter is null. - public ProtectedString GetSafe(string strName) - { - Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); - - ProtectedString ps; - if(m_vStrings.TryGetValue(strName, out ps)) return ps; - - return ProtectedString.Empty; - } - - /// - /// Test if a named string exists. - /// - /// Name of the string to try. - /// Returns true if the string exists, otherwise false. - /// Thrown if - /// is null. - public bool Exists(string strName) - { - Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); - - return m_vStrings.ContainsKey(strName); - } - - /// - /// Get one of the protected strings. If the string doesn't exist, the - /// return value is an empty string (""). - /// - /// Name of the requested string. - /// Requested string value or an empty string, if the named - /// string doesn't exist. - /// Thrown if the input - /// parameter is null. - public string ReadSafe(string strName) - { - Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); - - ProtectedString ps; - if(m_vStrings.TryGetValue(strName, out ps)) - return ps.ReadString(); - - return string.Empty; - } - - /// - /// Get one of the entry strings. If the string doesn't exist, the - /// return value is an empty string (""). If the string is - /// in-memory protected, the return value is PwDefs.HiddenPassword. - /// - /// Name of the requested string. - /// Returns the requested string in plain-text or - /// PwDefs.HiddenPassword if the string cannot be found. - /// Thrown if the input - /// parameter is null. - public string ReadSafeEx(string strName) - { - Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); - - ProtectedString ps; - if(m_vStrings.TryGetValue(strName, out ps)) - { - if(ps.IsProtected) return PwDefs.HiddenPassword; - return ps.ReadString(); - } - - return string.Empty; - } - - /// - /// Set a string. - /// - /// Identifier of the string field to modify. - /// New value. This parameter must not be null. - /// Thrown if one of the input - /// parameters is null. - public void Set(string strField, ProtectedString psNewValue) - { - Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField"); - Debug.Assert(psNewValue != null); if(psNewValue == null) throw new ArgumentNullException("psNewValue"); - - m_vStrings[strField] = psNewValue; - } - - /// - /// Delete a string. - /// - /// Name of the string field to delete. - /// Returns true if the field has been successfully - /// removed, otherwise the return value is false. - /// Thrown if the input - /// parameter is null. - public bool Remove(string strField) - { - Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField"); - - return m_vStrings.Remove(strField); - } - - public List GetKeys() - { - return new List(m_vStrings.Keys); - } - - public void EnableProtection(string strField, bool bProtect) - { - ProtectedString ps = Get(strField); - if(ps == null) return; // Nothing to do, no assert - - if(ps.IsProtected != bProtect) - Set(strField, ps.WithProtection(bProtect)); - } - } -} diff --git a/ModernKeePassLib/Collections/PwObjectList.cs b/ModernKeePassLib/Collections/PwObjectList.cs deleted file mode 100644 index 9d97763..0000000 --- a/ModernKeePassLib/Collections/PwObjectList.cs +++ /dev/null @@ -1,380 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; - -using ModernKeePassLib.Interfaces; - -namespace ModernKeePassLib.Collections -{ - /// - /// List of objects that implement IDeepCloneable, - /// and cannot be null. - /// - /// Type specifier. - public sealed class PwObjectList : IEnumerable - where T : class, IDeepCloneable - { - private List m_vObjects = new List(); - - /// - /// Get number of objects in this list. - /// - public uint UCount - { - get { return (uint)m_vObjects.Count; } - } - - /// - /// Construct a new list of objects. - /// - public PwObjectList() - { - } - - IEnumerator IEnumerable.GetEnumerator() - { - return m_vObjects.GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - return m_vObjects.GetEnumerator(); - } - - public void Clear() - { - // Do not destroy contained objects! - m_vObjects.Clear(); - } - - /// - /// Clone the current PwObjectList, including all - /// stored objects (deep copy). - /// - /// New PwObjectList. - public PwObjectList CloneDeep() - { - PwObjectList pl = new PwObjectList(); - - foreach(T po in m_vObjects) - pl.Add(po.CloneDeep()); - - return pl; - } - - public PwObjectList CloneShallow() - { - PwObjectList tNew = new PwObjectList(); - - foreach(T po in m_vObjects) tNew.Add(po); - - return tNew; - } - - public List CloneShallowToList() - { - PwObjectList tNew = CloneShallow(); - return tNew.m_vObjects; - } - - /// - /// Add an object to this list. - /// - /// Object to be added. - /// Thrown if the input - /// parameter is null. - public void Add(T pwObject) - { - Debug.Assert(pwObject != null); - if(pwObject == null) throw new ArgumentNullException("pwObject"); - - m_vObjects.Add(pwObject); - } - - public void Add(PwObjectList vObjects) - { - Debug.Assert(vObjects != null); - if(vObjects == null) throw new ArgumentNullException("vObjects"); - - foreach(T po in vObjects) - { - m_vObjects.Add(po); - } - } - - public void Add(List vObjects) - { - Debug.Assert(vObjects != null); - if(vObjects == null) throw new ArgumentNullException("vObjects"); - - foreach(T po in vObjects) - { - m_vObjects.Add(po); - } - } - - public void Insert(uint uIndex, T pwObject) - { - Debug.Assert(pwObject != null); - if(pwObject == null) throw new ArgumentNullException("pwObject"); - - m_vObjects.Insert((int)uIndex, pwObject); - } - - /// - /// Get an object of the list. - /// - /// Index of the object to get. Must be valid, otherwise an - /// exception is thrown. - /// Reference to an existing T object. Is never null. - public T GetAt(uint uIndex) - { - Debug.Assert(uIndex < m_vObjects.Count); - if(uIndex >= m_vObjects.Count) throw new ArgumentOutOfRangeException("uIndex"); - - return m_vObjects[(int)uIndex]; - } - - public void SetAt(uint uIndex, T pwObject) - { - Debug.Assert(pwObject != null); - if(pwObject == null) throw new ArgumentNullException("pwObject"); - if(uIndex >= (uint)m_vObjects.Count) - throw new ArgumentOutOfRangeException("uIndex"); - - m_vObjects[(int)uIndex] = pwObject; - } - - /// - /// Get a range of objects. - /// - /// Index of the first object to be - /// returned (inclusive). - /// Index of the last object to be - /// returned (inclusive). - /// - public List GetRange(uint uStartIndexIncl, uint uEndIndexIncl) - { - if(uStartIndexIncl >= (uint)m_vObjects.Count) - throw new ArgumentOutOfRangeException("uStartIndexIncl"); - if(uEndIndexIncl >= (uint)m_vObjects.Count) - throw new ArgumentOutOfRangeException("uEndIndexIncl"); - if(uStartIndexIncl > uEndIndexIncl) - throw new ArgumentException(); - - List list = new List((int)(uEndIndexIncl - uStartIndexIncl) + 1); - for(uint u = uStartIndexIncl; u <= uEndIndexIncl; ++u) - { - list.Add(m_vObjects[(int)u]); - } - - return list; - } - - public int IndexOf(T pwReference) - { - Debug.Assert(pwReference != null); if(pwReference == null) throw new ArgumentNullException("pwReference"); - - return m_vObjects.IndexOf(pwReference); - } - - /// - /// Delete an object of this list. The object to be deleted is identified - /// by a reference handle. - /// - /// Reference of the object to be deleted. - /// Returns true if the object was deleted, false if - /// the object wasn't found in this list. - /// Thrown if the input - /// parameter is null. - public bool Remove(T pwReference) - { - Debug.Assert(pwReference != null); if(pwReference == null) throw new ArgumentNullException("pwReference"); - - return m_vObjects.Remove(pwReference); - } - - public void RemoveAt(uint uIndex) - { - m_vObjects.RemoveAt((int)uIndex); - } - - /// - /// Move an object up or down. - /// - /// The object to be moved. - /// Move one up. If false, move one down. - public void MoveOne(T tObject, bool bUp) - { - Debug.Assert(tObject != null); - if(tObject == null) throw new ArgumentNullException("tObject"); - - int nCount = m_vObjects.Count; - if(nCount <= 1) return; - - int nIndex = m_vObjects.IndexOf(tObject); - if(nIndex < 0) { Debug.Assert(false); return; } - - if(bUp && (nIndex > 0)) // No assert for top item - { - T tTemp = m_vObjects[nIndex - 1]; - m_vObjects[nIndex - 1] = m_vObjects[nIndex]; - m_vObjects[nIndex] = tTemp; - } - else if(!bUp && (nIndex != (nCount - 1))) // No assert for bottom item - { - T tTemp = m_vObjects[nIndex + 1]; - m_vObjects[nIndex + 1] = m_vObjects[nIndex]; - m_vObjects[nIndex] = tTemp; - } - } - - public void MoveOne(T[] vObjects, bool bUp) - { - Debug.Assert(vObjects != null); - if(vObjects == null) throw new ArgumentNullException("vObjects"); - - List lIndices = new List(); - foreach(T t in vObjects) - { - if(t == null) { Debug.Assert(false); continue; } - - int p = IndexOf(t); - if(p >= 0) lIndices.Add(p); - else { Debug.Assert(false); } - } - - MoveOne(lIndices.ToArray(), bUp); - } - - public void MoveOne(int[] vIndices, bool bUp) - { - Debug.Assert(vIndices != null); - if(vIndices == null) throw new ArgumentNullException("vIndices"); - - int n = m_vObjects.Count; - if(n <= 1) return; // No moving possible - - int m = vIndices.Length; - if(m == 0) return; // Nothing to move - - int[] v = new int[m]; - Array.Copy(vIndices, v, m); - Array.Sort(v); - - if((bUp && (v[0] <= 0)) || (!bUp && (v[m - 1] >= (n - 1)))) - return; // Moving as a block is not possible - - int iStart = (bUp ? 0 : (m - 1)); - int iExcl = (bUp ? m : -1); - int iStep = (bUp ? 1 : -1); - - for(int i = iStart; i != iExcl; i += iStep) - { - int p = v[i]; - if((p < 0) || (p >= n)) { Debug.Assert(false); continue; } - - T t = m_vObjects[p]; - - if(bUp) - { - Debug.Assert(p > 0); - m_vObjects.RemoveAt(p); - m_vObjects.Insert(p - 1, t); - } - else // Down - { - Debug.Assert(p < (n - 1)); - m_vObjects.RemoveAt(p); - m_vObjects.Insert(p + 1, t); - } - } - } - - /// - /// Move some of the objects in this list to the top/bottom. - /// - /// List of objects to be moved. - /// Move to top. If false, move to bottom. - public void MoveTopBottom(T[] vObjects, bool bTop) - { - Debug.Assert(vObjects != null); - if(vObjects == null) throw new ArgumentNullException("vObjects"); - - if(vObjects.Length == 0) return; - - int nCount = m_vObjects.Count; - foreach(T t in vObjects) m_vObjects.Remove(t); - - if(bTop) - { - int nPos = 0; - foreach(T t in vObjects) - { - m_vObjects.Insert(nPos, t); - ++nPos; - } - } - else // Move to bottom - { - foreach(T t in vObjects) m_vObjects.Add(t); - } - - Debug.Assert(nCount == m_vObjects.Count); - if(nCount != m_vObjects.Count) - throw new ArgumentException("At least one of the T objects in the vObjects list doesn't exist!"); - } - - public void Sort(IComparer tComparer) - { - if(tComparer == null) throw new ArgumentNullException("tComparer"); - - m_vObjects.Sort(tComparer); - } - - public void Sort(Comparison tComparison) - { - if(tComparison == null) throw new ArgumentNullException("tComparison"); - - m_vObjects.Sort(tComparison); - } - - public static PwObjectList FromArray(T[] tArray) - { - if(tArray == null) throw new ArgumentNullException("tArray"); - - PwObjectList l = new PwObjectList(); - foreach(T t in tArray) { l.Add(t); } - return l; - } - - public static PwObjectList FromList(List tList) - { - if(tList == null) throw new ArgumentNullException("tList"); - - PwObjectList l = new PwObjectList(); - l.Add(tList); - return l; - } - } -} diff --git a/ModernKeePassLib/Collections/PwObjectPool.cs b/ModernKeePassLib/Collections/PwObjectPool.cs deleted file mode 100644 index 5c15a00..0000000 --- a/ModernKeePassLib/Collections/PwObjectPool.cs +++ /dev/null @@ -1,232 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Delegates; -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Utility; - -#if KeePassLibSD -using KeePassLibSD; -#endif - -namespace ModernKeePassLib.Collections -{ - public sealed class PwObjectPool - { - private SortedDictionary m_dict = - new SortedDictionary(); - - public static PwObjectPool FromGroupRecursive(PwGroup pgRoot, bool bEntries) - { - if(pgRoot == null) throw new ArgumentNullException("pgRoot"); - - PwObjectPool p = new PwObjectPool(); - - if(!bEntries) p.m_dict[pgRoot.Uuid] = pgRoot; - GroupHandler gh = delegate(PwGroup pg) - { - p.m_dict[pg.Uuid] = pg; - return true; - }; - - EntryHandler eh = delegate(PwEntry pe) - { - p.m_dict[pe.Uuid] = pe; - return true; - }; - - pgRoot.TraverseTree(TraversalMethod.PreOrder, bEntries ? null : gh, - bEntries ? eh : null); - return p; - } - - public IStructureItem Get(PwUuid pwUuid) - { - IStructureItem pItem; - m_dict.TryGetValue(pwUuid, out pItem); - return pItem; - } - - public bool ContainsOnlyType(Type t) - { - foreach(KeyValuePair kvp in m_dict) - { - if(kvp.Value.GetType() != t) return false; - } - - return true; - } - } - - internal sealed class PwObjectPoolEx - { - private Dictionary m_dUuidToId = - new Dictionary(); - private Dictionary m_dIdToItem = - new Dictionary(); - - private PwObjectPoolEx() - { - } - - public static PwObjectPoolEx FromGroup(PwGroup pg) - { - PwObjectPoolEx p = new PwObjectPoolEx(); - - if(pg == null) { Debug.Assert(false); return p; } - - ulong uFreeId = 2; // 0 = "not found", 1 is a hole - - p.m_dUuidToId[pg.Uuid] = uFreeId; - p.m_dIdToItem[uFreeId] = pg; - uFreeId += 2; // Make hole - - p.AddGroupRec(pg, ref uFreeId); - return p; - } - - private void AddGroupRec(PwGroup pg, ref ulong uFreeId) - { - if(pg == null) { Debug.Assert(false); return; } - - ulong uId = uFreeId; - - // Consecutive entries must have consecutive IDs - foreach(PwEntry pe in pg.Entries) - { - Debug.Assert(!m_dUuidToId.ContainsKey(pe.Uuid)); - Debug.Assert(!m_dIdToItem.ContainsValue(pe)); - - m_dUuidToId[pe.Uuid] = uId; - m_dIdToItem[uId] = pe; - ++uId; - } - ++uId; // Make hole - - // Consecutive groups must have consecutive IDs - foreach(PwGroup pgSub in pg.Groups) - { - Debug.Assert(!m_dUuidToId.ContainsKey(pgSub.Uuid)); - Debug.Assert(!m_dIdToItem.ContainsValue(pgSub)); - - m_dUuidToId[pgSub.Uuid] = uId; - m_dIdToItem[uId] = pgSub; - ++uId; - } - ++uId; // Make hole - - foreach(PwGroup pgSub in pg.Groups) - { - AddGroupRec(pgSub, ref uId); - } - - uFreeId = uId; - } - - public ulong GetIdByUuid(PwUuid pwUuid) - { - if(pwUuid == null) { Debug.Assert(false); return 0; } - - ulong uId; - m_dUuidToId.TryGetValue(pwUuid, out uId); - return uId; - } - - public IStructureItem GetItemByUuid(PwUuid pwUuid) - { - if(pwUuid == null) { Debug.Assert(false); return null; } - - ulong uId; - if(!m_dUuidToId.TryGetValue(pwUuid, out uId)) return null; - Debug.Assert(uId != 0); - - return GetItemById(uId); - } - - public IStructureItem GetItemById(ulong uId) - { - IStructureItem p; - m_dIdToItem.TryGetValue(uId, out p); - return p; - } - } - - internal sealed class PwObjectBlock : IEnumerable - where T : class, ITimeLogger, IStructureItem, IDeepCloneable - { - private List m_l = new List(); - - public T PrimaryItem - { - get { return ((m_l.Count > 0) ? m_l[0] : null); } - } - - private DateTime m_dtLocationChanged = TimeUtil.SafeMinValueUtc; - public DateTime LocationChanged - { - get { return m_dtLocationChanged; } - } - - private PwObjectPoolEx m_poolAssoc = null; - public PwObjectPoolEx PoolAssoc - { - get { return m_poolAssoc; } - } - - public PwObjectBlock() - { - } - -#if DEBUG - public override string ToString() - { - return ("PwObjectBlock, Count = " + m_l.Count.ToString()); - } -#endif - - IEnumerator IEnumerable.GetEnumerator() - { - return m_l.GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - return m_l.GetEnumerator(); - } - - public void Add(T t, DateTime dtLoc, PwObjectPoolEx pool) - { - if(t == null) { Debug.Assert(false); return; } - - m_l.Add(t); - - if(dtLoc > m_dtLocationChanged) - { - m_dtLocationChanged = dtLoc; - m_poolAssoc = pool; - } - } - } -} diff --git a/ModernKeePassLib/Collections/StringDictionaryEx.cs b/ModernKeePassLib/Collections/StringDictionaryEx.cs deleted file mode 100644 index 570ece3..0000000 --- a/ModernKeePassLib/Collections/StringDictionaryEx.cs +++ /dev/null @@ -1,130 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -using ModernKeePassLib.Interfaces; - -#if KeePassLibSD -using KeePassLibSD; -#endif - -namespace ModernKeePassLib.Collections -{ - public sealed class StringDictionaryEx : IDeepCloneable, - IEnumerable>, IEquatable - { - private SortedDictionary m_dict = - new SortedDictionary(); - - public int Count - { - get { return m_dict.Count; } - } - - public StringDictionaryEx() - { - } - - IEnumerator IEnumerable.GetEnumerator() - { - return m_dict.GetEnumerator(); - } - - public IEnumerator> GetEnumerator() - { - return m_dict.GetEnumerator(); - } - - public StringDictionaryEx CloneDeep() - { - StringDictionaryEx sdNew = new StringDictionaryEx(); - - foreach(KeyValuePair kvp in m_dict) - sdNew.m_dict[kvp.Key] = kvp.Value; // Strings are immutable - - return sdNew; - } - - public bool Equals(StringDictionaryEx sdOther) - { - if(sdOther == null) { Debug.Assert(false); return false; } - - if(m_dict.Count != sdOther.m_dict.Count) return false; - - foreach(KeyValuePair kvp in sdOther.m_dict) - { - string str = Get(kvp.Key); - if((str == null) || (str != kvp.Value)) return false; - } - - return true; - } - - public string Get(string strName) - { - if(strName == null) { Debug.Assert(false); throw new ArgumentNullException("strName"); } - - string s; - if(m_dict.TryGetValue(strName, out s)) return s; - return null; - } - - public bool Exists(string strName) - { - if(strName == null) { Debug.Assert(false); throw new ArgumentNullException("strName"); } - - return m_dict.ContainsKey(strName); - } - - /// - /// Set a string. - /// - /// Identifier of the string field to modify. - /// New value. This parameter must not be null. - /// Thrown if one of the input - /// parameters is null. - public void Set(string strField, string strNewValue) - { - if(strField == null) { Debug.Assert(false); throw new ArgumentNullException("strField"); } - if(strNewValue == null) { Debug.Assert(false); throw new ArgumentNullException("strNewValue"); } - - m_dict[strField] = strNewValue; - } - - /// - /// Delete a string. - /// - /// Name of the string field to delete. - /// Returns true, if the field has been successfully - /// removed. Otherwise, the return value is false. - /// Thrown if the input - /// parameter is null. - public bool Remove(string strField) - { - if(strField == null) { Debug.Assert(false); throw new ArgumentNullException("strField"); } - - return m_dict.Remove(strField); - } - } -} diff --git a/ModernKeePassLib/Collections/VariantDictionary.cs b/ModernKeePassLib/Collections/VariantDictionary.cs deleted file mode 100644 index cb66d90..0000000 --- a/ModernKeePassLib/Collections/VariantDictionary.cs +++ /dev/null @@ -1,415 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; - -using ModernKeePassLib.Resources; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Collections -{ - public class VariantDictionary - { - private const ushort VdVersion = 0x0100; - private const ushort VdmCritical = 0xFF00; - private const ushort VdmInfo = 0x00FF; - - private Dictionary m_d = new Dictionary(); - - private enum VdType : byte - { - None = 0, - - // Byte = 0x02, - // UInt16 = 0x03, - UInt32 = 0x04, - UInt64 = 0x05, - - // Signed mask: 0x08 - Bool = 0x08, - // SByte = 0x0A, - // Int16 = 0x0B, - Int32 = 0x0C, - Int64 = 0x0D, - - // Float = 0x10, - // Double = 0x11, - // Decimal = 0x12, - - // Char = 0x17, // 16-bit Unicode character - String = 0x18, - - // Array mask: 0x40 - ByteArray = 0x42 - } - - public int Count - { - get { return m_d.Count; } - } - - public VariantDictionary() - { - Debug.Assert((VdmCritical & VdmInfo) == ushort.MinValue); - Debug.Assert((VdmCritical | VdmInfo) == ushort.MaxValue); - } - - private bool Get(string strName, out T t) - { - t = default(T); - - if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return false; } - - object o; - if(!m_d.TryGetValue(strName, out o)) return false; // No assert - - if(o == null) { Debug.Assert(false); return false; } - if(o.GetType() != typeof(T)) { Debug.Assert(false); return false; } - - t = (T)o; - return true; - } - - private void SetStruct(string strName, T t) - where T : struct - { - if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return; } - -#if DEBUG - T tEx; - Get(strName, out tEx); // Assert same type -#endif - - m_d[strName] = t; - } - - private void SetRef(string strName, T t) - where T : class - { - if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return; } - if(t == null) { Debug.Assert(false); return; } - -#if DEBUG - T tEx; - Get(strName, out tEx); // Assert same type -#endif - - m_d[strName] = t; - } - - public bool Remove(string strName) - { - if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return false; } - - return m_d.Remove(strName); - } - - public void CopyTo(VariantDictionary d) - { - if(d == null) { Debug.Assert(false); return; } - - // Do not clear the target - foreach(KeyValuePair kvp in m_d) - { - d.m_d[kvp.Key] = kvp.Value; - } - } - - public Type GetTypeOf(string strName) - { - if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return null; } - - object o; - m_d.TryGetValue(strName, out o); - if(o == null) return null; // No assert - - return o.GetType(); - } - - public uint GetUInt32(string strName, uint uDefault) - { - uint u; - if(Get(strName, out u)) return u; - return uDefault; - } - - public void SetUInt32(string strName, uint uValue) - { - SetStruct(strName, uValue); - } - - public ulong GetUInt64(string strName, ulong uDefault) - { - ulong u; - if(Get(strName, out u)) return u; - return uDefault; - } - - public void SetUInt64(string strName, ulong uValue) - { - SetStruct(strName, uValue); - } - - public bool GetBool(string strName, bool bDefault) - { - bool b; - if(Get(strName, out b)) return b; - return bDefault; - } - - public void SetBool(string strName, bool bValue) - { - SetStruct(strName, bValue); - } - - public int GetInt32(string strName, int iDefault) - { - int i; - if(Get(strName, out i)) return i; - return iDefault; - } - - public void SetInt32(string strName, int iValue) - { - SetStruct(strName, iValue); - } - - public long GetInt64(string strName, long lDefault) - { - long l; - if(Get(strName, out l)) return l; - return lDefault; - } - - public void SetInt64(string strName, long lValue) - { - SetStruct(strName, lValue); - } - - public string GetString(string strName) - { - string str; - Get(strName, out str); - return str; - } - - public void SetString(string strName, string strValue) - { - SetRef(strName, strValue); - } - - public byte[] GetByteArray(string strName) - { - byte[] pb; - Get(strName, out pb); - return pb; - } - - public void SetByteArray(string strName, byte[] pbValue) - { - SetRef(strName, pbValue); - } - - /// - /// Create a deep copy. - /// - public virtual object Clone() - { - VariantDictionary vdNew = new VariantDictionary(); - - foreach(KeyValuePair kvp in m_d) - { - object o = kvp.Value; - if(o == null) { Debug.Assert(false); continue; } - - Type t = o.GetType(); - if(t == typeof(byte[])) - { - byte[] p = (byte[])o; - byte[] pNew = new byte[p.Length]; - if(p.Length > 0) Array.Copy(p, pNew, p.Length); - - o = pNew; - } - - vdNew.m_d[kvp.Key] = o; - } - - return vdNew; - } - - public static byte[] Serialize(VariantDictionary p) - { - if(p == null) { Debug.Assert(false); return null; } - - byte[] pbRet; - using(MemoryStream ms = new MemoryStream()) - { - MemUtil.Write(ms, MemUtil.UInt16ToBytes(VdVersion)); - - foreach(KeyValuePair kvp in p.m_d) - { - string strName = kvp.Key; - if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); continue; } - byte[] pbName = StrUtil.Utf8.GetBytes(strName); - - object o = kvp.Value; - if(o == null) { Debug.Assert(false); continue; } - - Type t = o.GetType(); - VdType vt = VdType.None; - byte[] pbValue = null; - if(t == typeof(uint)) - { - vt = VdType.UInt32; - pbValue = MemUtil.UInt32ToBytes((uint)o); - } - else if(t == typeof(ulong)) - { - vt = VdType.UInt64; - pbValue = MemUtil.UInt64ToBytes((ulong)o); - } - else if(t == typeof(bool)) - { - vt = VdType.Bool; - pbValue = new byte[1]; - pbValue[0] = ((bool)o ? (byte)1 : (byte)0); - } - else if(t == typeof(int)) - { - vt = VdType.Int32; - pbValue = MemUtil.Int32ToBytes((int)o); - } - else if(t == typeof(long)) - { - vt = VdType.Int64; - pbValue = MemUtil.Int64ToBytes((long)o); - } - else if(t == typeof(string)) - { - vt = VdType.String; - pbValue = StrUtil.Utf8.GetBytes((string)o); - } - else if(t == typeof(byte[])) - { - vt = VdType.ByteArray; - pbValue = (byte[])o; - } - else { Debug.Assert(false); continue; } // Unknown type - - ms.WriteByte((byte)vt); - MemUtil.Write(ms, MemUtil.Int32ToBytes(pbName.Length)); - MemUtil.Write(ms, pbName); - MemUtil.Write(ms, MemUtil.Int32ToBytes(pbValue.Length)); - MemUtil.Write(ms, pbValue); - } - - ms.WriteByte((byte)VdType.None); - pbRet = ms.ToArray(); - } - - return pbRet; - } - - public static VariantDictionary Deserialize(byte[] pb) - { - if(pb == null) { Debug.Assert(false); return null; } - - VariantDictionary d = new VariantDictionary(); - using(MemoryStream ms = new MemoryStream(pb, false)) - { - ushort uVersion = MemUtil.BytesToUInt16(MemUtil.Read(ms, 2)); - if((uVersion & VdmCritical) > (VdVersion & VdmCritical)) - throw new FormatException(KLRes.FileNewVerReq); - - while(true) - { - int iType = ms.ReadByte(); - if(iType < 0) throw new EndOfStreamException(KLRes.FileCorrupted); - byte btType = (byte)iType; - if(btType == (byte)VdType.None) break; - - int cbName = MemUtil.BytesToInt32(MemUtil.Read(ms, 4)); - byte[] pbName = MemUtil.Read(ms, cbName); - if(pbName.Length != cbName) - throw new EndOfStreamException(KLRes.FileCorrupted); - string strName = StrUtil.Utf8.GetString(pbName, 0, pbName.Length); - - int cbValue = MemUtil.BytesToInt32(MemUtil.Read(ms, 4)); - byte[] pbValue = MemUtil.Read(ms, cbValue); - if(pbValue.Length != cbValue) - throw new EndOfStreamException(KLRes.FileCorrupted); - - switch(btType) - { - case (byte)VdType.UInt32: - if(cbValue == 4) - d.SetUInt32(strName, MemUtil.BytesToUInt32(pbValue)); - else { Debug.Assert(false); } - break; - - case (byte)VdType.UInt64: - if(cbValue == 8) - d.SetUInt64(strName, MemUtil.BytesToUInt64(pbValue)); - else { Debug.Assert(false); } - break; - - case (byte)VdType.Bool: - if(cbValue == 1) - d.SetBool(strName, (pbValue[0] != 0)); - else { Debug.Assert(false); } - break; - - case (byte)VdType.Int32: - if(cbValue == 4) - d.SetInt32(strName, MemUtil.BytesToInt32(pbValue)); - else { Debug.Assert(false); } - break; - - case (byte)VdType.Int64: - if(cbValue == 8) - d.SetInt64(strName, MemUtil.BytesToInt64(pbValue)); - else { Debug.Assert(false); } - break; - - case (byte)VdType.String: - d.SetString(strName, StrUtil.Utf8.GetString(pbValue, 0, pbValue.Length)); - break; - - case (byte)VdType.ByteArray: - d.SetByteArray(strName, pbValue); - break; - - default: - Debug.Assert(false); // Unknown type - break; - } - } - - Debug.Assert(ms.ReadByte() < 0); - } - - return d; - } - } -} diff --git a/ModernKeePassLib/Cryptography/Cipher/ChaCha20Cipher.cs b/ModernKeePassLib/Cryptography/Cipher/ChaCha20Cipher.cs deleted file mode 100644 index 907c17a..0000000 --- a/ModernKeePassLib/Cryptography/Cipher/ChaCha20Cipher.cs +++ /dev/null @@ -1,254 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; - -using ModernKeePassLib.Resources; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.Cipher -{ - /// - /// Implementation of the ChaCha20 cipher with a 96-bit nonce, - /// as specified in RFC 7539. - /// https://tools.ietf.org/html/rfc7539 - /// - public sealed class ChaCha20Cipher : CtrBlockCipher - { - private uint[] m_s = new uint[16]; // State - private uint[] m_x = new uint[16]; // Working buffer - - private bool m_bLargeCounter; // See constructor documentation - - private static readonly uint[] g_sigma = new uint[4] { - 0x61707865, 0x3320646E, 0x79622D32, 0x6B206574 - }; - - private const string StrNameRfc = "ChaCha20 (RFC 7539)"; - - public override int BlockSize - { - get { return 64; } - } - - public ChaCha20Cipher(byte[] pbKey32, byte[] pbIV12) : - this(pbKey32, pbIV12, false) - { - } - - /// - /// Constructor. - /// - /// Key (32 bytes). - /// Nonce (12 bytes). - /// If false, the RFC 7539 version - /// of ChaCha20 is used. In this case, only 256 GB of data can be - /// encrypted securely (because the block counter is a 32-bit variable); - /// an attempt to encrypt more data throws an exception. - /// If is true, the 32-bit - /// counter overflows to another 32-bit variable (i.e. the counter - /// effectively is a 64-bit variable), like in the original ChaCha20 - /// specification by D. J. Bernstein (which has a 64-bit counter and a - /// 64-bit nonce). To be compatible with this version, the 64-bit nonce - /// must be stored in the last 8 bytes of - /// and the first 4 bytes must be 0. - /// If the IV was generated randomly, a 12-byte IV and a large counter - /// can be used to securely encrypt more than 256 GB of data (but note - /// this is incompatible with RFC 7539 and the original specification). - public ChaCha20Cipher(byte[] pbKey32, byte[] pbIV12, bool bLargeCounter) : - base() - { - if(pbKey32 == null) throw new ArgumentNullException("pbKey32"); - if(pbKey32.Length != 32) throw new ArgumentOutOfRangeException("pbKey32"); - if(pbIV12 == null) throw new ArgumentNullException("pbIV12"); - if(pbIV12.Length != 12) throw new ArgumentOutOfRangeException("pbIV12"); - - m_bLargeCounter = bLargeCounter; - - // Key setup - m_s[4] = MemUtil.BytesToUInt32(pbKey32, 0); - m_s[5] = MemUtil.BytesToUInt32(pbKey32, 4); - m_s[6] = MemUtil.BytesToUInt32(pbKey32, 8); - m_s[7] = MemUtil.BytesToUInt32(pbKey32, 12); - m_s[8] = MemUtil.BytesToUInt32(pbKey32, 16); - m_s[9] = MemUtil.BytesToUInt32(pbKey32, 20); - m_s[10] = MemUtil.BytesToUInt32(pbKey32, 24); - m_s[11] = MemUtil.BytesToUInt32(pbKey32, 28); - m_s[0] = g_sigma[0]; - m_s[1] = g_sigma[1]; - m_s[2] = g_sigma[2]; - m_s[3] = g_sigma[3]; - - // IV setup - m_s[12] = 0; // Counter - m_s[13] = MemUtil.BytesToUInt32(pbIV12, 0); - m_s[14] = MemUtil.BytesToUInt32(pbIV12, 4); - m_s[15] = MemUtil.BytesToUInt32(pbIV12, 8); - } - - protected override void Dispose(bool bDisposing) - { - if(bDisposing) - { - MemUtil.ZeroArray(m_s); - MemUtil.ZeroArray(m_x); - } - - base.Dispose(bDisposing); - } - - protected override void NextBlock(byte[] pBlock) - { - if(pBlock == null) throw new ArgumentNullException("pBlock"); - if(pBlock.Length != 64) throw new ArgumentOutOfRangeException("pBlock"); - - // x is a local alias for the working buffer; with this, - // the compiler/runtime might remove some checks - uint[] x = m_x; - if(x == null) throw new InvalidOperationException(); - if(x.Length < 16) throw new InvalidOperationException(); - - uint[] s = m_s; - if(s == null) throw new InvalidOperationException(); - if(s.Length < 16) throw new InvalidOperationException(); - - Array.Copy(s, x, 16); - - unchecked - { - // 10 * 8 quarter rounds = 20 rounds - for(int i = 0; i < 10; ++i) - { - // Column quarter rounds - x[ 0] += x[ 4]; - x[12] = MemUtil.RotateLeft32(x[12] ^ x[ 0], 16); - x[ 8] += x[12]; - x[ 4] = MemUtil.RotateLeft32(x[ 4] ^ x[ 8], 12); - x[ 0] += x[ 4]; - x[12] = MemUtil.RotateLeft32(x[12] ^ x[ 0], 8); - x[ 8] += x[12]; - x[ 4] = MemUtil.RotateLeft32(x[ 4] ^ x[ 8], 7); - - x[ 1] += x[ 5]; - x[13] = MemUtil.RotateLeft32(x[13] ^ x[ 1], 16); - x[ 9] += x[13]; - x[ 5] = MemUtil.RotateLeft32(x[ 5] ^ x[ 9], 12); - x[ 1] += x[ 5]; - x[13] = MemUtil.RotateLeft32(x[13] ^ x[ 1], 8); - x[ 9] += x[13]; - x[ 5] = MemUtil.RotateLeft32(x[ 5] ^ x[ 9], 7); - - x[ 2] += x[ 6]; - x[14] = MemUtil.RotateLeft32(x[14] ^ x[ 2], 16); - x[10] += x[14]; - x[ 6] = MemUtil.RotateLeft32(x[ 6] ^ x[10], 12); - x[ 2] += x[ 6]; - x[14] = MemUtil.RotateLeft32(x[14] ^ x[ 2], 8); - x[10] += x[14]; - x[ 6] = MemUtil.RotateLeft32(x[ 6] ^ x[10], 7); - - x[ 3] += x[ 7]; - x[15] = MemUtil.RotateLeft32(x[15] ^ x[ 3], 16); - x[11] += x[15]; - x[ 7] = MemUtil.RotateLeft32(x[ 7] ^ x[11], 12); - x[ 3] += x[ 7]; - x[15] = MemUtil.RotateLeft32(x[15] ^ x[ 3], 8); - x[11] += x[15]; - x[ 7] = MemUtil.RotateLeft32(x[ 7] ^ x[11], 7); - - // Diagonal quarter rounds - x[ 0] += x[ 5]; - x[15] = MemUtil.RotateLeft32(x[15] ^ x[ 0], 16); - x[10] += x[15]; - x[ 5] = MemUtil.RotateLeft32(x[ 5] ^ x[10], 12); - x[ 0] += x[ 5]; - x[15] = MemUtil.RotateLeft32(x[15] ^ x[ 0], 8); - x[10] += x[15]; - x[ 5] = MemUtil.RotateLeft32(x[ 5] ^ x[10], 7); - - x[ 1] += x[ 6]; - x[12] = MemUtil.RotateLeft32(x[12] ^ x[ 1], 16); - x[11] += x[12]; - x[ 6] = MemUtil.RotateLeft32(x[ 6] ^ x[11], 12); - x[ 1] += x[ 6]; - x[12] = MemUtil.RotateLeft32(x[12] ^ x[ 1], 8); - x[11] += x[12]; - x[ 6] = MemUtil.RotateLeft32(x[ 6] ^ x[11], 7); - - x[ 2] += x[ 7]; - x[13] = MemUtil.RotateLeft32(x[13] ^ x[ 2], 16); - x[ 8] += x[13]; - x[ 7] = MemUtil.RotateLeft32(x[ 7] ^ x[ 8], 12); - x[ 2] += x[ 7]; - x[13] = MemUtil.RotateLeft32(x[13] ^ x[ 2], 8); - x[ 8] += x[13]; - x[ 7] = MemUtil.RotateLeft32(x[ 7] ^ x[ 8], 7); - - x[ 3] += x[ 4]; - x[14] = MemUtil.RotateLeft32(x[14] ^ x[ 3], 16); - x[ 9] += x[14]; - x[ 4] = MemUtil.RotateLeft32(x[ 4] ^ x[ 9], 12); - x[ 3] += x[ 4]; - x[14] = MemUtil.RotateLeft32(x[14] ^ x[ 3], 8); - x[ 9] += x[14]; - x[ 4] = MemUtil.RotateLeft32(x[ 4] ^ x[ 9], 7); - } - - for(int i = 0; i < 16; ++i) x[i] += s[i]; - - for(int i = 0; i < 16; ++i) - { - int i4 = i << 2; - uint xi = x[i]; - - pBlock[i4] = (byte)xi; - pBlock[i4 + 1] = (byte)(xi >> 8); - pBlock[i4 + 2] = (byte)(xi >> 16); - pBlock[i4 + 3] = (byte)(xi >> 24); - } - - ++s[12]; - if(s[12] == 0) - { - if(!m_bLargeCounter) - throw new InvalidOperationException( - KLRes.EncDataTooLarge.Replace(@"{PARAM}", StrNameRfc)); - ++s[13]; // Increment high half of large counter - } - } - } - - public long Seek(long lOffset, SeekOrigin so) - { - if(so != SeekOrigin.Begin) throw new NotSupportedException(); - - if((lOffset < 0) || ((lOffset & 63) != 0) || - ((lOffset >> 6) > (long)uint.MaxValue)) - throw new ArgumentOutOfRangeException("lOffset"); - - m_s[12] = (uint)(lOffset >> 6); - InvalidateBlock(); - - return lOffset; - } - } -} diff --git a/ModernKeePassLib/Cryptography/Cipher/ChaCha20Engine.cs b/ModernKeePassLib/Cryptography/Cipher/ChaCha20Engine.cs deleted file mode 100644 index 31ab9e5..0000000 --- a/ModernKeePassLib/Cryptography/Cipher/ChaCha20Engine.cs +++ /dev/null @@ -1,177 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; - -using ModernKeePassLib.Resources; - -namespace ModernKeePassLib.Cryptography.Cipher -{ - public sealed class ChaCha20Engine : ICipherEngine2 - { - private PwUuid m_uuid = new PwUuid(new byte[] { - 0xD6, 0x03, 0x8A, 0x2B, 0x8B, 0x6F, 0x4C, 0xB5, - 0xA5, 0x24, 0x33, 0x9A, 0x31, 0xDB, 0xB5, 0x9A - }); - - public PwUuid CipherUuid - { - get { return m_uuid; } - } - - public string DisplayName - { - get - { - return ("ChaCha20 (" + KLRes.KeyBits.Replace(@"{PARAM}", - "256") + ", RFC 7539)"); - } - } - - public int KeyLength - { - get { return 32; } - } - - public int IVLength - { - get { return 12; } // 96 bits - } - - public Stream EncryptStream(Stream sPlainText, byte[] pbKey, byte[] pbIV) - { - return new ChaCha20Stream(sPlainText, true, pbKey, pbIV); - } - - public Stream DecryptStream(Stream sEncrypted, byte[] pbKey, byte[] pbIV) - { - return new ChaCha20Stream(sEncrypted, false, pbKey, pbIV); - } - } - - public sealed class ChaCha20Stream : Stream - { - private Stream m_sBase; - private readonly bool m_bWriting; - private ChaCha20Cipher m_c; - - private byte[] m_pbBuffer = null; - - public override bool CanRead - { - get { return !m_bWriting; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return m_bWriting; } - } - - public override long Length - { - get { Debug.Assert(false); throw new NotSupportedException(); } - } - - public override long Position - { - get { Debug.Assert(false); throw new NotSupportedException(); } - set { Debug.Assert(false); throw new NotSupportedException(); } - } - - public ChaCha20Stream(Stream sBase, bool bWriting, byte[] pbKey32, - byte[] pbIV12) - { - if(sBase == null) throw new ArgumentNullException("sBase"); - - m_sBase = sBase; - m_bWriting = bWriting; - m_c = new ChaCha20Cipher(pbKey32, pbIV12); - } - - protected override void Dispose(bool bDisposing) - { - if(bDisposing) - { - if(m_sBase != null) - { - m_c.Dispose(); - m_c = null; - - m_sBase.Dispose(); - m_sBase = null; - } - - m_pbBuffer = null; - } - - base.Dispose(bDisposing); - } - - public override void Flush() - { - Debug.Assert(m_sBase != null); - if(m_bWriting && (m_sBase != null)) m_sBase.Flush(); - } - - public override long Seek(long lOffset, SeekOrigin soOrigin) - { - Debug.Assert(false); - throw new NotImplementedException(); - } - - public override void SetLength(long lValue) - { - Debug.Assert(false); - throw new NotImplementedException(); - } - - public override int Read(byte[] pbBuffer, int iOffset, int nCount) - { - if(m_bWriting) throw new InvalidOperationException(); - - int cbRead = m_sBase.Read(pbBuffer, iOffset, nCount); - m_c.Decrypt(pbBuffer, iOffset, cbRead); - return cbRead; - } - - public override void Write(byte[] pbBuffer, int iOffset, int nCount) - { - if(nCount < 0) throw new ArgumentOutOfRangeException("nCount"); - if(nCount == 0) return; - - if(!m_bWriting) throw new InvalidOperationException(); - - if((m_pbBuffer == null) || (m_pbBuffer.Length < nCount)) - m_pbBuffer = new byte[nCount]; - Array.Copy(pbBuffer, iOffset, m_pbBuffer, 0, nCount); - - m_c.Encrypt(m_pbBuffer, 0, nCount); - m_sBase.Write(m_pbBuffer, 0, nCount); - } - } -} diff --git a/ModernKeePassLib/Cryptography/Cipher/CipherPool.cs b/ModernKeePassLib/Cryptography/Cipher/CipherPool.cs deleted file mode 100644 index 49df33b..0000000 --- a/ModernKeePassLib/Cryptography/Cipher/CipherPool.cs +++ /dev/null @@ -1,165 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using System.Diagnostics; - -namespace ModernKeePassLib.Cryptography.Cipher -{ - /// - /// Pool of encryption/decryption algorithms (ciphers). - /// - public sealed class CipherPool - { - private List m_vCiphers = new List(); - private static CipherPool m_poolGlobal = null; - - /// - /// Reference to the global cipher pool. - /// - public static CipherPool GlobalPool - { - get - { - CipherPool cp = m_poolGlobal; - if(cp == null) - { - cp = new CipherPool(); - cp.AddCipher(new StandardAesEngine()); - cp.AddCipher(new ChaCha20Engine()); - - m_poolGlobal = cp; - } - - return cp; - } - } - - /// - /// Remove all cipher engines from the current pool. - /// - public void Clear() - { - m_vCiphers.Clear(); - } - - /// - /// Add a cipher engine to the pool. - /// - /// Cipher engine to add. Must not be null. - public void AddCipher(ICipherEngine csEngine) - { - Debug.Assert(csEngine != null); - if(csEngine == null) throw new ArgumentNullException("csEngine"); - - // Return if a cipher with that ID is registered already. - for(int i = 0; i < m_vCiphers.Count; ++i) - if(m_vCiphers[i].CipherUuid.Equals(csEngine.CipherUuid)) - return; - - m_vCiphers.Add(csEngine); - } - - /// - /// Get a cipher identified by its UUID. - /// - /// UUID of the cipher to return. - /// Reference to the requested cipher. If the cipher is - /// not found, null is returned. - public ICipherEngine GetCipher(PwUuid uuidCipher) - { - foreach(ICipherEngine iEngine in m_vCiphers) - { - if(iEngine.CipherUuid.Equals(uuidCipher)) - return iEngine; - } - - return null; - } - - /// - /// Get the index of a cipher. This index is temporary and should - /// not be stored or used to identify a cipher. - /// - /// UUID of the cipher. - /// Index of the requested cipher. Returns -1 if - /// the specified cipher is not found. - public int GetCipherIndex(PwUuid uuidCipher) - { - for(int i = 0; i < m_vCiphers.Count; ++i) - { - if(m_vCiphers[i].CipherUuid.Equals(uuidCipher)) - return i; - } - - Debug.Assert(false); - return -1; - } - - /// - /// Get the index of a cipher. This index is temporary and should - /// not be stored or used to identify a cipher. - /// - /// Name of the cipher. Note that - /// multiple ciphers can have the same name. In this case, the - /// first matching cipher is returned. - /// Cipher with the specified name or -1 if - /// no cipher with that name is found. - public int GetCipherIndex(string strDisplayName) - { - for(int i = 0; i < m_vCiphers.Count; ++i) - if(m_vCiphers[i].DisplayName == strDisplayName) - return i; - - Debug.Assert(false); - return -1; - } - - /// - /// Get the number of cipher engines in this pool. - /// - public int EngineCount - { - get { return m_vCiphers.Count; } - } - - /// - /// Get the cipher engine at the specified position. Throws - /// an exception if the index is invalid. You can use this - /// to iterate over all ciphers, but do not use it to - /// identify ciphers. - /// - /// Index of the requested cipher engine. - /// Reference to the cipher engine at the specified - /// position. - public ICipherEngine this[int nIndex] - { - get - { - if((nIndex < 0) || (nIndex >= m_vCiphers.Count)) - throw new ArgumentOutOfRangeException("nIndex"); - - return m_vCiphers[nIndex]; - } - } - } -} diff --git a/ModernKeePassLib/Cryptography/Cipher/CtrBlockCipher.cs b/ModernKeePassLib/Cryptography/Cipher/CtrBlockCipher.cs deleted file mode 100644 index a428e7c..0000000 --- a/ModernKeePassLib/Cryptography/Cipher/CtrBlockCipher.cs +++ /dev/null @@ -1,109 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.Cipher -{ - public abstract class CtrBlockCipher : IDisposable - { - private bool m_bDisposed = false; - - private byte[] m_pBlock; - private int m_iBlockPos; - - public abstract int BlockSize - { - get; - } - - public CtrBlockCipher() - { - int cb = this.BlockSize; - if(cb <= 0) throw new InvalidOperationException("this.BlockSize"); - - m_pBlock = new byte[cb]; - m_iBlockPos = cb; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool bDisposing) - { - if(bDisposing) - { - MemUtil.ZeroByteArray(m_pBlock); - m_iBlockPos = m_pBlock.Length; - - m_bDisposed = true; - } - } - - protected void InvalidateBlock() - { - m_iBlockPos = m_pBlock.Length; - } - - protected abstract void NextBlock(byte[] pBlock); - - public void Encrypt(byte[] m, int iOffset, int cb) - { - if(m_bDisposed) throw new ObjectDisposedException(null); - if(m == null) throw new ArgumentNullException("m"); - if(iOffset < 0) throw new ArgumentOutOfRangeException("iOffset"); - if(cb < 0) throw new ArgumentOutOfRangeException("cb"); - if(iOffset > (m.Length - cb)) throw new ArgumentOutOfRangeException("cb"); - - int cbBlock = m_pBlock.Length; - - while(cb > 0) - { - Debug.Assert(m_iBlockPos <= cbBlock); - if(m_iBlockPos == cbBlock) - { - NextBlock(m_pBlock); - m_iBlockPos = 0; - } - - int cbCopy = Math.Min(cbBlock - m_iBlockPos, cb); - Debug.Assert(cbCopy > 0); - - MemUtil.XorArray(m_pBlock, m_iBlockPos, m, iOffset, cbCopy); - - m_iBlockPos += cbCopy; - iOffset += cbCopy; - cb -= cbCopy; - } - } - - public void Decrypt(byte[] m, int iOffset, int cb) - { - Encrypt(m, iOffset, cb); - } - } -} diff --git a/ModernKeePassLib/Cryptography/Cipher/ICipherEngine.cs b/ModernKeePassLib/Cryptography/Cipher/ICipherEngine.cs deleted file mode 100644 index d4e257c..0000000 --- a/ModernKeePassLib/Cryptography/Cipher/ICipherEngine.cs +++ /dev/null @@ -1,87 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.IO; - -namespace ModernKeePassLib.Cryptography.Cipher -{ - /// - /// Interface of an encryption/decryption class. - /// - public interface ICipherEngine - { - /// - /// UUID of the engine. If you want to write an engine/plugin, - /// please contact the KeePass team to obtain a new UUID. - /// - PwUuid CipherUuid - { - get; - } - - /// - /// String displayed in the list of available encryption/decryption - /// engines in the GUI. - /// - string DisplayName - { - get; - } - - /// - /// Encrypt a stream. - /// - /// Stream to read the plain-text from. - /// Key to use. - /// Initialization vector. - /// Stream, from which the encrypted data can be read. - Stream EncryptStream(Stream sPlainText, byte[] pbKey, byte[] pbIV); - - /// - /// Decrypt a stream. - /// - /// Stream to read the encrypted data from. - /// Key to use. - /// Initialization vector. - /// Stream, from which the decrypted data can be read. - Stream DecryptStream(Stream sEncrypted, byte[] pbKey, byte[] pbIV); - } - - public interface ICipherEngine2 : ICipherEngine - { - /// - /// Length of an encryption key in bytes. - /// The base ICipherEngine assumes 32. - /// - int KeyLength - { - get; - } - - /// - /// Length of the initialization vector in bytes. - /// The base ICipherEngine assumes 16. - /// - int IVLength - { - get; - } - } -} diff --git a/ModernKeePassLib/Cryptography/Cipher/Salsa20Cipher.cs b/ModernKeePassLib/Cryptography/Cipher/Salsa20Cipher.cs deleted file mode 100644 index bec707b..0000000 --- a/ModernKeePassLib/Cryptography/Cipher/Salsa20Cipher.cs +++ /dev/null @@ -1,165 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// Implementation of the Salsa20 cipher, based on the eSTREAM -// submission by D. J. Bernstein. - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.Cipher -{ - public sealed class Salsa20Cipher : CtrBlockCipher - { - private uint[] m_s = new uint[16]; // State - private uint[] m_x = new uint[16]; // Working buffer - - private static readonly uint[] g_sigma = new uint[4] { - 0x61707865, 0x3320646E, 0x79622D32, 0x6B206574 - }; - - public override int BlockSize - { - get { return 64; } - } - - public Salsa20Cipher(byte[] pbKey32, byte[] pbIV8) : base() - { - if(pbKey32 == null) throw new ArgumentNullException("pbKey32"); - if(pbKey32.Length != 32) throw new ArgumentOutOfRangeException("pbKey32"); - if(pbIV8 == null) throw new ArgumentNullException("pbIV8"); - if(pbIV8.Length != 8) throw new ArgumentOutOfRangeException("pbIV8"); - - // Key setup - m_s[1] = MemUtil.BytesToUInt32(pbKey32, 0); - m_s[2] = MemUtil.BytesToUInt32(pbKey32, 4); - m_s[3] = MemUtil.BytesToUInt32(pbKey32, 8); - m_s[4] = MemUtil.BytesToUInt32(pbKey32, 12); - m_s[11] = MemUtil.BytesToUInt32(pbKey32, 16); - m_s[12] = MemUtil.BytesToUInt32(pbKey32, 20); - m_s[13] = MemUtil.BytesToUInt32(pbKey32, 24); - m_s[14] = MemUtil.BytesToUInt32(pbKey32, 28); - m_s[0] = g_sigma[0]; - m_s[5] = g_sigma[1]; - m_s[10] = g_sigma[2]; - m_s[15] = g_sigma[3]; - - // IV setup - m_s[6] = MemUtil.BytesToUInt32(pbIV8, 0); - m_s[7] = MemUtil.BytesToUInt32(pbIV8, 4); - m_s[8] = 0; // Counter, low - m_s[9] = 0; // Counter, high - } - - protected override void Dispose(bool bDisposing) - { - if(bDisposing) - { - MemUtil.ZeroArray(m_s); - MemUtil.ZeroArray(m_x); - } - - base.Dispose(bDisposing); - } - - protected override void NextBlock(byte[] pBlock) - { - if(pBlock == null) throw new ArgumentNullException("pBlock"); - if(pBlock.Length != 64) throw new ArgumentOutOfRangeException("pBlock"); - - // x is a local alias for the working buffer; with this, - // the compiler/runtime might remove some checks - uint[] x = m_x; - if(x == null) throw new InvalidOperationException(); - if(x.Length < 16) throw new InvalidOperationException(); - - uint[] s = m_s; - if(s == null) throw new InvalidOperationException(); - if(s.Length < 16) throw new InvalidOperationException(); - - Array.Copy(s, x, 16); - - unchecked - { - // 10 * 8 quarter rounds = 20 rounds - for(int i = 0; i < 10; ++i) - { - x[ 4] ^= MemUtil.RotateLeft32(x[ 0] + x[12], 7); - x[ 8] ^= MemUtil.RotateLeft32(x[ 4] + x[ 0], 9); - x[12] ^= MemUtil.RotateLeft32(x[ 8] + x[ 4], 13); - x[ 0] ^= MemUtil.RotateLeft32(x[12] + x[ 8], 18); - - x[ 9] ^= MemUtil.RotateLeft32(x[ 5] + x[ 1], 7); - x[13] ^= MemUtil.RotateLeft32(x[ 9] + x[ 5], 9); - x[ 1] ^= MemUtil.RotateLeft32(x[13] + x[ 9], 13); - x[ 5] ^= MemUtil.RotateLeft32(x[ 1] + x[13], 18); - - x[14] ^= MemUtil.RotateLeft32(x[10] + x[ 6], 7); - x[ 2] ^= MemUtil.RotateLeft32(x[14] + x[10], 9); - x[ 6] ^= MemUtil.RotateLeft32(x[ 2] + x[14], 13); - x[10] ^= MemUtil.RotateLeft32(x[ 6] + x[ 2], 18); - - x[ 3] ^= MemUtil.RotateLeft32(x[15] + x[11], 7); - x[ 7] ^= MemUtil.RotateLeft32(x[ 3] + x[15], 9); - x[11] ^= MemUtil.RotateLeft32(x[ 7] + x[ 3], 13); - x[15] ^= MemUtil.RotateLeft32(x[11] + x[ 7], 18); - - x[ 1] ^= MemUtil.RotateLeft32(x[ 0] + x[ 3], 7); - x[ 2] ^= MemUtil.RotateLeft32(x[ 1] + x[ 0], 9); - x[ 3] ^= MemUtil.RotateLeft32(x[ 2] + x[ 1], 13); - x[ 0] ^= MemUtil.RotateLeft32(x[ 3] + x[ 2], 18); - - x[ 6] ^= MemUtil.RotateLeft32(x[ 5] + x[ 4], 7); - x[ 7] ^= MemUtil.RotateLeft32(x[ 6] + x[ 5], 9); - x[ 4] ^= MemUtil.RotateLeft32(x[ 7] + x[ 6], 13); - x[ 5] ^= MemUtil.RotateLeft32(x[ 4] + x[ 7], 18); - - x[11] ^= MemUtil.RotateLeft32(x[10] + x[ 9], 7); - x[ 8] ^= MemUtil.RotateLeft32(x[11] + x[10], 9); - x[ 9] ^= MemUtil.RotateLeft32(x[ 8] + x[11], 13); - x[10] ^= MemUtil.RotateLeft32(x[ 9] + x[ 8], 18); - - x[12] ^= MemUtil.RotateLeft32(x[15] + x[14], 7); - x[13] ^= MemUtil.RotateLeft32(x[12] + x[15], 9); - x[14] ^= MemUtil.RotateLeft32(x[13] + x[12], 13); - x[15] ^= MemUtil.RotateLeft32(x[14] + x[13], 18); - } - - for(int i = 0; i < 16; ++i) x[i] += s[i]; - - for(int i = 0; i < 16; ++i) - { - int i4 = i << 2; - uint xi = x[i]; - - pBlock[i4] = (byte)xi; - pBlock[i4 + 1] = (byte)(xi >> 8); - pBlock[i4 + 2] = (byte)(xi >> 16); - pBlock[i4 + 3] = (byte)(xi >> 24); - } - - ++s[8]; - if(s[8] == 0) ++s[9]; - } - } - } -} diff --git a/ModernKeePassLib/Cryptography/Cipher/StandardAesEngine.cs b/ModernKeePassLib/Cryptography/Cipher/StandardAesEngine.cs deleted file mode 100644 index d47da91..0000000 --- a/ModernKeePassLib/Cryptography/Cipher/StandardAesEngine.cs +++ /dev/null @@ -1,173 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using System.Security; -using System.Diagnostics; -#if ModernKeePassLib -using ModernKeePassLib.Resources; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.IO; -using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Paddings; -using Org.BouncyCastle.Crypto.Parameters; -#else -using System.Security.Cryptography; -#endif - -namespace ModernKeePassLib.Cryptography.Cipher -{ - /// - /// Standard AES cipher implementation. - /// - public sealed class StandardAesEngine : ICipherEngine - { -#if !ModernKeePassLib && !KeePassUAP - private const CipherMode m_rCipherMode = CipherMode.CBC; - private const PaddingMode m_rCipherPadding = PaddingMode.PKCS7; -#endif - - private static PwUuid g_uuidAes = null; - - /// - /// UUID of the cipher engine. This ID uniquely identifies the - /// AES engine. Must not be used by other ciphers. - /// - public static PwUuid AesUuid - { - get - { - PwUuid pu = g_uuidAes; - if(pu == null) - { - pu = new PwUuid(new byte[] { - 0x31, 0xC1, 0xF2, 0xE6, 0xBF, 0x71, 0x43, 0x50, - 0xBE, 0x58, 0x05, 0x21, 0x6A, 0xFC, 0x5A, 0xFF }); - g_uuidAes = pu; - } - - return pu; - } - } - - /// - /// Get the UUID of this cipher engine as PwUuid object. - /// - public PwUuid CipherUuid - { - get { return StandardAesEngine.AesUuid; } - } - - /// - /// Get a displayable name describing this cipher engine. - /// - public string DisplayName - { - get - { - return ("AES/Rijndael (" + KLRes.KeyBits.Replace(@"{PARAM}", - "256") + ", FIPS 197)"); - } - } - - private static void ValidateArguments(Stream stream, bool bEncrypt, byte[] pbKey, byte[] pbIV) - { - Debug.Assert(stream != null); if(stream == null) throw new ArgumentNullException("stream"); - - Debug.Assert(pbKey != null); if(pbKey == null) throw new ArgumentNullException("pbKey"); - Debug.Assert(pbKey.Length == 32); - if(pbKey.Length != 32) throw new ArgumentException("Key must be 256 bits wide!"); - - Debug.Assert(pbIV != null); if(pbIV == null) throw new ArgumentNullException("pbIV"); - Debug.Assert(pbIV.Length == 16); - if(pbIV.Length != 16) throw new ArgumentException("Initialization vector must be 128 bits wide!"); - - if(bEncrypt) - { - Debug.Assert(stream.CanWrite); - if(!stream.CanWrite) throw new ArgumentException("Stream must be writable!"); - } - else // Decrypt - { - Debug.Assert(stream.CanRead); - if(!stream.CanRead) throw new ArgumentException("Encrypted stream must be readable!"); - } - } - - private static Stream CreateStream(Stream s, bool bEncrypt, byte[] pbKey, byte[] pbIV) - { - StandardAesEngine.ValidateArguments(s, bEncrypt, pbKey, pbIV); - - byte[] pbLocalIV = new byte[16]; - Array.Copy(pbIV, pbLocalIV, 16); - - byte[] pbLocalKey = new byte[32]; - Array.Copy(pbKey, pbLocalKey, 32); - -#if ModernKeePassLib - var cbc = new CbcBlockCipher(new AesEngine()); - var bc = new PaddedBufferedBlockCipher(cbc, - new Pkcs7Padding()); - var kp = new KeyParameter(pbLocalKey); - var prmIV = new ParametersWithIV(kp, pbLocalIV); - bc.Init(bEncrypt, prmIV); - - var cpRead = (bEncrypt ? null : bc); - var cpWrite = (bEncrypt ? bc : null); - return new CipherStream(s, cpRead, cpWrite); -#elif KeePassUAP - return StandardAesEngineExt.CreateStream(s, bEncrypt, pbLocalKey, pbLocalIV); -#else - SymmetricAlgorithm a = CryptoUtil.CreateAes(); - if(a.BlockSize != 128) // AES block size - { - Debug.Assert(false); - a.BlockSize = 128; - } - - a.IV = pbLocalIV; - a.KeySize = 256; - a.Key = pbLocalKey; - a.Mode = m_rCipherMode; - a.Padding = m_rCipherPadding; - - ICryptoTransform iTransform = (bEncrypt ? a.CreateEncryptor() : a.CreateDecryptor()); - Debug.Assert(iTransform != null); - if(iTransform == null) throw new SecurityException("Unable to create AES transform!"); - - return new CryptoStream(s, iTransform, bEncrypt ? CryptoStreamMode.Write : - CryptoStreamMode.Read); -#endif - } - - public Stream EncryptStream(Stream sPlainText, byte[] pbKey, byte[] pbIV) - { - return StandardAesEngine.CreateStream(sPlainText, true, pbKey, pbIV); - } - - public Stream DecryptStream(Stream sEncrypted, byte[] pbKey, byte[] pbIV) - { - return StandardAesEngine.CreateStream(sEncrypted, false, pbKey, pbIV); - } - } -} diff --git a/ModernKeePassLib/Cryptography/CryptoRandom.cs b/ModernKeePassLib/Cryptography/CryptoRandom.cs deleted file mode 100644 index 1a83aab..0000000 --- a/ModernKeePassLib/Cryptography/CryptoRandom.cs +++ /dev/null @@ -1,398 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -#if ModernKeePassLib -using ModernKeePassLib.Cryptography.Hash; -using Windows.Security.Cryptography; -#else -using System.Security.Cryptography; -using System.Windows.Forms; -#endif - -using ModernKeePassLib.Native; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography -{ - /// - /// Cryptographically secure pseudo-random number generator. - /// The returned values are unpredictable and cannot be reproduced. - /// CryptoRandom is a singleton class. - /// - public sealed class CryptoRandom - { - private byte[] m_pbEntropyPool = new byte[64]; - private ulong m_uCounter; -#if !ModernKeePassLib - private RNGCryptoServiceProvider m_rng = new RNGCryptoServiceProvider(); -#endif - private ulong m_uGeneratedBytesCount = 0; - - private static readonly object g_oSyncRoot = new object(); - private readonly object m_oSyncRoot = new object(); - - private static CryptoRandom g_pInstance = null; - public static CryptoRandom Instance - { - get - { - CryptoRandom cr; - lock(g_oSyncRoot) - { - cr = g_pInstance; - if(cr == null) - { - cr = new CryptoRandom(); - g_pInstance = cr; - } - } - - return cr; - } - } - - /// - /// Get the number of random bytes that this instance generated so far. - /// Note that this number can be higher than the number of random bytes - /// actually requested using the GetRandomBytes method. - /// - public ulong GeneratedBytesCount - { - get - { - ulong u; - lock(m_oSyncRoot) { u = m_uGeneratedBytesCount; } - return u; - } - } - - /// - /// Event that is triggered whenever the internal GenerateRandom256 - /// method is called to generate random bytes. - /// - public event EventHandler GenerateRandom256Pre; - - private CryptoRandom() - { - // Random rWeak = new Random(); // Based on tick count - // byte[] pb = new byte[8]; - // rWeak.NextBytes(pb); - // m_uCounter = MemUtil.BytesToUInt64(pb); - m_uCounter = (ulong)DateTime.UtcNow.ToBinary(); - - AddEntropy(GetSystemData()); - AddEntropy(GetCspData()); - } - - /// - /// Update the internal seed of the random number generator based - /// on entropy data. - /// This method is thread-safe. - /// - /// Entropy bytes. - public void AddEntropy(byte[] pbEntropy) - { - if(pbEntropy == null) { Debug.Assert(false); return; } - if(pbEntropy.Length == 0) { Debug.Assert(false); return; } - - byte[] pbNewData = pbEntropy; - if(pbEntropy.Length > 64) - { -#if KeePassLibSD - using(SHA256Managed shaNew = new SHA256Managed()) -#else - using(SHA512Managed shaNew = new SHA512Managed()) -#endif - { - pbNewData = shaNew.ComputeHash(pbEntropy); - } - } - - lock(m_oSyncRoot) - { - int cbPool = m_pbEntropyPool.Length; - int cbNew = pbNewData.Length; - - byte[] pbCmp = new byte[cbPool + cbNew]; - Array.Copy(m_pbEntropyPool, pbCmp, cbPool); - Array.Copy(pbNewData, 0, pbCmp, cbPool, cbNew); - - MemUtil.ZeroByteArray(m_pbEntropyPool); - -#if KeePassLibSD - using(SHA256Managed shaPool = new SHA256Managed()) -#else - using(SHA512Managed shaPool = new SHA512Managed()) -#endif - { - m_pbEntropyPool = shaPool.ComputeHash(pbCmp); - } - - MemUtil.ZeroByteArray(pbCmp); - } - } - - private static byte[] GetSystemData() - { - MemoryStream ms = new MemoryStream(); - byte[] pb; - - pb = MemUtil.Int32ToBytes(Environment.TickCount); - MemUtil.Write(ms, pb); - - pb = MemUtil.Int64ToBytes(DateTime.UtcNow.ToBinary()); - MemUtil.Write(ms, pb); - -#if (!ModernKeePassLib && !KeePassLibSD) - // In try-catch for systems without GUI; - // https://sourceforge.net/p/keepass/discussion/329221/thread/20335b73/ - try - { - Point pt = Cursor.Position; - pb = MemUtil.Int32ToBytes(pt.X); - MemUtil.Write(ms, pb); - pb = MemUtil.Int32ToBytes(pt.Y); - MemUtil.Write(ms, pb); - } - catch(Exception) { } -#endif -#if ModernKeePassLib - pb = MemUtil.UInt32ToBytes((uint)Environment.ProcessorCount); - ms.Write(pb, 0, pb.Length); - - pb = MemUtil.UInt32ToBytes((uint)Environment.CurrentManagedThreadId); - ms.Write(pb, 0, pb.Length); -#else - pb = MemUtil.UInt32ToBytes((uint)NativeLib.GetPlatformID()); - MemUtil.Write(ms, pb); - - try - { -#if KeePassUAP - string strOS = EnvironmentExt.OSVersion.VersionString; -#else - string strOS = Environment.OSVersion.VersionString; -#endif - AddStrHash(ms, strOS); - - pb = MemUtil.Int32ToBytes(Environment.ProcessorCount); - MemUtil.Write(ms, pb); - -#if !KeePassUAP - AddStrHash(ms, Environment.CommandLine); - - pb = MemUtil.Int64ToBytes(Environment.WorkingSet); - MemUtil.Write(ms, pb); -#endif - } - catch(Exception) { Debug.Assert(false); } - - try - { - foreach(DictionaryEntry de in Environment.GetEnvironmentVariables()) - { - AddStrHash(ms, (de.Key as string)); - AddStrHash(ms, (de.Value as string)); - } - } - catch(Exception) { Debug.Assert(false); } - -#if KeePassUAP - pb = DiagnosticsExt.GetProcessEntropy(); - MemUtil.Write(ms, pb); -#elif !KeePassLibSD - try - { - using(Process p = Process.GetCurrentProcess()) - { - pb = MemUtil.Int64ToBytes(p.Handle.ToInt64()); - MemUtil.Write(ms, pb); - pb = MemUtil.Int32ToBytes(p.HandleCount); - MemUtil.Write(ms, pb); - pb = MemUtil.Int32ToBytes(p.Id); - MemUtil.Write(ms, pb); - pb = MemUtil.Int64ToBytes(p.NonpagedSystemMemorySize64); - MemUtil.Write(ms, pb); - pb = MemUtil.Int64ToBytes(p.PagedMemorySize64); - MemUtil.Write(ms, pb); - pb = MemUtil.Int64ToBytes(p.PagedSystemMemorySize64); - MemUtil.Write(ms, pb); - pb = MemUtil.Int64ToBytes(p.PeakPagedMemorySize64); - MemUtil.Write(ms, pb); - pb = MemUtil.Int64ToBytes(p.PeakVirtualMemorySize64); - MemUtil.Write(ms, pb); - pb = MemUtil.Int64ToBytes(p.PeakWorkingSet64); - MemUtil.Write(ms, pb); - pb = MemUtil.Int64ToBytes(p.PrivateMemorySize64); - MemUtil.Write(ms, pb); - pb = MemUtil.Int64ToBytes(p.StartTime.ToBinary()); - MemUtil.Write(ms, pb); - pb = MemUtil.Int64ToBytes(p.VirtualMemorySize64); - MemUtil.Write(ms, pb); - pb = MemUtil.Int64ToBytes(p.WorkingSet64); - MemUtil.Write(ms, pb); - - // Not supported in Mono 1.2.6: - // pb = MemUtil.UInt32ToBytes((uint)p.SessionId); - // MemUtil.Write(ms, pb); - } - } - catch(Exception) { Debug.Assert(NativeLib.IsUnix()); } -#endif -#endif - - try - { - CultureInfo ci = CultureInfo.CurrentCulture; - if(ci != null) - { - pb = MemUtil.Int32ToBytes(ci.GetHashCode()); - MemUtil.Write(ms, pb); - } - else { Debug.Assert(false); } - } - catch(Exception) { Debug.Assert(false); } - - pb = Guid.NewGuid().ToByteArray(); - MemUtil.Write(ms, pb); - - byte[] pbAll = ms.ToArray(); - ms.Dispose(); - return pbAll; - } - - private static void AddStrHash(Stream s, string str) - { - if(s == null) { Debug.Assert(false); return; } - if(string.IsNullOrEmpty(str)) return; - - byte[] pbUtf8 = StrUtil.Utf8.GetBytes(str); - byte[] pbHash = CryptoUtil.HashSha256(pbUtf8); - MemUtil.Write(s, pbHash); - } - - private byte[] GetCspData() - { - byte[] pbCspRandom = new byte[32]; -#if ModernKeePassLib - CryptographicBuffer.CopyToByteArray(CryptographicBuffer.GenerateRandom(32), out pbCspRandom); -#else - m_rng.GetBytes(pbCspRandom); -#endif - return pbCspRandom; - } - - private byte[] GenerateRandom256() - { - if(this.GenerateRandom256Pre != null) - this.GenerateRandom256Pre(this, EventArgs.Empty); - - byte[] pbCmp; - lock(m_oSyncRoot) - { - m_uCounter += 0x74D8B29E4D38E161UL; // Prime number - byte[] pbCounter = MemUtil.UInt64ToBytes(m_uCounter); - - byte[] pbCspRandom = GetCspData(); - - int cbPool = m_pbEntropyPool.Length; - int cbCtr = pbCounter.Length; - int cbCsp = pbCspRandom.Length; - - pbCmp = new byte[cbPool + cbCtr + cbCsp]; - Array.Copy(m_pbEntropyPool, pbCmp, cbPool); - Array.Copy(pbCounter, 0, pbCmp, cbPool, cbCtr); - Array.Copy(pbCspRandom, 0, pbCmp, cbPool + cbCtr, cbCsp); - - MemUtil.ZeroByteArray(pbCspRandom); - - m_uGeneratedBytesCount += 32; - } - - byte[] pbRet = CryptoUtil.HashSha256(pbCmp); - MemUtil.ZeroByteArray(pbCmp); - return pbRet; - } - - /// - /// Get a number of cryptographically strong random bytes. - /// This method is thread-safe. - /// - /// Number of requested random bytes. - /// A byte array consisting of - /// random bytes. - public byte[] GetRandomBytes(uint uRequestedBytes) - { - if(uRequestedBytes == 0) return MemUtil.EmptyByteArray; - if(uRequestedBytes > (uint)int.MaxValue) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("uRequestedBytes"); - } - - int cbRem = (int)uRequestedBytes; - byte[] pbRes = new byte[cbRem]; - int iPos = 0; - - while(cbRem != 0) - { - byte[] pbRandom256 = GenerateRandom256(); - Debug.Assert(pbRandom256.Length == 32); - - int cbCopy = Math.Min(cbRem, pbRandom256.Length); - Array.Copy(pbRandom256, 0, pbRes, iPos, cbCopy); - - MemUtil.ZeroByteArray(pbRandom256); - - iPos += cbCopy; - cbRem -= cbCopy; - } - - Debug.Assert(iPos == pbRes.Length); - return pbRes; - } - - private static int g_iWeakSeed = 0; - public static Random NewWeakRandom() - { - long s64 = DateTime.UtcNow.ToBinary(); - int s32 = (int)((s64 >> 32) ^ s64); - - lock(g_oSyncRoot) - { - unchecked - { - g_iWeakSeed += 0x78A8C4B7; // Prime number - s32 ^= g_iWeakSeed; - } - } - - // Prevent overflow in the Random constructor of .NET 2.0 - if(s32 == int.MinValue) s32 = int.MaxValue; - - return new Random(s32); - } - } -} diff --git a/ModernKeePassLib/Cryptography/CryptoRandomStream.cs b/ModernKeePassLib/Cryptography/CryptoRandomStream.cs deleted file mode 100644 index 091cd5d..0000000 --- a/ModernKeePassLib/Cryptography/CryptoRandomStream.cs +++ /dev/null @@ -1,264 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Diagnostics; - -#if ModernKeePassLib -using ModernKeePassLib.Cryptography.Hash; -#elif !KeePassUAP -using System.Security.Cryptography; -#endif - -using ModernKeePassLib.Cryptography.Cipher; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography -{ - /// - /// Algorithms supported by CryptoRandomStream. - /// - public enum CrsAlgorithm - { - /// - /// Not supported. - /// - Null = 0, - - /// - /// A variant of the ARCFour algorithm (RC4 incompatible). - /// Insecure; for backward compatibility only. - /// - ArcFourVariant = 1, - - /// - /// Salsa20 stream cipher algorithm. - /// - Salsa20 = 2, - - /// - /// ChaCha20 stream cipher algorithm. - /// - ChaCha20 = 3, - - Count = 4 - } - - /// - /// A random stream class. The class is initialized using random - /// bytes provided by the caller. The produced stream has random - /// properties, but for the same seed always the same stream - /// is produced, i.e. this class can be used as stream cipher. - /// - public sealed class CryptoRandomStream : IDisposable - { - private readonly CrsAlgorithm m_crsAlgorithm; - private bool m_bDisposed = false; - - private byte[] m_pbState = null; - private byte m_i = 0; - private byte m_j = 0; - - private Salsa20Cipher m_salsa20 = null; - private ChaCha20Cipher m_chacha20 = null; - - /// - /// Construct a new cryptographically secure random stream object. - /// - /// Algorithm to use. - /// Initialization key. Must not be null and - /// must contain at least 1 byte. - public CryptoRandomStream(CrsAlgorithm a, byte[] pbKey) - { - if(pbKey == null) { Debug.Assert(false); throw new ArgumentNullException("pbKey"); } - - int cbKey = pbKey.Length; - if(cbKey <= 0) - { - Debug.Assert(false); // Need at least one byte - throw new ArgumentOutOfRangeException("pbKey"); - } - - m_crsAlgorithm = a; - - if(a == CrsAlgorithm.ChaCha20) - { - byte[] pbKey32 = new byte[32]; - byte[] pbIV12 = new byte[12]; - - using(SHA512Managed h = new SHA512Managed()) - { - byte[] pbHash = h.ComputeHash(pbKey); - Array.Copy(pbHash, pbKey32, 32); - Array.Copy(pbHash, 32, pbIV12, 0, 12); - MemUtil.ZeroByteArray(pbHash); - } - - m_chacha20 = new ChaCha20Cipher(pbKey32, pbIV12, true); - } - else if(a == CrsAlgorithm.Salsa20) - { - byte[] pbKey32 = CryptoUtil.HashSha256(pbKey); - byte[] pbIV8 = new byte[8] { 0xE8, 0x30, 0x09, 0x4B, - 0x97, 0x20, 0x5D, 0x2A }; // Unique constant - - m_salsa20 = new Salsa20Cipher(pbKey32, pbIV8); - } - else if(a == CrsAlgorithm.ArcFourVariant) - { - // Fill the state linearly - m_pbState = new byte[256]; - for(int w = 0; w < 256; ++w) m_pbState[w] = (byte)w; - - unchecked - { - byte j = 0, t; - int inxKey = 0; - for(int w = 0; w < 256; ++w) // Key setup - { - j += (byte)(m_pbState[w] + pbKey[inxKey]); - - t = m_pbState[0]; // Swap entries - m_pbState[0] = m_pbState[j]; - m_pbState[j] = t; - - ++inxKey; - if(inxKey >= cbKey) inxKey = 0; - } - } - - GetRandomBytes(512); // Increases security, see cryptanalysis - } - else // Unknown algorithm - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("a"); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if(disposing) - { - if(m_crsAlgorithm == CrsAlgorithm.ChaCha20) - m_chacha20.Dispose(); - else if(m_crsAlgorithm == CrsAlgorithm.Salsa20) - m_salsa20.Dispose(); - else if(m_crsAlgorithm == CrsAlgorithm.ArcFourVariant) - { - MemUtil.ZeroByteArray(m_pbState); - m_i = 0; - m_j = 0; - } - else { Debug.Assert(false); } - - m_bDisposed = true; - } - } - - /// - /// Get random bytes. - /// - /// Number of random bytes to retrieve. - /// Returns random bytes. - public byte[] GetRandomBytes(uint uRequestedCount) - { - if(m_bDisposed) throw new ObjectDisposedException(null); - - if(uRequestedCount == 0) return MemUtil.EmptyByteArray; - if(uRequestedCount > (uint)int.MaxValue) - throw new ArgumentOutOfRangeException("uRequestedCount"); - int cb = (int)uRequestedCount; - - byte[] pbRet = new byte[cb]; - - if(m_crsAlgorithm == CrsAlgorithm.ChaCha20) - m_chacha20.Encrypt(pbRet, 0, cb); - else if(m_crsAlgorithm == CrsAlgorithm.Salsa20) - m_salsa20.Encrypt(pbRet, 0, cb); - else if(m_crsAlgorithm == CrsAlgorithm.ArcFourVariant) - { - unchecked - { - for(int w = 0; w < cb; ++w) - { - ++m_i; - m_j += m_pbState[m_i]; - - byte t = m_pbState[m_i]; // Swap entries - m_pbState[m_i] = m_pbState[m_j]; - m_pbState[m_j] = t; - - t = (byte)(m_pbState[m_i] + m_pbState[m_j]); - pbRet[w] = m_pbState[t]; - } - } - } - else { Debug.Assert(false); } - - return pbRet; - } - - public ulong GetRandomUInt64() - { - byte[] pb = GetRandomBytes(8); - return MemUtil.BytesToUInt64(pb); - } - -#if CRSBENCHMARK - public static string Benchmark() - { - int nRounds = 2000000; - - string str = "ArcFour small: " + BenchTime(CrsAlgorithm.ArcFourVariant, - nRounds, 16).ToString() + "\r\n"; - str += "ArcFour big: " + BenchTime(CrsAlgorithm.ArcFourVariant, - 32, 2 * 1024 * 1024).ToString() + "\r\n"; - str += "Salsa20 small: " + BenchTime(CrsAlgorithm.Salsa20, - nRounds, 16).ToString() + "\r\n"; - str += "Salsa20 big: " + BenchTime(CrsAlgorithm.Salsa20, - 32, 2 * 1024 * 1024).ToString(); - return str; - } - - private static int BenchTime(CrsAlgorithm cra, int nRounds, int nDataSize) - { - byte[] pbKey = new byte[4] { 0x00, 0x01, 0x02, 0x03 }; - - int nStart = Environment.TickCount; - for(int i = 0; i < nRounds; ++i) - { - using(CryptoRandomStream c = new CryptoRandomStream(cra, pbKey)) - { - c.GetRandomBytes((uint)nDataSize); - } - } - int nEnd = Environment.TickCount; - - return (nEnd - nStart); - } -#endif - } -} diff --git a/ModernKeePassLib/Cryptography/CryptoUtil.cs b/ModernKeePassLib/Cryptography/CryptoUtil.cs deleted file mode 100644 index 2d6b4a4..0000000 --- a/ModernKeePassLib/Cryptography/CryptoUtil.cs +++ /dev/null @@ -1,237 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Reflection; -using System.Text; -#if ModernKeePassLib -using ModernKeePassLib.Cryptography.Hash; -#elif !KeePassUAP -using System.Security.Cryptography; -#endif - -using ModernKeePassLib.Native; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography -{ - public static class CryptoUtil - { - private static bool? g_obProtData = null; - public static bool IsProtectedDataSupported - { - get - { - if(g_obProtData.HasValue) return g_obProtData.Value; - - bool b = false; - try - { - Random r = CryptoRandom.NewWeakRandom(); - - byte[] pbData = new byte[137]; - r.NextBytes(pbData); - - byte[] pbEnt = new byte[41]; - r.NextBytes(pbEnt); - - byte[] pbEnc = ProtectedData.Protect(pbData, pbEnt, - DataProtectionScope.CurrentUser); - if((pbEnc != null) && !MemUtil.ArraysEqual(pbEnc, pbData)) - { - byte[] pbDec = ProtectedData.Unprotect(pbEnc, pbEnt, - DataProtectionScope.CurrentUser); - if((pbDec != null) && MemUtil.ArraysEqual(pbDec, pbData)) - b = true; - } - } - catch(Exception) { Debug.Assert(false); } - - Debug.Assert(b); // Should be supported on all systems - g_obProtData = b; - return b; - } - } - - public static byte[] HashSha256(byte[] pbData) - { - if(pbData == null) throw new ArgumentNullException("pbData"); - - return HashSha256(pbData, 0, pbData.Length); - } - - public static byte[] HashSha256(byte[] pbData, int iOffset, int cbCount) - { - if(pbData == null) throw new ArgumentNullException("pbData"); - -#if DEBUG - byte[] pbCopy = new byte[pbData.Length]; - Array.Copy(pbData, pbCopy, pbData.Length); -#endif - - byte[] pbHash; - using(SHA256Managed h = new SHA256Managed()) - { - pbHash = h.ComputeHash(pbData, iOffset, cbCount); - } - -#if DEBUG - // Ensure the data has not been modified - Debug.Assert(MemUtil.ArraysEqual(pbData, pbCopy)); - - Debug.Assert((pbHash != null) && (pbHash.Length == 32)); - byte[] pbZero = new byte[32]; - Debug.Assert(!MemUtil.ArraysEqual(pbHash, pbZero)); -#endif - - return pbHash; - } - - /// - /// Create a cryptographic key of length - /// (in bytes) from . - /// - public static byte[] ResizeKey(byte[] pbIn, int iInOffset, - int cbIn, int cbOut) - { - if(pbIn == null) throw new ArgumentNullException("pbIn"); - if(cbOut < 0) throw new ArgumentOutOfRangeException("cbOut"); - - if(cbOut == 0) return MemUtil.EmptyByteArray; - - byte[] pbHash; - if(cbOut <= 32) pbHash = HashSha256(pbIn, iInOffset, cbIn); - else - { - using(SHA512Managed h = new SHA512Managed()) - { - pbHash = h.ComputeHash(pbIn, iInOffset, cbIn); - } - } - - if(cbOut == pbHash.Length) return pbHash; - - byte[] pbRet = new byte[cbOut]; - if(cbOut < pbHash.Length) - Array.Copy(pbHash, pbRet, cbOut); - else - { - int iPos = 0; - ulong r = 0; - while(iPos < cbOut) - { - Debug.Assert(pbHash.Length == 64); - using(HMACSHA256 h = new HMACSHA256(pbHash)) - { - byte[] pbR = MemUtil.UInt64ToBytes(r); - byte[] pbPart = h.ComputeHash(pbR); - - int cbCopy = Math.Min(cbOut - iPos, pbPart.Length); - Debug.Assert(cbCopy > 0); - - Array.Copy(pbPart, 0, pbRet, iPos, cbCopy); - iPos += cbCopy; - ++r; - - MemUtil.ZeroByteArray(pbPart); - } - } - Debug.Assert(iPos == cbOut); - } - -#if DEBUG - byte[] pbZero = new byte[pbHash.Length]; - Debug.Assert(!MemUtil.ArraysEqual(pbHash, pbZero)); -#endif - MemUtil.ZeroByteArray(pbHash); - return pbRet; - } - -#if !ModernKeePassLib - private static bool? g_obAesCsp = null; - internal static SymmetricAlgorithm CreateAes() - { - if(g_obAesCsp.HasValue) - return (g_obAesCsp.Value ? CreateAesCsp() : new RijndaelManaged()); - - SymmetricAlgorithm a = CreateAesCsp(); - g_obAesCsp = (a != null); - return (a ?? new RijndaelManaged()); - } - - private static SymmetricAlgorithm CreateAesCsp() - { - try - { - // On Windows, the CSP implementation is only minimally - // faster (and for key derivations it's not used anyway, - // as KeePass uses a native implementation based on - // CNG/BCrypt, which is much faster) - if(!NativeLib.IsUnix()) return null; - - string strFqn = Assembly.CreateQualifiedName( - "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", - "System.Security.Cryptography.AesCryptoServiceProvider"); - - Type t = Type.GetType(strFqn); - if(t == null) return null; - - return (Activator.CreateInstance(t) as SymmetricAlgorithm); - } - catch(Exception) { Debug.Assert(false); } - - return null; - } -#endif - public static byte[] ProtectData(byte[] pb, byte[] pbOptEntropy, - DataProtectionScope s) - { - return ProtectDataPriv(pb, true, pbOptEntropy, s); - } - - public static byte[] UnprotectData(byte[] pb, byte[] pbOptEntropy, - DataProtectionScope s) - { - return ProtectDataPriv(pb, false, pbOptEntropy, s); - } - - private static byte[] ProtectDataPriv(byte[] pb, bool bProtect, - byte[] pbOptEntropy, DataProtectionScope s) - { - if(pb == null) throw new ArgumentNullException("pb"); - - if((pbOptEntropy != null) && (pbOptEntropy.Length == 0)) - pbOptEntropy = null; - - if(CryptoUtil.IsProtectedDataSupported) - { - if(bProtect) - return ProtectedData.Protect(pb, pbOptEntropy, s); - return ProtectedData.Unprotect(pb, pbOptEntropy, s); - } - - Debug.Assert(false); - byte[] pbCopy = new byte[pb.Length]; - Array.Copy(pb, pbCopy, pb.Length); - return pbCopy; - } - } -} diff --git a/ModernKeePassLib/Cryptography/Hash/Blake2b.cs b/ModernKeePassLib/Cryptography/Hash/Blake2b.cs deleted file mode 100644 index d7732c4..0000000 --- a/ModernKeePassLib/Cryptography/Hash/Blake2b.cs +++ /dev/null @@ -1,394 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// This implementation is based on the official reference C -// implementation by Samuel Neves (CC0 1.0 Universal). - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; - -#if ModernKeePassLib -#elif !KeePassUAP -using System.Security.Cryptography; -#endif - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.Hash -{ - public sealed class Blake2b : IDisposable - { - protected int HashSizeValue; - protected internal byte[] HashValue; - protected int State = 0; - - private bool m_bDisposed = false; - - private const int NbRounds = 12; - private const int NbBlockBytes = 128; - private const int NbMaxOutBytes = 64; - - private static readonly ulong[] g_vIV = new ulong[8] { - 0x6A09E667F3BCC908UL, 0xBB67AE8584CAA73BUL, - 0x3C6EF372FE94F82BUL, 0xA54FF53A5F1D36F1UL, - 0x510E527FADE682D1UL, 0x9B05688C2B3E6C1FUL, - 0x1F83D9ABFB41BD6BUL, 0x5BE0CD19137E2179UL - }; - - private static readonly int[] g_vSigma = new int[NbRounds * 16] { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, - 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, - 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, - 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, - 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, - 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11, - 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10, - 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5, - 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 - }; - - private readonly int m_cbHashLength; - - private ulong[] m_h = new ulong[8]; - private ulong[] m_t = new ulong[2]; - private ulong[] m_f = new ulong[2]; - private byte[] m_buf = new byte[NbBlockBytes]; - private int m_cbBuf = 0; - - private ulong[] m_m = new ulong[16]; - private ulong[] m_v = new ulong[16]; - - public int HashSize - { - get { return HashSizeValue; } - } - - public byte[] Hash - { - get - { - if (m_bDisposed) - throw new ObjectDisposedException(null); - if (State != 0) - throw new InvalidOperationException("Blak2B Cryptography Hash Not Yet Finalized"); - return (byte[])HashValue.Clone(); - } - } - - public Blake2b() - { - m_cbHashLength = NbMaxOutBytes; - this.HashSizeValue = NbMaxOutBytes * 8; // Bits - - Initialize(); - } - - public Blake2b(int cbHashLength) - { - if((cbHashLength < 0) || (cbHashLength > NbMaxOutBytes)) - throw new ArgumentOutOfRangeException("cbHashLength"); - - m_cbHashLength = cbHashLength; - this.HashSizeValue = cbHashLength * 8; // Bits - - Initialize(); - } - - public void Initialize() - { - Debug.Assert(m_h.Length == g_vIV.Length); - Array.Copy(g_vIV, m_h, m_h.Length); - - // Fan-out = 1, depth = 1 - m_h[0] ^= 0x0000000001010000UL ^ (ulong)m_cbHashLength; - - Array.Clear(m_t, 0, m_t.Length); - Array.Clear(m_f, 0, m_f.Length); - Array.Clear(m_buf, 0, m_buf.Length); - m_cbBuf = 0; - - Array.Clear(m_m, 0, m_m.Length); - Array.Clear(m_v, 0, m_v.Length); - } - - private static void G(ulong[] v, ulong[] m, int r16, int i, - int a, int b, int c, int d) - { - int p = r16 + i; - - v[a] += v[b] + m[g_vSigma[p]]; - v[d] = MemUtil.RotateRight64(v[d] ^ v[a], 32); - v[c] += v[d]; - v[b] = MemUtil.RotateRight64(v[b] ^ v[c], 24); - v[a] += v[b] + m[g_vSigma[p + 1]]; - v[d] = MemUtil.RotateRight64(v[d] ^ v[a], 16); - v[c] += v[d]; - v[b] = MemUtil.RotateRight64(v[b] ^ v[c], 63); - } - - private void Compress(byte[] pb, int iOffset) - { - ulong[] v = m_v; - ulong[] m = m_m; - ulong[] h = m_h; - - for(int i = 0; i < 16; ++i) - m[i] = MemUtil.BytesToUInt64(pb, iOffset + (i << 3)); - - Array.Copy(h, v, 8); - v[8] = g_vIV[0]; - v[9] = g_vIV[1]; - v[10] = g_vIV[2]; - v[11] = g_vIV[3]; - v[12] = g_vIV[4] ^ m_t[0]; - v[13] = g_vIV[5] ^ m_t[1]; - v[14] = g_vIV[6] ^ m_f[0]; - v[15] = g_vIV[7] ^ m_f[1]; - - for(int r = 0; r < NbRounds; ++r) - { - int r16 = r << 4; - - G(v, m, r16, 0, 0, 4, 8, 12); - G(v, m, r16, 2, 1, 5, 9, 13); - G(v, m, r16, 4, 2, 6, 10, 14); - G(v, m, r16, 6, 3, 7, 11, 15); - G(v, m, r16, 8, 0, 5, 10, 15); - G(v, m, r16, 10, 1, 6, 11, 12); - G(v, m, r16, 12, 2, 7, 8, 13); - G(v, m, r16, 14, 3, 4, 9, 14); - } - - for(int i = 0; i < 8; ++i) - h[i] ^= v[i] ^ v[i + 8]; - } - - private void IncrementCounter(ulong cb) - { - m_t[0] += cb; - if(m_t[0] < cb) ++m_t[1]; - } - - private void HashCore(byte[] array, int ibStart, int cbSize) - { - Debug.Assert(m_f[0] == 0); - - if((m_cbBuf + cbSize) > NbBlockBytes) // Not '>=' (buffer must not be empty) - { - int cbFill = NbBlockBytes - m_cbBuf; - if(cbFill > 0) Array.Copy(array, ibStart, m_buf, m_cbBuf, cbFill); - - IncrementCounter((ulong)NbBlockBytes); - Compress(m_buf, 0); - - m_cbBuf = 0; - cbSize -= cbFill; - ibStart += cbFill; - - while(cbSize > NbBlockBytes) // Not '>=' (buffer must not be empty) - { - IncrementCounter((ulong)NbBlockBytes); - Compress(array, ibStart); - - cbSize -= NbBlockBytes; - ibStart += NbBlockBytes; - } - } - - if(cbSize > 0) - { - Debug.Assert((m_cbBuf + cbSize) <= NbBlockBytes); - - Array.Copy(array, ibStart, m_buf, m_cbBuf, cbSize); - m_cbBuf += cbSize; - } - } - - private byte[] HashFinal() - { - if(m_f[0] != 0) { Debug.Assert(false); throw new InvalidOperationException(); } - Debug.Assert(((m_t[1] == 0) && (m_t[0] == 0)) || - (m_cbBuf > 0)); // Buffer must not be empty for last block processing - - m_f[0] = ulong.MaxValue; // Indicate last block - - int cbFill = NbBlockBytes - m_cbBuf; - if(cbFill > 0) Array.Clear(m_buf, m_cbBuf, cbFill); - - IncrementCounter((ulong)m_cbBuf); - Compress(m_buf, 0); - - byte[] pbHash = new byte[NbMaxOutBytes]; - for(int i = 0; i < m_h.Length; ++i) - MemUtil.UInt64ToBytesEx(m_h[i], pbHash, i << 3); - - if(m_cbHashLength == NbMaxOutBytes) return pbHash; - Debug.Assert(m_cbHashLength < NbMaxOutBytes); - - byte[] pbShort = new byte[m_cbHashLength]; - if(m_cbHashLength > 0) - Array.Copy(pbHash, pbShort, m_cbHashLength); - MemUtil.ZeroByteArray(pbHash); - return pbShort; - } - - public byte[] ComputeHash(Stream inputStream) - { - if (m_bDisposed) - throw new ObjectDisposedException(null); - - // Default the buffer size to 4K. - byte[] buffer = new byte[4096]; - int bytesRead; - do - { - bytesRead = inputStream.Read(buffer, 0, 4096); - if (bytesRead > 0) - { - HashCore(buffer, 0, bytesRead); - } - } while (bytesRead > 0); - - HashValue = HashFinal(); - byte[] Tmp = (byte[])HashValue.Clone(); - Initialize(); - return (Tmp); - } - - public byte[] ComputeHash(byte[] buffer) - { - if (m_bDisposed) - throw new ObjectDisposedException(null); - - // Do some validation - if (buffer == null) throw new ArgumentNullException("buffer"); - - HashCore(buffer, 0, buffer.Length); - HashValue = HashFinal(); - byte[] Tmp = (byte[])HashValue.Clone(); - Initialize(); - return (Tmp); - } - - public byte[] ComputeHash(byte[] buffer, int offset, int count) - { - // Do some validation - if (buffer == null) - throw new ArgumentNullException("buffer"); - if (offset < 0) - throw new ArgumentOutOfRangeException("offset", "ArgumentOutOfRange_NeedNonNegNum"); - if (count < 0 || (count > buffer.Length)) - throw new ArgumentException("Argument_InvalidValue"); - if ((buffer.Length - count) < offset) - throw new ArgumentException("Argument_InvalidOffLen"); - - if (m_bDisposed) - throw new ObjectDisposedException(null); - - HashCore(buffer, offset, count); - HashValue = HashFinal(); - byte[] Tmp = (byte[])HashValue.Clone(); - Initialize(); - return (Tmp); - } - - public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) - { - // Do some validation, we let BlockCopy do the destination array validation - if (inputBuffer == null) - throw new ArgumentNullException("inputBuffer"); - if (inputOffset < 0) - throw new ArgumentOutOfRangeException("inputOffset", "ArgumentOutOfRange_NeedNonNegNum"); - if (inputCount < 0 || (inputCount > inputBuffer.Length)) - throw new ArgumentException("Argument_InvalidValue"); - if ((inputBuffer.Length - inputCount) < inputOffset) - throw new ArgumentException("Argument_InvalidOffLen"); - - if (m_bDisposed) - throw new ObjectDisposedException(null); - - // Change the State value - State = 1; - HashCore(inputBuffer, inputOffset, inputCount); - if ((outputBuffer != null) && ((inputBuffer != outputBuffer) || (inputOffset != outputOffset))) - Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount); - return inputCount; - } - - public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) - { - // Do some validation - if (inputBuffer == null) - throw new ArgumentNullException("inputBuffer"); - if (inputOffset < 0) - throw new ArgumentOutOfRangeException("inputOffset", "ArgumentOutOfRange_NeedNonNegNum"); - if (inputCount < 0 || (inputCount > inputBuffer.Length)) - throw new ArgumentException("Argument_InvalidValue"); - if ((inputBuffer.Length - inputCount) < inputOffset) - throw new ArgumentException("Argument_InvalidOffLen"); - - if (m_bDisposed) - throw new ObjectDisposedException(null); - - HashCore(inputBuffer, inputOffset, inputCount); - HashValue = HashFinal(); - byte[] outputBytes; - if (inputCount != 0) - { - outputBytes = new byte[inputCount]; - Array.Copy(inputBuffer, inputOffset, outputBytes, 0, inputCount); - } - else - { - outputBytes = MemUtil.EmptyByteArray; - } - // reset the State value - State = 0; - return outputBytes; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - public void Clear() - { - (this as IDisposable).Dispose(); - } - - private void Dispose(bool disposing) - { - if (disposing) - { - if (HashValue != null) - Array.Clear(HashValue, 0, HashValue.Length); - HashValue = null; - m_bDisposed = true; - } - } - } -} diff --git a/ModernKeePassLib/Cryptography/Hash/HMAC.cs b/ModernKeePassLib/Cryptography/Hash/HMAC.cs deleted file mode 100644 index 281baa9..0000000 --- a/ModernKeePassLib/Cryptography/Hash/HMAC.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using Org.BouncyCastle.Crypto.Macs; - -namespace ModernKeePassLib.Cryptography.Hash -{ - public class HMAC : IDisposable - { - protected HMac Hmac; - - public byte[] Hash - { - get - { - var result = new byte[Hmac.GetMacSize()]; - Hmac.DoFinal(result, 0); - return result; - } - } - - public byte[] ComputeHash(byte[] value) - { - return ComputeHash(value, 0, value.Length); - } - - public byte[] ComputeHash(byte[] value, int offset, int length) - { - if (value == null) throw new ArgumentNullException(nameof(value)); - - byte[] resBuf = new byte[Hmac.GetMacSize()]; - Hmac.BlockUpdate(value, offset, length); - Hmac.DoFinal(resBuf, offset); - - return resBuf; - } - - public void TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) - { - Hmac.BlockUpdate(inputBuffer, inputOffset, inputCount); - if ((outputBuffer != null) && ((inputBuffer != outputBuffer) || (inputOffset != outputOffset))) - Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount); - } - - public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) - { - Hmac.BlockUpdate(inputBuffer, inputOffset, inputCount); - byte[] outputBytes = new byte[inputCount]; - if (inputCount != 0) - Buffer.BlockCopy(inputBuffer, inputOffset, outputBytes, 0, inputCount); - return outputBytes; - } - - public void Initialize() - { - Hmac.Reset(); - } - - public void Dispose() - { - Hmac.Reset(); - } - } -} diff --git a/ModernKeePassLib/Cryptography/Hash/HMACSHA1.cs b/ModernKeePassLib/Cryptography/Hash/HMACSHA1.cs deleted file mode 100644 index 1653a82..0000000 --- a/ModernKeePassLib/Cryptography/Hash/HMACSHA1.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.Security.Cryptography.Core; - -namespace ModernKeePassLib.Cryptography.Hash -{ - public class HMACSHA1: HashAlgorithm - { - public HMACSHA1(byte[] key) : base (MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha1).CreateHash(key.AsBuffer())) {} - } -} diff --git a/ModernKeePassLib/Cryptography/Hash/HMACSHA256.cs b/ModernKeePassLib/Cryptography/Hash/HMACSHA256.cs deleted file mode 100644 index 49280d8..0000000 --- a/ModernKeePassLib/Cryptography/Hash/HMACSHA256.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.Security.Cryptography.Core; - -namespace ModernKeePassLib.Cryptography.Hash -{ - public class HMACSHA256: HashAlgorithm - { - public HMACSHA256(byte[] key) : base (MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256).CreateHash(key.AsBuffer())) {} - } -} diff --git a/ModernKeePassLib/Cryptography/Hash/HashAlgorithm.cs b/ModernKeePassLib/Cryptography/Hash/HashAlgorithm.cs deleted file mode 100644 index 8ff9821..0000000 --- a/ModernKeePassLib/Cryptography/Hash/HashAlgorithm.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.Security.Cryptography.Core; -using Validation; - -namespace ModernKeePassLib.Cryptography.Hash -{ - public abstract class HashAlgorithm: IDisposable - { - /// - /// The platform-specific hash object. - /// - private readonly CryptographicHash _hash; - - /// - /// Initializes a new instance of the class. - /// - /// The platform hash. - internal HashAlgorithm(CryptographicHash hash) - { - Requires.NotNull(hash, "Hash"); - _hash = hash; - } - - public bool CanReuseTransform => true; - public bool CanTransformMultipleBlocks => true; - - public byte[] Hash => _hash.GetValueAndReset().ToArray(); - - public void Append(byte[] data) - { - _hash.Append(data.AsBuffer()); - } - - public byte[] GetValueAndReset() - { - return _hash.GetValueAndReset().ToArray(); - } - - #region ICryptoTransform methods - - public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) - { - byte[] buffer; - if (inputCount < inputBuffer.Length) - { - buffer = new byte[inputCount]; - Array.Copy(inputBuffer, inputOffset, buffer, 0, inputCount); - } - else - { - buffer = inputBuffer; - } - - Append(buffer); - if (outputBuffer != null) - { - Array.Copy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount); - } - - return inputCount; - } - - public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) - { - this.TransformBlock(inputBuffer, inputOffset, inputCount, null, 0); - if (inputCount == inputBuffer.Length) - { - return inputBuffer; - } - var buffer = new byte[inputCount]; - Array.Copy(inputBuffer, inputOffset, buffer, 0, inputCount); - return buffer; - } - - public byte[] ComputeHash(byte[] value) - { - return ComputeHash(value, 0, value.Length); - } - - public byte[] ComputeHash(byte[] value, int offset, int length) - { - if (value == null) throw new ArgumentNullException(nameof(value)); - - TransformFinalBlock(value, offset, length); - var resBuf = GetValueAndReset(); - - return resBuf; - } - public void Initialize() - { - } - - public void Dispose() - { - } - - #endregion - } -} diff --git a/ModernKeePassLib/Cryptography/Hash/SHA256Managed.cs b/ModernKeePassLib/Cryptography/Hash/SHA256Managed.cs deleted file mode 100644 index 1996667..0000000 --- a/ModernKeePassLib/Cryptography/Hash/SHA256Managed.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Windows.Security.Cryptography.Core; - -namespace ModernKeePassLib.Cryptography.Hash -{ - public class SHA256Managed : HashAlgorithm - { - public SHA256Managed() : base(HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha256).CreateHash()) {} - } -} diff --git a/ModernKeePassLib/Cryptography/Hash/SHA512Managed.cs b/ModernKeePassLib/Cryptography/Hash/SHA512Managed.cs deleted file mode 100644 index 26fd625..0000000 --- a/ModernKeePassLib/Cryptography/Hash/SHA512Managed.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Windows.Security.Cryptography.Core; - -namespace ModernKeePassLib.Cryptography.Hash -{ - public class SHA512Managed: HashAlgorithm - { - public SHA512Managed() : base(HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha512).CreateHash()) {} - } -} diff --git a/ModernKeePassLib/Cryptography/HashingStreamEx.cs b/ModernKeePassLib/Cryptography/HashingStreamEx.cs deleted file mode 100644 index 7a4fde4..0000000 --- a/ModernKeePassLib/Cryptography/HashingStreamEx.cs +++ /dev/null @@ -1,186 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; -#if ModernKeePassLib -using ModernKeePassLib.Cryptography.Hash; -#elif !KeePassUAP -using System.Security.Cryptography; -#endif - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography -{ - public sealed class HashingStreamEx : Stream - { - private readonly Stream m_sBaseStream; - private readonly bool m_bWriting; - private HashAlgorithm m_hash; - - private byte[] m_pbFinalHash = null; - - public byte[] Hash - { - get { return m_pbFinalHash; } - } - - public override bool CanRead - { - get { return !m_bWriting; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return m_bWriting; } - } - - public override long Length - { - get { return m_sBaseStream.Length; } - } - - public override long Position - { - get { return m_sBaseStream.Position; } - set { Debug.Assert(false); throw new NotSupportedException(); } - } - - public HashingStreamEx(Stream sBaseStream, bool bWriting, HashAlgorithm hashAlgorithm) - { - if(sBaseStream == null) throw new ArgumentNullException("sBaseStream"); - - m_sBaseStream = sBaseStream; - m_bWriting = bWriting; - -#if !KeePassLibSD - m_hash = (hashAlgorithm ?? new SHA256Managed()); -#else // KeePassLibSD - m_hash = null; - - try { m_hash = HashAlgorithm.Create("SHA256"); } - catch(Exception) { } - try { if(m_hash == null) m_hash = HashAlgorithm.Create(); } - catch(Exception) { } -#endif - if(m_hash == null) { Debug.Assert(false); return; } - - // Validate hash algorithm - if(!m_hash.CanReuseTransform || !m_hash.CanTransformMultipleBlocks) - { - Debug.Assert(false); - m_hash = null; - } - } - - protected override void Dispose(bool disposing) - { - if(disposing) - { - if(m_hash != null) - { - try - { - m_hash.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); - - m_pbFinalHash = m_hash.Hash; - } - catch(Exception) { Debug.Assert(false); } - - m_hash = null; - } - - m_sBaseStream.Dispose(); - } - - base.Dispose(disposing); - } - - public override void Flush() - { - m_sBaseStream.Flush(); - } - - public override long Seek(long lOffset, SeekOrigin soOrigin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long lValue) - { - throw new NotSupportedException(); - } - - public override int Read(byte[] pbBuffer, int nOffset, int nCount) - { - if(m_bWriting) throw new InvalidOperationException(); - - int nRead = m_sBaseStream.Read(pbBuffer, nOffset, nCount); - int nPartialRead = nRead; - while((nRead < nCount) && (nPartialRead != 0)) - { - nPartialRead = m_sBaseStream.Read(pbBuffer, nOffset + nRead, - nCount - nRead); - nRead += nPartialRead; - } - -#if DEBUG - byte[] pbOrg = new byte[pbBuffer.Length]; - Array.Copy(pbBuffer, pbOrg, pbBuffer.Length); -#endif - - if((m_hash != null) && (nRead > 0)) - m_hash.TransformBlock(pbBuffer, nOffset, nRead, pbBuffer, nOffset); - -#if DEBUG - Debug.Assert(MemUtil.ArraysEqual(pbBuffer, pbOrg)); -#endif - - return nRead; - } - - public override void Write(byte[] pbBuffer, int nOffset, int nCount) - { - if(!m_bWriting) throw new InvalidOperationException(); - -#if DEBUG - byte[] pbOrg = new byte[pbBuffer.Length]; - Array.Copy(pbBuffer, pbOrg, pbBuffer.Length); -#endif - - if((m_hash != null) && (nCount > 0)) - m_hash.TransformBlock(pbBuffer, nOffset, nCount, pbBuffer, nOffset); - -#if DEBUG - Debug.Assert(MemUtil.ArraysEqual(pbBuffer, pbOrg)); -#endif - - m_sBaseStream.Write(pbBuffer, nOffset, nCount); - } - } -} diff --git a/ModernKeePassLib/Cryptography/HmacOtp.cs b/ModernKeePassLib/Cryptography/HmacOtp.cs deleted file mode 100644 index 0e11aab..0000000 --- a/ModernKeePassLib/Cryptography/HmacOtp.cs +++ /dev/null @@ -1,96 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text; -#if ModernKeePassLib -using ModernKeePassLib.Cryptography.Hash; -#elif !KeePassUAP -using System.Security.Cryptography; -#endif - -using ModernKeePassLib.Utility; - -#if !KeePassLibSD -namespace ModernKeePassLib.Cryptography -{ - /// - /// Generate HMAC-based one-time passwords as specified in RFC 4226. - /// - public static class HmacOtp - { - private static readonly uint[] vDigitsPower = new uint[]{ 1, 10, 100, - 1000, 10000, 100000, 1000000, 10000000, 100000000 }; - - public static string Generate(byte[] pbSecret, ulong uFactor, - uint uCodeDigits, bool bAddChecksum, int iTruncationOffset) - { - byte[] pbText = MemUtil.UInt64ToBytes(uFactor); - Array.Reverse(pbText); // To big-endian - - HMACSHA1 hsha1 = new HMACSHA1(pbSecret); - byte[] pbHash = hsha1.ComputeHash(pbText); - - uint uOffset = (uint)(pbHash[pbHash.Length - 1] & 0xF); - if((iTruncationOffset >= 0) && (iTruncationOffset < (pbHash.Length - 4))) - uOffset = (uint)iTruncationOffset; - - uint uBinary = (uint)(((pbHash[uOffset] & 0x7F) << 24) | - ((pbHash[uOffset + 1] & 0xFF) << 16) | - ((pbHash[uOffset + 2] & 0xFF) << 8) | - (pbHash[uOffset + 3] & 0xFF)); - - uint uOtp = (uBinary % vDigitsPower[uCodeDigits]); - if(bAddChecksum) - uOtp = ((uOtp * 10) + CalculateChecksum(uOtp, uCodeDigits)); - - uint uDigits = (bAddChecksum ? (uCodeDigits + 1) : uCodeDigits); - return uOtp.ToString(NumberFormatInfo.InvariantInfo).PadLeft( - (int)uDigits, '0'); - } - - private static readonly uint[] vDoubleDigits = new uint[]{ 0, 2, 4, 6, 8, - 1, 3, 5, 7, 9 }; - - private static uint CalculateChecksum(uint uNum, uint uDigits) - { - bool bDoubleDigit = true; - uint uTotal = 0; - - while(0 < uDigits--) - { - uint uDigit = (uNum % 10); - uNum /= 10; - - if(bDoubleDigit) uDigit = vDoubleDigits[uDigit]; - - uTotal += uDigit; - bDoubleDigit = !bDoubleDigit; - } - - uint uResult = (uTotal % 10); - if(uResult != 0) uResult = 10 - uResult; - - return uResult; - } - } -} -#endif diff --git a/ModernKeePassLib/Cryptography/KeyDerivation/AesKdf.GCrypt.cs b/ModernKeePassLib/Cryptography/KeyDerivation/AesKdf.GCrypt.cs deleted file mode 100644 index 51b100d..0000000 --- a/ModernKeePassLib/Cryptography/KeyDerivation/AesKdf.GCrypt.cs +++ /dev/null @@ -1,399 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; - -using ModernKeePassLib.Native; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.KeyDerivation -{ - public sealed partial class AesKdf : KdfEngine - { - private static bool TransformKeyGCrypt(byte[] pbData32, byte[] pbSeed32, - ulong uRounds) - { - byte[] pbNewData32 = null; - try - { - if(GCryptInitLib()) - { - pbNewData32 = new byte[32]; - Array.Copy(pbData32, pbNewData32, 32); - - if(TransformKeyGCryptPriv(pbNewData32, pbSeed32, uRounds)) - { - Array.Copy(pbNewData32, pbData32, 32); - return true; - } - } - } - catch(Exception) { } - finally { if(pbNewData32 != null) MemUtil.ZeroByteArray(pbNewData32); } - - return false; - } - - private static bool TransformKeyBenchmarkGCrypt(uint uTimeMs, out ulong uRounds) - { - uRounds = 0; - - try - { - if(GCryptInitLib()) - return TransformKeyBenchmarkGCryptPriv(uTimeMs, ref uRounds); - } - catch(Exception) { } - - return false; - } - - private static bool GCryptInitLib() - { - if(!NativeLib.IsUnix()) return false; // Independent of workaround state - if(!MonoWorkarounds.IsRequired(1468)) return false; // Can be turned off - - // gcry_check_version initializes the library; - // throws when LibGCrypt is not available - NativeMethods.gcry_check_version(IntPtr.Zero); - return true; - } - - // ============================================================= - // Multi-threaded implementation - - // For some reason, the following multi-threaded implementation - // is slower than the single-threaded implementation below - // (threading overhead by Mono? LibGCrypt threading issues?) - /* private sealed class GCryptTransformInfo : IDisposable - { - public IntPtr Data16; - public IntPtr Seed32; - public ulong Rounds; - public uint TimeMs; - - public bool Success = false; - - public GCryptTransformInfo(byte[] pbData32, int iDataOffset, - byte[] pbSeed32, ulong uRounds, uint uTimeMs) - { - this.Data16 = Marshal.AllocCoTaskMem(16); - Marshal.Copy(pbData32, iDataOffset, this.Data16, 16); - - this.Seed32 = Marshal.AllocCoTaskMem(32); - Marshal.Copy(pbSeed32, 0, this.Seed32, 32); - - this.Rounds = uRounds; - this.TimeMs = uTimeMs; - } - - public void Dispose() - { - if(this.Data16 != IntPtr.Zero) - { - Marshal.WriteInt64(this.Data16, 0); - Marshal.WriteInt64(this.Data16, 8, 0); - Marshal.FreeCoTaskMem(this.Data16); - this.Data16 = IntPtr.Zero; - } - - if(this.Seed32 != IntPtr.Zero) - { - Marshal.FreeCoTaskMem(this.Seed32); - this.Seed32 = IntPtr.Zero; - } - } - } - - private static GCryptTransformInfo[] GCryptRun(byte[] pbData32, - byte[] pbSeed32, ulong uRounds, uint uTimeMs, ParameterizedThreadStart fL, - ParameterizedThreadStart fR) - { - GCryptTransformInfo tiL = new GCryptTransformInfo(pbData32, 0, - pbSeed32, uRounds, uTimeMs); - GCryptTransformInfo tiR = new GCryptTransformInfo(pbData32, 16, - pbSeed32, uRounds, uTimeMs); - - Thread th = new Thread(fL); - th.Start(tiL); - - fR(tiR); - - th.Join(); - - Marshal.Copy(tiL.Data16, pbData32, 0, 16); - Marshal.Copy(tiR.Data16, pbData32, 16, 16); - - tiL.Dispose(); - tiR.Dispose(); - - if(tiL.Success && tiR.Success) - return new GCryptTransformInfo[2] { tiL, tiR }; - return null; - } - - private static bool TransformKeyGCryptPriv(byte[] pbData32, byte[] pbSeed32, - ulong uRounds) - { - return (GCryptRun(pbData32, pbSeed32, uRounds, 0, - new ParameterizedThreadStart(AesKdf.GCryptTransformTh), - new ParameterizedThreadStart(AesKdf.GCryptTransformTh)) != null); - } - - private static bool GCryptInitCipher(ref IntPtr h, GCryptTransformInfo ti) - { - NativeMethods.gcry_cipher_open(ref h, NativeMethods.GCRY_CIPHER_AES256, - NativeMethods.GCRY_CIPHER_MODE_ECB, 0); - if(h == IntPtr.Zero) { Debug.Assert(false); return false; } - - IntPtr n32 = new IntPtr(32); - if(NativeMethods.gcry_cipher_setkey(h, ti.Seed32, n32) != 0) - { - Debug.Assert(false); - return false; - } - - return true; - } - - private static void GCryptTransformTh(object o) - { - IntPtr h = IntPtr.Zero; - try - { - GCryptTransformInfo ti = (o as GCryptTransformInfo); - if(ti == null) { Debug.Assert(false); return; } - - if(!GCryptInitCipher(ref h, ti)) return; - - IntPtr n16 = new IntPtr(16); - for(ulong u = 0; u < ti.Rounds; ++u) - { - if(NativeMethods.gcry_cipher_encrypt(h, ti.Data16, n16, - IntPtr.Zero, IntPtr.Zero) != 0) - { - Debug.Assert(false); - return; - } - } - - ti.Success = true; - } - catch(Exception) { Debug.Assert(false); } - finally - { - try { if(h != IntPtr.Zero) NativeMethods.gcry_cipher_close(h); } - catch(Exception) { Debug.Assert(false); } - } - } - - private static bool TransformKeyBenchmarkGCryptPriv(uint uTimeMs, ref ulong uRounds) - { - GCryptTransformInfo[] v = GCryptRun(new byte[32], new byte[32], - 0, uTimeMs, - new ParameterizedThreadStart(AesKdf.GCryptBenchmarkTh), - new ParameterizedThreadStart(AesKdf.GCryptBenchmarkTh)); - - if(v != null) - { - ulong uL = Math.Min(v[0].Rounds, ulong.MaxValue >> 1); - ulong uR = Math.Min(v[1].Rounds, ulong.MaxValue >> 1); - uRounds = (uL + uR) / 2; - - return true; - } - return false; - } - - private static void GCryptBenchmarkTh(object o) - { - IntPtr h = IntPtr.Zero; - try - { - GCryptTransformInfo ti = (o as GCryptTransformInfo); - if(ti == null) { Debug.Assert(false); return; } - - if(!GCryptInitCipher(ref h, ti)) return; - - ulong r = 0; - IntPtr n16 = new IntPtr(16); - int tStart = Environment.TickCount; - while(true) - { - for(ulong j = 0; j < BenchStep; ++j) - { - if(NativeMethods.gcry_cipher_encrypt(h, ti.Data16, n16, - IntPtr.Zero, IntPtr.Zero) != 0) - { - Debug.Assert(false); - return; - } - } - - r += BenchStep; - if(r < BenchStep) // Overflow check - { - r = ulong.MaxValue; - break; - } - - uint tElapsed = (uint)(Environment.TickCount - tStart); - if(tElapsed > ti.TimeMs) break; - } - - ti.Rounds = r; - ti.Success = true; - } - catch(Exception) { Debug.Assert(false); } - finally - { - try { if(h != IntPtr.Zero) NativeMethods.gcry_cipher_close(h); } - catch(Exception) { Debug.Assert(false); } - } - } */ - - // ============================================================= - // Single-threaded implementation - - private static bool GCryptInitCipher(ref IntPtr h, IntPtr pSeed32) - { - NativeMethods.gcry_cipher_open(ref h, NativeMethods.GCRY_CIPHER_AES256, - NativeMethods.GCRY_CIPHER_MODE_ECB, 0); - if(h == IntPtr.Zero) { Debug.Assert(false); return false; } - - IntPtr n32 = new IntPtr(32); - if(NativeMethods.gcry_cipher_setkey(h, pSeed32, n32) != 0) - { - Debug.Assert(false); - return false; - } - - return true; - } - - private static bool GCryptBegin(byte[] pbData32, byte[] pbSeed32, - ref IntPtr h, ref IntPtr pData32, ref IntPtr pSeed32) - { - pData32 = Marshal.AllocCoTaskMem(32); - pSeed32 = Marshal.AllocCoTaskMem(32); - - Marshal.Copy(pbData32, 0, pData32, 32); - Marshal.Copy(pbSeed32, 0, pSeed32, 32); - - return GCryptInitCipher(ref h, pSeed32); - } - - private static void GCryptEnd(IntPtr h, IntPtr pData32, IntPtr pSeed32) - { - NativeMethods.gcry_cipher_close(h); - - Marshal.WriteInt64(pData32, 0); - Marshal.WriteInt64(pData32, 8, 0); - Marshal.WriteInt64(pData32, 16, 0); - Marshal.WriteInt64(pData32, 24, 0); - - Marshal.FreeCoTaskMem(pData32); - Marshal.FreeCoTaskMem(pSeed32); - } - - private static bool TransformKeyGCryptPriv(byte[] pbData32, byte[] pbSeed32, - ulong uRounds) - { - IntPtr h = IntPtr.Zero, pData32 = IntPtr.Zero, pSeed32 = IntPtr.Zero; - if(!GCryptBegin(pbData32, pbSeed32, ref h, ref pData32, ref pSeed32)) - return false; - - try - { - IntPtr n32 = new IntPtr(32); - for(ulong i = 0; i < uRounds; ++i) - { - if(NativeMethods.gcry_cipher_encrypt(h, pData32, n32, - IntPtr.Zero, IntPtr.Zero) != 0) - { - Debug.Assert(false); - return false; - } - } - - Marshal.Copy(pData32, pbData32, 0, 32); - return true; - } - catch(Exception) { Debug.Assert(false); } - finally { GCryptEnd(h, pData32, pSeed32); } - - return false; - } - - private static bool TransformKeyBenchmarkGCryptPriv(uint uTimeMs, ref ulong uRounds) - { - byte[] pbData32 = new byte[32]; - byte[] pbSeed32 = new byte[32]; - - IntPtr h = IntPtr.Zero, pData32 = IntPtr.Zero, pSeed32 = IntPtr.Zero; - if(!GCryptBegin(pbData32, pbSeed32, ref h, ref pData32, ref pSeed32)) - return false; - - uint uMaxMs = uTimeMs; - ulong uDiv = 1; - if(uMaxMs <= (uint.MaxValue >> 1)) { uMaxMs *= 2U; uDiv = 2; } - - try - { - ulong r = 0; - IntPtr n32 = new IntPtr(32); - int tStart = Environment.TickCount; - while(true) - { - for(ulong j = 0; j < BenchStep; ++j) - { - if(NativeMethods.gcry_cipher_encrypt(h, pData32, n32, - IntPtr.Zero, IntPtr.Zero) != 0) - { - Debug.Assert(false); - return false; - } - } - - r += BenchStep; - if(r < BenchStep) // Overflow check - { - r = ulong.MaxValue; - break; - } - - uint tElapsed = (uint)(Environment.TickCount - tStart); - if(tElapsed > uMaxMs) break; - } - - uRounds = r / uDiv; - return true; - } - catch(Exception) { Debug.Assert(false); } - finally { GCryptEnd(h, pData32, pSeed32); } - - return false; - } - } -} diff --git a/ModernKeePassLib/Cryptography/KeyDerivation/AesKdf.cs b/ModernKeePassLib/Cryptography/KeyDerivation/AesKdf.cs deleted file mode 100644 index 16a4a3c..0000000 --- a/ModernKeePassLib/Cryptography/KeyDerivation/AesKdf.cs +++ /dev/null @@ -1,281 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -#if ModernKeePassLib || KeePassUAP -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Parameters; -#else -using System.Security.Cryptography; -#endif - -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Native; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.KeyDerivation -{ - public sealed partial class AesKdf : KdfEngine - { - private static readonly PwUuid g_uuid = new PwUuid(new byte[] { - 0xC9, 0xD9, 0xF3, 0x9A, 0x62, 0x8A, 0x44, 0x60, - 0xBF, 0x74, 0x0D, 0x08, 0xC1, 0x8A, 0x4F, 0xEA }); - - public const string ParamRounds = "R"; // UInt64 - public const string ParamSeed = "S"; // Byte[32] - - private const ulong BenchStep = 3001; - - public override PwUuid Uuid - { - get { return g_uuid; } - } - - public override string Name - { - get { return "AES-KDF"; } - } - - public AesKdf() - { - } - - public override KdfParameters GetDefaultParameters() - { - KdfParameters p = base.GetDefaultParameters(); - p.SetUInt64(ParamRounds, PwDefs.DefaultKeyEncryptionRounds); - return p; - } - - public override void Randomize(KdfParameters p) - { - if(p == null) { Debug.Assert(false); return; } - Debug.Assert(g_uuid.Equals(p.KdfUuid)); - - byte[] pbSeed = CryptoRandom.Instance.GetRandomBytes(32); - p.SetByteArray(ParamSeed, pbSeed); - } - - public override byte[] Transform(byte[] pbMsg, KdfParameters p) - { - if(pbMsg == null) throw new ArgumentNullException("pbMsg"); - if(p == null) throw new ArgumentNullException("p"); - - Type tRounds = p.GetTypeOf(ParamRounds); - if(tRounds == null) throw new ArgumentNullException("p.Rounds"); - if(tRounds != typeof(ulong)) throw new ArgumentOutOfRangeException("p.Rounds"); - ulong uRounds = p.GetUInt64(ParamRounds, 0); - - byte[] pbSeed = p.GetByteArray(ParamSeed); - if(pbSeed == null) throw new ArgumentNullException("p.Seed"); - - if(pbMsg.Length != 32) - { - Debug.Assert(false); - pbMsg = CryptoUtil.HashSha256(pbMsg); - } - - if(pbSeed.Length != 32) - { - Debug.Assert(false); - pbSeed = CryptoUtil.HashSha256(pbSeed); - } - - return TransformKey(pbMsg, pbSeed, uRounds); - } - - private static byte[] TransformKey(byte[] pbOriginalKey32, byte[] pbKeySeed32, - ulong uNumRounds) - { - Debug.Assert((pbOriginalKey32 != null) && (pbOriginalKey32.Length == 32)); - if(pbOriginalKey32 == null) throw new ArgumentNullException("pbOriginalKey32"); - if(pbOriginalKey32.Length != 32) throw new ArgumentException(); - - Debug.Assert((pbKeySeed32 != null) && (pbKeySeed32.Length == 32)); - if(pbKeySeed32 == null) throw new ArgumentNullException("pbKeySeed32"); - if(pbKeySeed32.Length != 32) throw new ArgumentException(); - - byte[] pbNewKey = new byte[32]; - Array.Copy(pbOriginalKey32, pbNewKey, pbNewKey.Length); - - try - { -#if !ModernKeePassLib - // Try to use the native library first - if(NativeLib.TransformKey256(pbNewKey, pbKeySeed32, uNumRounds)) - return CryptoUtil.HashSha256(pbNewKey); -#endif - - if(TransformKeyGCrypt(pbNewKey, pbKeySeed32, uNumRounds)) - return CryptoUtil.HashSha256(pbNewKey); - - if(TransformKeyManaged(pbNewKey, pbKeySeed32, uNumRounds)) - return CryptoUtil.HashSha256(pbNewKey); - } - finally { MemUtil.ZeroByteArray(pbNewKey); } - - return null; - } - - public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32, - ulong uNumRounds) - { -#if ModernKeePassLib || KeePassUAP - KeyParameter kp = new KeyParameter(pbKeySeed32); - AesEngine aes = new AesEngine(); - aes.Init(true, kp); - - for(ulong i = 0; i < uNumRounds; ++i) - { - aes.ProcessBlock(pbNewKey32, 0, pbNewKey32, 0); - aes.ProcessBlock(pbNewKey32, 16, pbNewKey32, 16); - } -#else - byte[] pbIV = new byte[16]; - Array.Clear(pbIV, 0, pbIV.Length); - - SymmetricAlgorithm a = CryptoUtil.CreateAes(); - if(a.BlockSize != 128) // AES block size - { - Debug.Assert(false); - a.BlockSize = 128; - } - - a.IV = pbIV; - a.Mode = CipherMode.ECB; - a.KeySize = 256; - a.Key = pbKeySeed32; - ICryptoTransform iCrypt = a.CreateEncryptor(); - - // !iCrypt.CanReuseTransform -- doesn't work with Mono - if((iCrypt == null) || (iCrypt.InputBlockSize != 16) || - (iCrypt.OutputBlockSize != 16)) - { - Debug.Assert(false, "Invalid ICryptoTransform."); - Debug.Assert((iCrypt.InputBlockSize == 16), "Invalid input block size!"); - Debug.Assert((iCrypt.OutputBlockSize == 16), "Invalid output block size!"); - return false; - } - - for(ulong i = 0; i < uNumRounds; ++i) - { - iCrypt.TransformBlock(pbNewKey32, 0, 16, pbNewKey32, 0); - iCrypt.TransformBlock(pbNewKey32, 16, 16, pbNewKey32, 16); - } -#endif - - return true; - } - - public override KdfParameters GetBestParameters(uint uMilliseconds) - { - KdfParameters p = GetDefaultParameters(); - ulong uRounds; -#if !ModernKeePassLib - // Try native method - if(NativeLib.TransformKeyBenchmark256(uMilliseconds, out uRounds)) - { - p.SetUInt64(ParamRounds, uRounds); - return p; - } -#endif - if(TransformKeyBenchmarkGCrypt(uMilliseconds, out uRounds)) - { - p.SetUInt64(ParamRounds, uRounds); - return p; - } - - byte[] pbKey = new byte[32]; - byte[] pbNewKey = new byte[32]; - for(int i = 0; i < pbKey.Length; ++i) - { - pbKey[i] = (byte)i; - pbNewKey[i] = (byte)i; - } - -#if ModernKeePassLib || KeePassUAP - KeyParameter kp = new KeyParameter(pbKey); - AesEngine aes = new AesEngine(); - aes.Init(true, kp); -#else - byte[] pbIV = new byte[16]; - Array.Clear(pbIV, 0, pbIV.Length); - - SymmetricAlgorithm a = CryptoUtil.CreateAes(); - if(a.BlockSize != 128) // AES block size - { - Debug.Assert(false); - a.BlockSize = 128; - } - - a.IV = pbIV; - a.Mode = CipherMode.ECB; - a.KeySize = 256; - a.Key = pbKey; - ICryptoTransform iCrypt = a.CreateEncryptor(); - - // !iCrypt.CanReuseTransform -- doesn't work with Mono - if((iCrypt == null) || (iCrypt.InputBlockSize != 16) || - (iCrypt.OutputBlockSize != 16)) - { - Debug.Assert(false, "Invalid ICryptoTransform."); - Debug.Assert(iCrypt.InputBlockSize == 16, "Invalid input block size!"); - Debug.Assert(iCrypt.OutputBlockSize == 16, "Invalid output block size!"); - - p.SetUInt64(ParamRounds, PwDefs.DefaultKeyEncryptionRounds); - return p; - } -#endif - - uRounds = 0; - int tStart = Environment.TickCount; - while(true) - { - for(ulong j = 0; j < BenchStep; ++j) - { -#if ModernKeePassLib || KeePassUAP - aes.ProcessBlock(pbNewKey, 0, pbNewKey, 0); - aes.ProcessBlock(pbNewKey, 16, pbNewKey, 16); -#else - iCrypt.TransformBlock(pbNewKey, 0, 16, pbNewKey, 0); - iCrypt.TransformBlock(pbNewKey, 16, 16, pbNewKey, 16); -#endif - } - - uRounds += BenchStep; - if(uRounds < BenchStep) // Overflow check - { - uRounds = ulong.MaxValue; - break; - } - - uint tElapsed = (uint)(Environment.TickCount - tStart); - if(tElapsed > uMilliseconds) break; - } - - p.SetUInt64(ParamRounds, uRounds); - return p; - } - } -} diff --git a/ModernKeePassLib/Cryptography/KeyDerivation/Argon2Kdf.Core.cs b/ModernKeePassLib/Cryptography/KeyDerivation/Argon2Kdf.Core.cs deleted file mode 100644 index c706c6e..0000000 --- a/ModernKeePassLib/Cryptography/KeyDerivation/Argon2Kdf.Core.cs +++ /dev/null @@ -1,637 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// This implementation is based on the official reference C -// implementation by Daniel Dinu and Dmitry Khovratovich (CC0 1.0). - -// Relative iterations (* = B2ROUND_ARRAYS \\ G_INLINED): -// * | false true -// ------+----------- -// false | 8885 9618 -// true | 9009 9636 -#define ARGON2_B2ROUND_ARRAYS -#define ARGON2_G_INLINED - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using ModernKeePassLib.Cryptography.Hash; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.KeyDerivation -{ - public sealed partial class Argon2Kdf : KdfEngine - { - private const ulong NbBlockSize = 1024; - private const ulong NbBlockSizeInQW = NbBlockSize / 8UL; - private const ulong NbSyncPoints = 4; - - private const int NbPreHashDigestLength = 64; - private const int NbPreHashSeedLength = NbPreHashDigestLength + 8; - -#if ARGON2_B2ROUND_ARRAYS - private static int[][] g_vFBCols = null; - private static int[][] g_vFBRows = null; -#endif - - private sealed class Argon2Ctx - { - public uint Version = 0; - - public ulong Lanes = 0; - public ulong TCost = 0; - public ulong MCost = 0; - public ulong MemoryBlocks = 0; - public ulong SegmentLength = 0; - public ulong LaneLength = 0; - - public ulong[] Mem = null; - } - - private sealed class Argon2ThreadInfo - { - public Argon2Ctx Context = null; - public ManualResetEvent Finished = new ManualResetEvent(false); - - public ulong Pass = 0; - public ulong Lane = 0; - public ulong Slice = 0; - public ulong Index = 0; - - public void Release() - { - if(this.Finished != null) - { - this.Finished.Dispose(); - this.Finished = null; - } - else { Debug.Assert(false); } - } - } - - private static byte[] Argon2d(byte[] pbMsg, byte[] pbSalt, uint uParallel, - ulong uMem, ulong uIt, int cbOut, uint uVersion, byte[] pbSecretKey, - byte[] pbAssocData) - { - pbSecretKey = (pbSecretKey ?? MemUtil.EmptyByteArray); - pbAssocData = (pbAssocData ?? MemUtil.EmptyByteArray); - -#if ARGON2_B2ROUND_ARRAYS - InitB2RoundIndexArrays(); -#endif - - Argon2Ctx ctx = new Argon2Ctx(); - ctx.Version = uVersion; - - ctx.Lanes = uParallel; - ctx.TCost = uIt; - ctx.MCost = uMem / NbBlockSize; - ctx.MemoryBlocks = Math.Max(ctx.MCost, 2UL * NbSyncPoints * ctx.Lanes); - - ctx.SegmentLength = ctx.MemoryBlocks / (ctx.Lanes * NbSyncPoints); - ctx.MemoryBlocks = ctx.SegmentLength * ctx.Lanes * NbSyncPoints; - - ctx.LaneLength = ctx.SegmentLength * NbSyncPoints; - - Debug.Assert(NbBlockSize == (NbBlockSizeInQW * -#if ModernKeePassLib || KeePassUAP - (ulong)Marshal.SizeOf() -#else - (ulong)Marshal.SizeOf(typeof(ulong)) -#endif - )); - ctx.Mem = new ulong[ctx.MemoryBlocks * NbBlockSizeInQW]; - - Blake2b h = new Blake2b(); - - // Initial hash - Debug.Assert(h.HashSize == (NbPreHashDigestLength * 8)); - byte[] pbBuf = new byte[4]; - MemUtil.UInt32ToBytesEx(uParallel, pbBuf, 0); - h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); - MemUtil.UInt32ToBytesEx((uint)cbOut, pbBuf, 0); - h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); - MemUtil.UInt32ToBytesEx((uint)ctx.MCost, pbBuf, 0); - h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); - MemUtil.UInt32ToBytesEx((uint)uIt, pbBuf, 0); - h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); - MemUtil.UInt32ToBytesEx(uVersion, pbBuf, 0); - h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); - MemUtil.UInt32ToBytesEx(0, pbBuf, 0); // Argon2d type = 0 - h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); - MemUtil.UInt32ToBytesEx((uint)pbMsg.Length, pbBuf, 0); - h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); - h.TransformBlock(pbMsg, 0, pbMsg.Length, pbMsg, 0); - MemUtil.UInt32ToBytesEx((uint)pbSalt.Length, pbBuf, 0); - h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); - h.TransformBlock(pbSalt, 0, pbSalt.Length, pbSalt, 0); - MemUtil.UInt32ToBytesEx((uint)pbSecretKey.Length, pbBuf, 0); - h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); - h.TransformBlock(pbSecretKey, 0, pbSecretKey.Length, pbSecretKey, 0); - MemUtil.UInt32ToBytesEx((uint)pbAssocData.Length, pbBuf, 0); - h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); - h.TransformBlock(pbAssocData, 0, pbAssocData.Length, pbAssocData, 0); - h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); - byte[] pbH0 = h.Hash; - Debug.Assert(pbH0.Length == 64); - - byte[] pbBlockHash = new byte[NbPreHashSeedLength]; - Array.Copy(pbH0, pbBlockHash, pbH0.Length); - MemUtil.ZeroByteArray(pbH0); - - FillFirstBlocks(ctx, pbBlockHash, h); - MemUtil.ZeroByteArray(pbBlockHash); - - FillMemoryBlocks(ctx); - - byte[] pbOut = FinalHash(ctx, cbOut, h); - - h.Clear(); - MemUtil.ZeroArray(ctx.Mem); - return pbOut; - } - - private static void LoadBlock(ulong[] pqDst, ulong uDstOffset, byte[] pbIn) - { - // for(ulong i = 0; i < NbBlockSizeInQW; ++i) - // pqDst[uDstOffset + i] = MemUtil.BytesToUInt64(pbIn, (int)(i << 3)); - - Debug.Assert((uDstOffset + NbBlockSizeInQW - 1UL) <= (ulong)int.MaxValue); - int iDstOffset = (int)uDstOffset; - for(int i = 0; i < (int)NbBlockSizeInQW; ++i) - pqDst[iDstOffset + i] = MemUtil.BytesToUInt64(pbIn, i << 3); - } - - private static void StoreBlock(byte[] pbDst, ulong[] pqSrc) - { - for(int i = 0; i < (int)NbBlockSizeInQW; ++i) - MemUtil.UInt64ToBytesEx(pqSrc[i], pbDst, i << 3); - } - - private static void CopyBlock(ulong[] vDst, ulong uDstOffset, ulong[] vSrc, - ulong uSrcOffset) - { - // for(ulong i = 0; i < NbBlockSizeInQW; ++i) - // vDst[uDstOffset + i] = vSrc[uSrcOffset + i]; - - // Debug.Assert((uDstOffset + NbBlockSizeInQW - 1UL) <= (ulong)int.MaxValue); - // Debug.Assert((uSrcOffset + NbBlockSizeInQW - 1UL) <= (ulong)int.MaxValue); - // int iDstOffset = (int)uDstOffset; - // int iSrcOffset = (int)uSrcOffset; - // for(int i = 0; i < (int)NbBlockSizeInQW; ++i) - // vDst[iDstOffset + i] = vSrc[iSrcOffset + i]; - -#if ModernKeePassLib || KeePassUAP - Array.Copy(vSrc, (int)uSrcOffset, vDst, (int)uDstOffset, - (int)NbBlockSizeInQW); -#else - Array.Copy(vSrc, (long)uSrcOffset, vDst, (long)uDstOffset, - (long)NbBlockSizeInQW); -#endif - } - - private static void XorBlock(ulong[] vDst, ulong uDstOffset, ulong[] vSrc, - ulong uSrcOffset) - { - // for(ulong i = 0; i < NbBlockSizeInQW; ++i) - // vDst[uDstOffset + i] ^= vSrc[uSrcOffset + i]; - - Debug.Assert((uDstOffset + NbBlockSizeInQW - 1UL) <= (ulong)int.MaxValue); - Debug.Assert((uSrcOffset + NbBlockSizeInQW - 1UL) <= (ulong)int.MaxValue); - int iDstOffset = (int)uDstOffset; - int iSrcOffset = (int)uSrcOffset; - for(int i = 0; i < (int)NbBlockSizeInQW; ++i) - vDst[iDstOffset + i] ^= vSrc[iSrcOffset + i]; - } - - private static void Blake2bLong(byte[] pbOut, int cbOut, - byte[] pbIn, int cbIn, Blake2b h) - { - Debug.Assert((h != null) && (h.HashSize == (64 * 8))); - - byte[] pbOutLen = new byte[4]; - MemUtil.UInt32ToBytesEx((uint)cbOut, pbOutLen, 0); - - if(cbOut <= 64) - { - Blake2b hOut = ((cbOut == 64) ? h : new Blake2b(cbOut)); - if(cbOut == 64) hOut.Initialize(); - - hOut.TransformBlock(pbOutLen, 0, pbOutLen.Length, pbOutLen, 0); - hOut.TransformBlock(pbIn, 0, cbIn, pbIn, 0); - hOut.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); - - Array.Copy(hOut.Hash, pbOut, cbOut); - - if(cbOut < 64) hOut.Clear(); - return; - } - - h.Initialize(); - h.TransformBlock(pbOutLen, 0, pbOutLen.Length, pbOutLen, 0); - h.TransformBlock(pbIn, 0, cbIn, pbIn, 0); - h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); - - byte[] pbOutBuffer = new byte[64]; - Array.Copy(h.Hash, pbOutBuffer, pbOutBuffer.Length); - - int ibOut = 64 / 2; - Array.Copy(pbOutBuffer, pbOut, ibOut); - int cbToProduce = cbOut - ibOut; - - h.Initialize(); - while(cbToProduce > 64) - { - byte[] pbHash = h.ComputeHash(pbOutBuffer); - Array.Copy(pbHash, pbOutBuffer, 64); - - Array.Copy(pbHash, 0, pbOut, ibOut, 64 / 2); - ibOut += 64 / 2; - cbToProduce -= 64 / 2; - - MemUtil.ZeroByteArray(pbHash); - } - - using(Blake2b hOut = new Blake2b(cbToProduce)) - { - byte[] pbHash = hOut.ComputeHash(pbOutBuffer); - Array.Copy(pbHash, 0, pbOut, ibOut, cbToProduce); - - MemUtil.ZeroByteArray(pbHash); - } - - MemUtil.ZeroByteArray(pbOutBuffer); - } - -#if !ARGON2_G_INLINED - private static ulong BlaMka(ulong x, ulong y) - { - ulong xy = (x & 0xFFFFFFFFUL) * (y & 0xFFFFFFFFUL); - return (x + y + (xy << 1)); - } - - private static void G(ulong[] v, int a, int b, int c, int d) - { - ulong va = v[a], vb = v[b], vc = v[c], vd = v[d]; - - va = BlaMka(va, vb); - vd = MemUtil.RotateRight64(vd ^ va, 32); - vc = BlaMka(vc, vd); - vb = MemUtil.RotateRight64(vb ^ vc, 24); - va = BlaMka(va, vb); - vd = MemUtil.RotateRight64(vd ^ va, 16); - vc = BlaMka(vc, vd); - vb = MemUtil.RotateRight64(vb ^ vc, 63); - - v[a] = va; - v[b] = vb; - v[c] = vc; - v[d] = vd; - } -#else - private static void G(ulong[] v, int a, int b, int c, int d) - { - ulong va = v[a], vb = v[b], vc = v[c], vd = v[d]; - - ulong xy = (va & 0xFFFFFFFFUL) * (vb & 0xFFFFFFFFUL); - va += vb + (xy << 1); - - vd = MemUtil.RotateRight64(vd ^ va, 32); - - xy = (vc & 0xFFFFFFFFUL) * (vd & 0xFFFFFFFFUL); - vc += vd + (xy << 1); - - vb = MemUtil.RotateRight64(vb ^ vc, 24); - - xy = (va & 0xFFFFFFFFUL) * (vb & 0xFFFFFFFFUL); - va += vb + (xy << 1); - - vd = MemUtil.RotateRight64(vd ^ va, 16); - - xy = (vc & 0xFFFFFFFFUL) * (vd & 0xFFFFFFFFUL); - vc += vd + (xy << 1); - - vb = MemUtil.RotateRight64(vb ^ vc, 63); - - v[a] = va; - v[b] = vb; - v[c] = vc; - v[d] = vd; - } -#endif - -#if ARGON2_B2ROUND_ARRAYS - private static void Blake2RoundNoMsg(ulong[] pbR, int[] v) - { - G(pbR, v[0], v[4], v[8], v[12]); - G(pbR, v[1], v[5], v[9], v[13]); - G(pbR, v[2], v[6], v[10], v[14]); - G(pbR, v[3], v[7], v[11], v[15]); - G(pbR, v[0], v[5], v[10], v[15]); - G(pbR, v[1], v[6], v[11], v[12]); - G(pbR, v[2], v[7], v[8], v[13]); - G(pbR, v[3], v[4], v[9], v[14]); - } -#else - private static void Blake2RoundNoMsgCols16i(ulong[] pbR, int i) - { - G(pbR, i, i + 4, i + 8, i + 12); - G(pbR, i + 1, i + 5, i + 9, i + 13); - G(pbR, i + 2, i + 6, i + 10, i + 14); - G(pbR, i + 3, i + 7, i + 11, i + 15); - G(pbR, i, i + 5, i + 10, i + 15); - G(pbR, i + 1, i + 6, i + 11, i + 12); - G(pbR, i + 2, i + 7, i + 8, i + 13); - G(pbR, i + 3, i + 4, i + 9, i + 14); - } - - private static void Blake2RoundNoMsgRows2i(ulong[] pbR, int i) - { - G(pbR, i, i + 32, i + 64, i + 96); - G(pbR, i + 1, i + 33, i + 65, i + 97); - G(pbR, i + 16, i + 48, i + 80, i + 112); - G(pbR, i + 17, i + 49, i + 81, i + 113); - G(pbR, i, i + 33, i + 80, i + 113); - G(pbR, i + 1, i + 48, i + 81, i + 96); - G(pbR, i + 16, i + 49, i + 64, i + 97); - G(pbR, i + 17, i + 32, i + 65, i + 112); - } -#endif - - private static void FillFirstBlocks(Argon2Ctx ctx, byte[] pbBlockHash, - Blake2b h) - { - byte[] pbBlock = new byte[NbBlockSize]; - - for(ulong l = 0; l < ctx.Lanes; ++l) - { - MemUtil.UInt32ToBytesEx(0, pbBlockHash, NbPreHashDigestLength); - MemUtil.UInt32ToBytesEx((uint)l, pbBlockHash, NbPreHashDigestLength + 4); - - Blake2bLong(pbBlock, (int)NbBlockSize, pbBlockHash, - NbPreHashSeedLength, h); - LoadBlock(ctx.Mem, l * ctx.LaneLength * NbBlockSizeInQW, pbBlock); - - MemUtil.UInt32ToBytesEx(1, pbBlockHash, NbPreHashDigestLength); - - Blake2bLong(pbBlock, (int)NbBlockSize, pbBlockHash, - NbPreHashSeedLength, h); - LoadBlock(ctx.Mem, (l * ctx.LaneLength + 1UL) * NbBlockSizeInQW, pbBlock); - } - - MemUtil.ZeroByteArray(pbBlock); - } - - private static ulong IndexAlpha(Argon2Ctx ctx, Argon2ThreadInfo ti, - uint uPseudoRand, bool bSameLane) - { - ulong uRefAreaSize; - if(ti.Pass == 0) - { - if(ti.Slice == 0) - { - Debug.Assert(ti.Index > 0); - uRefAreaSize = ti.Index - 1UL; - } - else - { - if(bSameLane) - uRefAreaSize = ti.Slice * ctx.SegmentLength + - ti.Index - 1UL; - else - uRefAreaSize = ti.Slice * ctx.SegmentLength - - ((ti.Index == 0UL) ? 1UL : 0UL); - } - } - else - { - if(bSameLane) - uRefAreaSize = ctx.LaneLength - ctx.SegmentLength + - ti.Index - 1UL; - else - uRefAreaSize = ctx.LaneLength - ctx.SegmentLength - - ((ti.Index == 0) ? 1UL : 0UL); - } - Debug.Assert(uRefAreaSize <= (ulong)uint.MaxValue); - - ulong uRelPos = uPseudoRand; - uRelPos = (uRelPos * uRelPos) >> 32; - uRelPos = uRefAreaSize - 1UL - ((uRefAreaSize * uRelPos) >> 32); - - ulong uStart = 0; - if(ti.Pass != 0) - uStart = (((ti.Slice + 1UL) == NbSyncPoints) ? 0UL : - ((ti.Slice + 1UL) * ctx.SegmentLength)); - Debug.Assert(uStart <= (ulong)uint.MaxValue); - - Debug.Assert(ctx.LaneLength <= (ulong)uint.MaxValue); - return ((uStart + uRelPos) % ctx.LaneLength); - } - - private static void FillMemoryBlocks(Argon2Ctx ctx) - { - int np = (int)ctx.Lanes; - Argon2ThreadInfo[] v = new Argon2ThreadInfo[np]; - - for(ulong r = 0; r < ctx.TCost; ++r) - { - for(ulong s = 0; s < NbSyncPoints; ++s) - { - for(int l = 0; l < np; ++l) - { - Argon2ThreadInfo ti = new Argon2ThreadInfo(); - ti.Context = ctx; - - ti.Pass = r; - ti.Lane = (ulong)l; - ti.Slice = s; - -#if ModernKeePassLib - Task.Factory.StartNew(FillSegmentThr, ti); - //ThreadPool.RunAsync(a => FillSegmentThr(ti)); -#else - if(!ThreadPool.QueueUserWorkItem(FillSegmentThr, ti)) - { - Debug.Assert(false); - throw new OutOfMemoryException(); - } -#endif - v[l] = ti; - } - - for(int l = 0; l < np; ++l) - { - v[l].Finished.WaitOne(); - v[l].Release(); - } - } - } - } - - private static void FillSegmentThr(object o) - { - Argon2ThreadInfo ti = (o as Argon2ThreadInfo); - if(ti == null) { Debug.Assert(false); return; } - - try - { - Argon2Ctx ctx = ti.Context; - if(ctx == null) { Debug.Assert(false); return; } - - Debug.Assert(ctx.Version >= MinVersion); - bool bCanXor = (ctx.Version >= 0x13U); - - ulong uStart = 0; - if((ti.Pass == 0) && (ti.Slice == 0)) uStart = 2; - - ulong uCur = (ti.Lane * ctx.LaneLength) + (ti.Slice * - ctx.SegmentLength) + uStart; - - ulong uPrev = (((uCur % ctx.LaneLength) == 0) ? - (uCur + ctx.LaneLength - 1UL) : (uCur - 1UL)); - - ulong[] pbR = new ulong[NbBlockSizeInQW]; - ulong[] pbTmp = new ulong[NbBlockSizeInQW]; - - for(ulong i = uStart; i < ctx.SegmentLength; ++i) - { - if((uCur % ctx.LaneLength) == 1) - uPrev = uCur - 1UL; - - ulong uPseudoRand = ctx.Mem[uPrev * NbBlockSizeInQW]; - ulong uRefLane = (uPseudoRand >> 32) % ctx.Lanes; - if((ti.Pass == 0) && (ti.Slice == 0)) - uRefLane = ti.Lane; - - ti.Index = i; - ulong uRefIndex = IndexAlpha(ctx, ti, (uint)uPseudoRand, - (uRefLane == ti.Lane)); - - ulong uRefBlockIndex = (ctx.LaneLength * uRefLane + - uRefIndex) * NbBlockSizeInQW; - ulong uCurBlockIndex = uCur * NbBlockSizeInQW; - - FillBlock(ctx.Mem, uPrev * NbBlockSizeInQW, uRefBlockIndex, - uCurBlockIndex, ((ti.Pass != 0) && bCanXor), pbR, pbTmp); - - ++uCur; - ++uPrev; - } - - MemUtil.ZeroArray(pbR); - MemUtil.ZeroArray(pbTmp); - } - catch(Exception) { Debug.Assert(false); } - - try { ti.Finished.Set(); } - catch(Exception) { Debug.Assert(false); } - } - -#if ARGON2_B2ROUND_ARRAYS - private static void InitB2RoundIndexArrays() - { - int[][] vCols = g_vFBCols; - if(vCols == null) - { - vCols = new int[8][]; - Debug.Assert(vCols.Length == 8); - int e = 0; - for(int i = 0; i < 8; ++i) - { - vCols[i] = new int[16]; - for(int j = 0; j < 16; ++j) - { - vCols[i][j] = e; - ++e; - } - } - - g_vFBCols = vCols; - } - - int[][] vRows = g_vFBRows; - if(vRows == null) - { - vRows = new int[8][]; - for(int i = 0; i < 8; ++i) - { - vRows[i] = new int[16]; - for(int j = 0; j < 16; ++j) - { - int jh = j / 2; - vRows[i][j] = (2 * i) + (16 * jh) + (j & 1); - } - } - - g_vFBRows = vRows; - } - } -#endif - - private static void FillBlock(ulong[] pMem, ulong uPrev, ulong uRef, - ulong uNext, bool bXor, ulong[] pbR, ulong[] pbTmp) - { - CopyBlock(pbR, 0, pMem, uRef); - XorBlock(pbR, 0, pMem, uPrev); - CopyBlock(pbTmp, 0, pbR, 0); - if(bXor) XorBlock(pbTmp, 0, pMem, uNext); - -#if ARGON2_B2ROUND_ARRAYS - int[][] vCols = g_vFBCols; - int[][] vRows = g_vFBRows; - for(int i = 0; i < 8; ++i) - Blake2RoundNoMsg(pbR, vCols[i]); - for(int i = 0; i < 8; ++i) - Blake2RoundNoMsg(pbR, vRows[i]); -#else - for(int i = 0; i < (8 * 16); i += 16) - Blake2RoundNoMsgCols16i(pbR, i); - for(int i = 0; i < (8 * 2); i += 2) - Blake2RoundNoMsgRows2i(pbR, i); -#endif - - CopyBlock(pMem, uNext, pbTmp, 0); - XorBlock(pMem, uNext, pbR, 0); - } - - private static byte[] FinalHash(Argon2Ctx ctx, int cbOut, Blake2b h) - { - ulong[] pqBlockHash = new ulong[NbBlockSizeInQW]; - CopyBlock(pqBlockHash, 0, ctx.Mem, (ctx.LaneLength - 1UL) * - NbBlockSizeInQW); - for(ulong l = 1; l < ctx.Lanes; ++l) - XorBlock(pqBlockHash, 0, ctx.Mem, (l * ctx.LaneLength + - ctx.LaneLength - 1UL) * NbBlockSizeInQW); - - byte[] pbBlockHashBytes = new byte[NbBlockSize]; - StoreBlock(pbBlockHashBytes, pqBlockHash); - - byte[] pbOut = new byte[cbOut]; - Blake2bLong(pbOut, cbOut, pbBlockHashBytes, (int)NbBlockSize, h); - - MemUtil.ZeroArray(pqBlockHash); - MemUtil.ZeroByteArray(pbBlockHashBytes); - return pbOut; - } - } -} diff --git a/ModernKeePassLib/Cryptography/KeyDerivation/Argon2Kdf.cs b/ModernKeePassLib/Cryptography/KeyDerivation/Argon2Kdf.cs deleted file mode 100644 index a65b0e2..0000000 --- a/ModernKeePassLib/Cryptography/KeyDerivation/Argon2Kdf.cs +++ /dev/null @@ -1,144 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -namespace ModernKeePassLib.Cryptography.KeyDerivation -{ - public sealed partial class Argon2Kdf : KdfEngine - { - private static readonly PwUuid g_uuid = new PwUuid(new byte[] { - 0xEF, 0x63, 0x6D, 0xDF, 0x8C, 0x29, 0x44, 0x4B, - 0x91, 0xF7, 0xA9, 0xA4, 0x03, 0xE3, 0x0A, 0x0C }); - - public const string ParamSalt = "S"; // Byte[] - public const string ParamParallelism = "P"; // UInt32 - public const string ParamMemory = "M"; // UInt64 - public const string ParamIterations = "I"; // UInt64 - public const string ParamVersion = "V"; // UInt32 - public const string ParamSecretKey = "K"; // Byte[] - public const string ParamAssocData = "A"; // Byte[] - - private const uint MinVersion = 0x10; - private const uint MaxVersion = 0x13; - - private const int MinSalt = 8; - private const int MaxSalt = int.MaxValue; // .NET limit; 2^32 - 1 in spec - - internal const ulong MinIterations = 1; - internal const ulong MaxIterations = uint.MaxValue; - - internal const ulong MinMemory = 1024 * 8; // For parallelism = 1 - // internal const ulong MaxMemory = (ulong)uint.MaxValue * 1024UL; // Spec - internal const ulong MaxMemory = int.MaxValue; // .NET limit - - internal const uint MinParallelism = 1; - internal const uint MaxParallelism = (1 << 24) - 1; - - internal const ulong DefaultIterations = 2; - internal const ulong DefaultMemory = 1024 * 1024; // 1 MB - internal const uint DefaultParallelism = 2; - - public override PwUuid Uuid - { - get { return g_uuid; } - } - - public override string Name - { - get { return "Argon2"; } - } - - public Argon2Kdf() - { - } - - public override KdfParameters GetDefaultParameters() - { - KdfParameters p = base.GetDefaultParameters(); - - p.SetUInt32(ParamVersion, MaxVersion); - - p.SetUInt64(ParamIterations, DefaultIterations); - p.SetUInt64(ParamMemory, DefaultMemory); - p.SetUInt32(ParamParallelism, DefaultParallelism); - - return p; - } - - public override void Randomize(KdfParameters p) - { - if(p == null) { Debug.Assert(false); return; } - Debug.Assert(g_uuid.Equals(p.KdfUuid)); - - byte[] pb = CryptoRandom.Instance.GetRandomBytes(32); - p.SetByteArray(ParamSalt, pb); - } - - public override byte[] Transform(byte[] pbMsg, KdfParameters p) - { - if(pbMsg == null) throw new ArgumentNullException("pbMsg"); - if(p == null) throw new ArgumentNullException("p"); - - byte[] pbSalt = p.GetByteArray(ParamSalt); - if(pbSalt == null) - throw new ArgumentNullException("p.Salt"); - if((pbSalt.Length < MinSalt) || (pbSalt.Length > MaxSalt)) - throw new ArgumentOutOfRangeException("p.Salt"); - - uint uPar = p.GetUInt32(ParamParallelism, 0); - if((uPar < MinParallelism) || (uPar > MaxParallelism)) - throw new ArgumentOutOfRangeException("p.Parallelism"); - - ulong uMem = p.GetUInt64(ParamMemory, 0); - if((uMem < MinMemory) || (uMem > MaxMemory)) - throw new ArgumentOutOfRangeException("p.Memory"); - - ulong uIt = p.GetUInt64(ParamIterations, 0); - if((uIt < MinIterations) || (uIt > MaxIterations)) - throw new ArgumentOutOfRangeException("p.Iterations"); - - uint v = p.GetUInt32(ParamVersion, 0); - if((v < MinVersion) || (v > MaxVersion)) - throw new ArgumentOutOfRangeException("p.Version"); - - byte[] pbSecretKey = p.GetByteArray(ParamSecretKey); - byte[] pbAssocData = p.GetByteArray(ParamAssocData); - - byte[] pbRet = Argon2d(pbMsg, pbSalt, uPar, uMem, uIt, - 32, v, pbSecretKey, pbAssocData); - - if(uMem > (100UL * 1024UL * 1024UL)) GC.Collect(); - return pbRet; - } - - public override KdfParameters GetBestParameters(uint uMilliseconds) - { - KdfParameters p = GetDefaultParameters(); - Randomize(p); - - MaximizeParamUInt64(p, ParamIterations, MinIterations, - MaxIterations, uMilliseconds, true); - return p; - } - } -} diff --git a/ModernKeePassLib/Cryptography/KeyDerivation/KdfEngine.cs b/ModernKeePassLib/Cryptography/KeyDerivation/KdfEngine.cs deleted file mode 100644 index dc108ea..0000000 --- a/ModernKeePassLib/Cryptography/KeyDerivation/KdfEngine.cs +++ /dev/null @@ -1,142 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -namespace ModernKeePassLib.Cryptography.KeyDerivation -{ - public abstract class KdfEngine - { - public abstract PwUuid Uuid - { - get; - } - - public abstract string Name - { - get; - } - - public virtual KdfParameters GetDefaultParameters() - { - return new KdfParameters(this.Uuid); - } - - /// - /// Generate random seeds and store them in . - /// - public virtual void Randomize(KdfParameters p) - { - Debug.Assert(p != null); - Debug.Assert(p.KdfUuid.Equals(this.Uuid)); - } - - public abstract byte[] Transform(byte[] pbMsg, KdfParameters p); - - public virtual KdfParameters GetBestParameters(uint uMilliseconds) - { - throw new NotImplementedException(); - } - - protected void MaximizeParamUInt64(KdfParameters p, string strName, - ulong uMin, ulong uMax, uint uMilliseconds, bool bInterpSearch) - { - if(p == null) { Debug.Assert(false); return; } - if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return; } - if(uMin > uMax) { Debug.Assert(false); return; } - - if(uMax > (ulong.MaxValue >> 1)) - { - Debug.Assert(false); - uMax = ulong.MaxValue >> 1; - - if(uMin > uMax) { p.SetUInt64(strName, uMin); return; } - } - - byte[] pbMsg = new byte[32]; - for(int i = 0; i < pbMsg.Length; ++i) pbMsg[i] = (byte)i; - - ulong uLow = uMin; - ulong uHigh = uMin + 1UL; - long tLow = 0; - long tHigh = 0; - long tTarget = (long)uMilliseconds; - - // Determine range - while(uHigh <= uMax) - { - p.SetUInt64(strName, uHigh); - - // GC.Collect(); - Stopwatch sw = Stopwatch.StartNew(); - Transform(pbMsg, p); - sw.Stop(); - - tHigh = sw.ElapsedMilliseconds; - if(tHigh > tTarget) break; - - uLow = uHigh; - tLow = tHigh; - uHigh <<= 1; - } - if(uHigh > uMax) { uHigh = uMax; tHigh = 0; } - if(uLow > uHigh) uLow = uHigh; // Skips to end - - // Find optimal number of iterations - while((uHigh - uLow) >= 2UL) - { - ulong u = (uHigh + uLow) >> 1; // Binary search - // Interpolation search, if possible - if(bInterpSearch && (tLow > 0) && (tHigh > tTarget) && - (tLow <= tTarget)) - { - u = uLow + (((uHigh - uLow) * (ulong)(tTarget - tLow)) / - (ulong)(tHigh - tLow)); - if((u >= uLow) && (u <= uHigh)) - { - u = Math.Max(u, uLow + 1UL); - u = Math.Min(u, uHigh - 1UL); - } - else - { - Debug.Assert(false); - u = (uHigh + uLow) >> 1; - } - } - - p.SetUInt64(strName, u); - - // GC.Collect(); - Stopwatch sw = Stopwatch.StartNew(); - Transform(pbMsg, p); - sw.Stop(); - - long t = sw.ElapsedMilliseconds; - if(t == tTarget) { uLow = u; break; } - else if(t > tTarget) { uHigh = u; tHigh = t; } - else { uLow = u; tLow = t; } - } - - p.SetUInt64(strName, uLow); - } - } -} diff --git a/ModernKeePassLib/Cryptography/KeyDerivation/KdfParameters.cs b/ModernKeePassLib/Cryptography/KeyDerivation/KdfParameters.cs deleted file mode 100644 index 04de500..0000000 --- a/ModernKeePassLib/Cryptography/KeyDerivation/KdfParameters.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; - -using ModernKeePassLib.Collections; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.KeyDerivation -{ - public sealed class KdfParameters : VariantDictionary - { - private const string ParamUuid = @"$UUID"; - - private readonly PwUuid m_puKdf; - public PwUuid KdfUuid - { - get { return m_puKdf; } - } - - public KdfParameters(PwUuid puKdf) - { - if(puKdf == null) throw new ArgumentNullException("puKdf"); - - m_puKdf = puKdf; - SetByteArray(ParamUuid, puKdf.UuidBytes); - } - - /// - /// Unsupported. - /// - public override object Clone() - { - throw new NotSupportedException(); - } - - public static byte[] SerializeExt(KdfParameters p) - { - return VariantDictionary.Serialize(p); - } - - public static KdfParameters DeserializeExt(byte[] pb) - { - VariantDictionary d = VariantDictionary.Deserialize(pb); - if(d == null) { Debug.Assert(false); return null; } - - byte[] pbUuid = d.GetByteArray(ParamUuid); - if((pbUuid == null) || (pbUuid.Length != (int)PwUuid.UuidSize)) - { - Debug.Assert(false); - return null; - } - - PwUuid pu = new PwUuid(pbUuid); - KdfParameters p = new KdfParameters(pu); - d.CopyTo(p); - return p; - } - } -} diff --git a/ModernKeePassLib/Cryptography/KeyDerivation/KdfPool.cs b/ModernKeePassLib/Cryptography/KeyDerivation/KdfPool.cs deleted file mode 100644 index 5b631b7..0000000 --- a/ModernKeePassLib/Cryptography/KeyDerivation/KdfPool.cs +++ /dev/null @@ -1,96 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.KeyDerivation -{ - public static class KdfPool - { - private static List g_l = new List(); - - public static IEnumerable Engines - { - get - { - EnsureInitialized(); - return g_l; - } - } - - private static void EnsureInitialized() - { - if(g_l.Count > 0) return; - - g_l.Add(new AesKdf()); - g_l.Add(new Argon2Kdf()); - } - - internal static KdfParameters GetDefaultParameters() - { - EnsureInitialized(); - return g_l[0].GetDefaultParameters(); - } - - public static KdfEngine Get(PwUuid pu) - { - if(pu == null) { Debug.Assert(false); return null; } - - EnsureInitialized(); - - foreach(KdfEngine kdf in g_l) - { - if(pu.Equals(kdf.Uuid)) return kdf; - } - - return null; - } - - public static KdfEngine Get(string strName) - { - if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return null; } - - EnsureInitialized(); - - foreach(KdfEngine kdf in g_l) - { - if(strName.Equals(kdf.Name, StrUtil.CaseIgnoreCmp)) return kdf; - } - - return null; - } - - public static void Add(KdfEngine kdf) - { - if(kdf == null) { Debug.Assert(false); return; } - - EnsureInitialized(); - - if(Get(kdf.Uuid) != null) { Debug.Assert(false); return; } - if(Get(kdf.Name) != null) { Debug.Assert(false); return; } - - g_l.Add(kdf); - } - } -} diff --git a/ModernKeePassLib/Cryptography/PasswordGenerator/CharSetBasedGenerator.cs b/ModernKeePassLib/Cryptography/PasswordGenerator/CharSetBasedGenerator.cs deleted file mode 100644 index 92d321d..0000000 --- a/ModernKeePassLib/Cryptography/PasswordGenerator/CharSetBasedGenerator.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.PasswordGenerator -{ - internal static class CharSetBasedGenerator - { - internal static PwgError Generate(out ProtectedString psOut, - PwProfile pwProfile, CryptoRandomStream crsRandomSource) - { - psOut = ProtectedString.Empty; - if(pwProfile.Length == 0) return PwgError.Success; - - PwCharSet pcs = new PwCharSet(pwProfile.CharSet.ToString()); - char[] vGenerated = new char[pwProfile.Length]; - - PwGenerator.PrepareCharSet(pcs, pwProfile); - - for(int nIndex = 0; nIndex < (int)pwProfile.Length; ++nIndex) - { - char ch = PwGenerator.GenerateCharacter(pwProfile, pcs, - crsRandomSource); - - if(ch == char.MinValue) - { - MemUtil.ZeroArray(vGenerated); - return PwgError.TooFewCharacters; - } - - vGenerated[nIndex] = ch; - } - - byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vGenerated); - psOut = new ProtectedString(true, pbUtf8); - MemUtil.ZeroByteArray(pbUtf8); - MemUtil.ZeroArray(vGenerated); - - return PwgError.Success; - } - } -} diff --git a/ModernKeePassLib/Cryptography/PasswordGenerator/CustomPwGenerator.cs b/ModernKeePassLib/Cryptography/PasswordGenerator/CustomPwGenerator.cs deleted file mode 100644 index 4ccaa03..0000000 --- a/ModernKeePassLib/Cryptography/PasswordGenerator/CustomPwGenerator.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -using ModernKeePassLib; -using ModernKeePassLib.Security; - -namespace ModernKeePassLib.Cryptography.PasswordGenerator -{ - public abstract class CustomPwGenerator - { - /// - /// Each custom password generation algorithm must have - /// its own unique UUID. - /// - public abstract PwUuid Uuid { get; } - - /// - /// Displayable name of the password generation algorithm. - /// - public abstract string Name { get; } - - public virtual bool SupportsOptions - { - get { return false; } - } - - /// - /// Password generation function. - /// - /// Password generation options chosen - /// by the user. This may be null, if the default - /// options should be used. - /// Source that the algorithm - /// can use to generate random numbers. - /// Generated password or null in case - /// of failure. If returning null, the caller assumes - /// that an error message has already been shown to the user. - public abstract ProtectedString Generate(PwProfile prf, - CryptoRandomStream crsRandomSource); - - public virtual string GetOptions(string strCurrentOptions) - { - return string.Empty; - } - } -} diff --git a/ModernKeePassLib/Cryptography/PasswordGenerator/CustomPwGeneratorPool.cs b/ModernKeePassLib/Cryptography/PasswordGenerator/CustomPwGeneratorPool.cs deleted file mode 100644 index 952faad..0000000 --- a/ModernKeePassLib/Cryptography/PasswordGenerator/CustomPwGeneratorPool.cs +++ /dev/null @@ -1,110 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; - -namespace ModernKeePassLib.Cryptography.PasswordGenerator -{ - public sealed class CustomPwGeneratorPool : IEnumerable - { - private List m_vGens = new List(); - - public int Count - { - get { return m_vGens.Count; } - } - - public CustomPwGeneratorPool() - { - } - - IEnumerator IEnumerable.GetEnumerator() - { - return m_vGens.GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - return m_vGens.GetEnumerator(); - } - - public void Add(CustomPwGenerator pwg) - { - if(pwg == null) throw new ArgumentNullException("pwg"); - - PwUuid uuid = pwg.Uuid; - if(uuid == null) throw new ArgumentException(); - - int nIndex = FindIndex(uuid); - - if(nIndex >= 0) m_vGens[nIndex] = pwg; // Replace - else m_vGens.Add(pwg); - } - - public CustomPwGenerator Find(PwUuid uuid) - { - if(uuid == null) throw new ArgumentNullException("uuid"); - - foreach(CustomPwGenerator pwg in m_vGens) - { - if(uuid.Equals(pwg.Uuid)) return pwg; - } - - return null; - } - - public CustomPwGenerator Find(string strName) - { - if(strName == null) throw new ArgumentNullException("strName"); - - foreach(CustomPwGenerator pwg in m_vGens) - { - if(pwg.Name == strName) return pwg; - } - - return null; - } - - private int FindIndex(PwUuid uuid) - { - if(uuid == null) throw new ArgumentNullException("uuid"); - - for(int i = 0; i < m_vGens.Count; ++i) - { - if(uuid.Equals(m_vGens[i].Uuid)) return i; - } - - return -1; - } - - public bool Remove(PwUuid uuid) - { - if(uuid == null) throw new ArgumentNullException("uuid"); - - int nIndex = FindIndex(uuid); - if(nIndex < 0) return false; - - m_vGens.RemoveAt(nIndex); - return true; - } - } -} diff --git a/ModernKeePassLib/Cryptography/PasswordGenerator/PatternBasedGenerator.cs b/ModernKeePassLib/Cryptography/PasswordGenerator/PatternBasedGenerator.cs deleted file mode 100644 index b14c1d5..0000000 --- a/ModernKeePassLib/Cryptography/PasswordGenerator/PatternBasedGenerator.cs +++ /dev/null @@ -1,184 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.PasswordGenerator -{ - internal static class PatternBasedGenerator - { - internal static PwgError Generate(out ProtectedString psOut, - PwProfile pwProfile, CryptoRandomStream crsRandomSource) - { - psOut = ProtectedString.Empty; - LinkedList vGenerated = new LinkedList(); - PwCharSet pcsCurrent = new PwCharSet(); - PwCharSet pcsCustom = new PwCharSet(); - PwCharSet pcsUsed = new PwCharSet(); - bool bInCharSetDef = false; - - string strPattern = ExpandPattern(pwProfile.Pattern); - if(strPattern.Length == 0) return PwgError.Success; - - CharStream csStream = new CharStream(strPattern); - char ch = csStream.ReadChar(); - - while(ch != char.MinValue) - { - pcsCurrent.Clear(); - - bool bGenerateChar = false; - - if(ch == '\\') - { - ch = csStream.ReadChar(); - if(ch == char.MinValue) // Backslash at the end - { - vGenerated.AddLast('\\'); - break; - } - - if(bInCharSetDef) pcsCustom.Add(ch); - else - { - vGenerated.AddLast(ch); - pcsUsed.Add(ch); - } - } - else if(ch == '^') - { - ch = csStream.ReadChar(); - if(ch == char.MinValue) // ^ at the end - { - vGenerated.AddLast('^'); - break; - } - - if(bInCharSetDef) pcsCustom.Remove(ch); - } - else if(ch == '[') - { - pcsCustom.Clear(); - bInCharSetDef = true; - } - else if(ch == ']') - { - pcsCurrent.Add(pcsCustom.ToString()); - - bInCharSetDef = false; - bGenerateChar = true; - } - else if(bInCharSetDef) - { - if(pcsCustom.AddCharSet(ch) == false) - pcsCustom.Add(ch); - } - else if(pcsCurrent.AddCharSet(ch) == false) - { - vGenerated.AddLast(ch); - pcsUsed.Add(ch); - } - else bGenerateChar = true; - - if(bGenerateChar) - { - PwGenerator.PrepareCharSet(pcsCurrent, pwProfile); - - if(pwProfile.NoRepeatingCharacters) - pcsCurrent.Remove(pcsUsed.ToString()); - - char chGen = PwGenerator.GenerateCharacter(pwProfile, - pcsCurrent, crsRandomSource); - - if(chGen == char.MinValue) return PwgError.TooFewCharacters; - - vGenerated.AddLast(chGen); - pcsUsed.Add(chGen); - } - - ch = csStream.ReadChar(); - } - - if(vGenerated.Count == 0) return PwgError.Success; - - char[] vArray = new char[vGenerated.Count]; - vGenerated.CopyTo(vArray, 0); - - if(pwProfile.PatternPermutePassword) - PwGenerator.ShufflePassword(vArray, crsRandomSource); - - byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vArray); - psOut = new ProtectedString(true, pbUtf8); - MemUtil.ZeroByteArray(pbUtf8); - MemUtil.ZeroArray(vArray); - vGenerated.Clear(); - - return PwgError.Success; - } - - private static string ExpandPattern(string strPattern) - { - Debug.Assert(strPattern != null); if(strPattern == null) return string.Empty; - string str = strPattern; - - while(true) - { - int nOpen = FindFirstUnescapedChar(str, '{'); - int nClose = FindFirstUnescapedChar(str, '}'); - - if((nOpen >= 0) && (nOpen < nClose)) - { - string strCount = str.Substring(nOpen + 1, nClose - nOpen - 1); - str = str.Remove(nOpen, nClose - nOpen + 1); - - uint uRepeat; - if(StrUtil.TryParseUInt(strCount, out uRepeat) && (nOpen >= 1)) - { - if(uRepeat == 0) - str = str.Remove(nOpen - 1, 1); - else - str = str.Insert(nOpen, new string(str[nOpen - 1], (int)uRepeat - 1)); - } - } - else break; - } - - return str; - } - - private static int FindFirstUnescapedChar(string str, char ch) - { - for(int i = 0; i < str.Length; ++i) - { - char chCur = str[i]; - - if(chCur == '\\') ++i; // Next is escaped, skip it - else if(chCur == ch) return i; - } - - return -1; - } - } -} diff --git a/ModernKeePassLib/Cryptography/PasswordGenerator/PwCharSet.cs b/ModernKeePassLib/Cryptography/PasswordGenerator/PwCharSet.cs deleted file mode 100644 index 3047b75..0000000 --- a/ModernKeePassLib/Cryptography/PasswordGenerator/PwCharSet.cs +++ /dev/null @@ -1,351 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -namespace ModernKeePassLib.Cryptography.PasswordGenerator -{ - public sealed class PwCharSet - { - public const string UpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - public const string LowerCase = "abcdefghijklmnopqrstuvwxyz"; - public const string Digits = "0123456789"; - - public const string UpperConsonants = "BCDFGHJKLMNPQRSTVWXYZ"; - public const string LowerConsonants = "bcdfghjklmnpqrstvwxyz"; - public const string UpperVowels = "AEIOU"; - public const string LowerVowels = "aeiou"; - - public const string Punctuation = @",.;:"; - public const string Brackets = @"[]{}()<>"; - - public const string PrintableAsciiSpecial = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; - - public const string UpperHex = "0123456789ABCDEF"; - public const string LowerHex = "0123456789abcdef"; - - public const string Invalid = "\t\r\n"; - public const string LookAlike = @"O0l1I|"; - - internal const string MenuAccels = PwCharSet.LowerCase + PwCharSet.Digits; - - private const int CharTabSize = (0x10000 / 8); - - private List m_vChars = new List(); - private byte[] m_vTab = new byte[CharTabSize]; - - private static string m_strHighAnsi = null; - public static string HighAnsiChars - { - get - { - if(m_strHighAnsi == null) { new PwCharSet(); } // Create string - Debug.Assert(m_strHighAnsi != null); - return m_strHighAnsi; - } - } - - private static string m_strSpecial = null; - public static string SpecialChars - { - get - { - if(m_strSpecial == null) { new PwCharSet(); } // Create string - Debug.Assert(m_strSpecial != null); - return m_strSpecial; - } - } - - /// - /// Create a new, empty character set collection object. - /// - public PwCharSet() - { - Initialize(true); - } - - public PwCharSet(string strCharSet) - { - Initialize(true); - Add(strCharSet); - } - - private PwCharSet(bool bFullInitialize) - { - Initialize(bFullInitialize); - } - - private void Initialize(bool bFullInitialize) - { - Clear(); - - if(!bFullInitialize) return; - - if(m_strHighAnsi == null) - { - StringBuilder sbHighAnsi = new StringBuilder(); - // [U+0080, U+009F] are C1 control characters, - // U+00A0 is non-breaking space - for(char ch = '\u00A1'; ch <= '\u00AC'; ++ch) - sbHighAnsi.Append(ch); - // U+00AD is soft hyphen (format character) - for(char ch = '\u00AE'; ch < '\u00FF'; ++ch) - sbHighAnsi.Append(ch); - sbHighAnsi.Append('\u00FF'); - - m_strHighAnsi = sbHighAnsi.ToString(); - } - - if(m_strSpecial == null) - { - PwCharSet pcs = new PwCharSet(false); - pcs.AddRange('!', '/'); - pcs.AddRange(':', '@'); - pcs.AddRange('[', '`'); - pcs.Add(@"|~"); - pcs.Remove(@"-_ "); - pcs.Remove(PwCharSet.Brackets); - - m_strSpecial = pcs.ToString(); - } - } - - /// - /// Number of characters in this set. - /// - public uint Size - { - get { return (uint)m_vChars.Count; } - } - - /// - /// Get a character of the set using an index. - /// - /// Index of the character to get. - /// Character at the specified position. If the index is invalid, - /// an ArgumentOutOfRangeException is thrown. - public char this[uint uPos] - { - get - { - if(uPos >= (uint)m_vChars.Count) - throw new ArgumentOutOfRangeException("uPos"); - - return m_vChars[(int)uPos]; - } - } - - /// - /// Remove all characters from this set. - /// - public void Clear() - { - m_vChars.Clear(); - Array.Clear(m_vTab, 0, m_vTab.Length); - } - - public bool Contains(char ch) - { - return (((m_vTab[ch / 8] >> (ch % 8)) & 1) != char.MinValue); - } - - public bool Contains(string strCharacters) - { - Debug.Assert(strCharacters != null); - if(strCharacters == null) throw new ArgumentNullException("strCharacters"); - - foreach(char ch in strCharacters) - { - if(!Contains(ch)) return false; - } - - return true; - } - - /// - /// Add characters to the set. - /// - /// Character to add. - public void Add(char ch) - { - if(ch == char.MinValue) { Debug.Assert(false); return; } - - if(!Contains(ch)) - { - m_vChars.Add(ch); - m_vTab[ch / 8] |= (byte)(1 << (ch % 8)); - } - } - - /// - /// Add characters to the set. - /// - /// String containing characters to add. - public void Add(string strCharSet) - { - Debug.Assert(strCharSet != null); - if(strCharSet == null) throw new ArgumentNullException("strCharSet"); - - m_vChars.Capacity = m_vChars.Count + strCharSet.Length; - - foreach(char ch in strCharSet) - Add(ch); - } - - public void Add(string strCharSet1, string strCharSet2) - { - Add(strCharSet1); - Add(strCharSet2); - } - - public void Add(string strCharSet1, string strCharSet2, string strCharSet3) - { - Add(strCharSet1); - Add(strCharSet2); - Add(strCharSet3); - } - - public void AddRange(char chMin, char chMax) - { - m_vChars.Capacity = m_vChars.Count + (chMax - chMin) + 1; - - for(char ch = chMin; ch < chMax; ++ch) - Add(ch); - - Add(chMax); - } - - public bool AddCharSet(char chCharSetIdentifier) - { - bool bResult = true; - - switch(chCharSetIdentifier) - { - case 'a': Add(PwCharSet.LowerCase, PwCharSet.Digits); break; - case 'A': Add(PwCharSet.LowerCase, PwCharSet.UpperCase, - PwCharSet.Digits); break; - case 'U': Add(PwCharSet.UpperCase, PwCharSet.Digits); break; - case 'c': Add(PwCharSet.LowerConsonants); break; - case 'C': Add(PwCharSet.LowerConsonants, - PwCharSet.UpperConsonants); break; - case 'z': Add(PwCharSet.UpperConsonants); break; - case 'd': Add(PwCharSet.Digits); break; // Digit - case 'h': Add(PwCharSet.LowerHex); break; - case 'H': Add(PwCharSet.UpperHex); break; - case 'l': Add(PwCharSet.LowerCase); break; - case 'L': Add(PwCharSet.LowerCase, PwCharSet.UpperCase); break; - case 'u': Add(PwCharSet.UpperCase); break; - case 'p': Add(PwCharSet.Punctuation); break; - case 'b': Add(PwCharSet.Brackets); break; - case 's': Add(PwCharSet.PrintableAsciiSpecial); break; - case 'S': Add(PwCharSet.UpperCase, PwCharSet.LowerCase); - Add(PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial); break; - case 'v': Add(PwCharSet.LowerVowels); break; - case 'V': Add(PwCharSet.LowerVowels, PwCharSet.UpperVowels); break; - case 'Z': Add(PwCharSet.UpperVowels); break; - case 'x': Add(m_strHighAnsi); break; - default: bResult = false; break; - } - - return bResult; - } - - public bool Remove(char ch) - { - m_vTab[ch / 8] &= (byte)(~(1 << (ch % 8))); - return m_vChars.Remove(ch); - } - - public bool Remove(string strCharacters) - { - Debug.Assert(strCharacters != null); - if(strCharacters == null) throw new ArgumentNullException("strCharacters"); - - bool bResult = true; - foreach(char ch in strCharacters) - { - if(!Remove(ch)) bResult = false; - } - - return bResult; - } - - public bool RemoveIfAllExist(string strCharacters) - { - Debug.Assert(strCharacters != null); - if(strCharacters == null) throw new ArgumentNullException("strCharacters"); - - if(!Contains(strCharacters)) - return false; - - return Remove(strCharacters); - } - - /// - /// Convert the character set to a string containing all its characters. - /// - /// String containing all character set characters. - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - foreach(char ch in m_vChars) - sb.Append(ch); - - return sb.ToString(); - } - - public string PackAndRemoveCharRanges() - { - StringBuilder sb = new StringBuilder(); - - sb.Append(RemoveIfAllExist(PwCharSet.UpperCase) ? 'U' : '_'); - sb.Append(RemoveIfAllExist(PwCharSet.LowerCase) ? 'L' : '_'); - sb.Append(RemoveIfAllExist(PwCharSet.Digits) ? 'D' : '_'); - sb.Append(RemoveIfAllExist(m_strSpecial) ? 'S' : '_'); - sb.Append(RemoveIfAllExist(PwCharSet.Punctuation) ? 'P' : '_'); - sb.Append(RemoveIfAllExist(@"-") ? 'm' : '_'); - sb.Append(RemoveIfAllExist(@"_") ? 'u' : '_'); - sb.Append(RemoveIfAllExist(@" ") ? 's' : '_'); - sb.Append(RemoveIfAllExist(PwCharSet.Brackets) ? 'B' : '_'); - sb.Append(RemoveIfAllExist(m_strHighAnsi) ? 'H' : '_'); - - return sb.ToString(); - } - - public void UnpackCharRanges(string strRanges) - { - if(strRanges == null) { Debug.Assert(false); return; } - if(strRanges.Length < 10) { Debug.Assert(false); return; } - - if(strRanges[0] != '_') Add(PwCharSet.UpperCase); - if(strRanges[1] != '_') Add(PwCharSet.LowerCase); - if(strRanges[2] != '_') Add(PwCharSet.Digits); - if(strRanges[3] != '_') Add(m_strSpecial); - if(strRanges[4] != '_') Add(PwCharSet.Punctuation); - if(strRanges[5] != '_') Add('-'); - if(strRanges[6] != '_') Add('_'); - if(strRanges[7] != '_') Add(' '); - if(strRanges[8] != '_') Add(PwCharSet.Brackets); - if(strRanges[9] != '_') Add(m_strHighAnsi); - } - } -} diff --git a/ModernKeePassLib/Cryptography/PasswordGenerator/PwGenerator.cs b/ModernKeePassLib/Cryptography/PasswordGenerator/PwGenerator.cs deleted file mode 100644 index 7a5c136..0000000 --- a/ModernKeePassLib/Cryptography/PasswordGenerator/PwGenerator.cs +++ /dev/null @@ -1,167 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -#if ModernKeePassLib -using ModernKeePassLib.Cryptography.Hash; -#elif !KeePassUAP -using System.Security.Cryptography; -#endif - -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.PasswordGenerator -{ - public enum PwgError - { - Success = 0, - Unknown = 1, - TooFewCharacters = 2, - UnknownAlgorithm = 3 - } - - /// - /// Utility functions for generating random passwords. - /// - public static class PwGenerator - { - public static PwgError Generate(out ProtectedString psOut, - PwProfile pwProfile, byte[] pbUserEntropy, - CustomPwGeneratorPool pwAlgorithmPool) - { - Debug.Assert(pwProfile != null); - if(pwProfile == null) throw new ArgumentNullException("pwProfile"); - - PwgError e = PwgError.Unknown; - CryptoRandomStream crs = null; - byte[] pbKey = null; - try - { - crs = CreateRandomStream(pbUserEntropy, out pbKey); - - if(pwProfile.GeneratorType == PasswordGeneratorType.CharSet) - e = CharSetBasedGenerator.Generate(out psOut, pwProfile, crs); - else if(pwProfile.GeneratorType == PasswordGeneratorType.Pattern) - e = PatternBasedGenerator.Generate(out psOut, pwProfile, crs); - else if(pwProfile.GeneratorType == PasswordGeneratorType.Custom) - e = GenerateCustom(out psOut, pwProfile, crs, pwAlgorithmPool); - else { Debug.Assert(false); psOut = ProtectedString.Empty; } - } - finally - { - if(crs != null) crs.Dispose(); - if(pbKey != null) MemUtil.ZeroByteArray(pbKey); - } - - return e; - } - - private static CryptoRandomStream CreateRandomStream(byte[] pbAdditionalEntropy, - out byte[] pbKey) - { - pbKey = CryptoRandom.Instance.GetRandomBytes(128); - - // Mix in additional entropy - Debug.Assert(pbKey.Length >= 64); - if((pbAdditionalEntropy != null) && (pbAdditionalEntropy.Length > 0)) - { - using(SHA512Managed h = new SHA512Managed()) - { - byte[] pbHash = h.ComputeHash(pbAdditionalEntropy); - MemUtil.XorArray(pbHash, 0, pbKey, 0, pbHash.Length); - } - } - - return new CryptoRandomStream(CrsAlgorithm.ChaCha20, pbKey); - } - - internal static char GenerateCharacter(PwProfile pwProfile, - PwCharSet pwCharSet, CryptoRandomStream crsRandomSource) - { - if(pwCharSet.Size == 0) return char.MinValue; - - ulong uIndex = crsRandomSource.GetRandomUInt64(); - uIndex %= (ulong)pwCharSet.Size; - - char ch = pwCharSet[(uint)uIndex]; - - if(pwProfile.NoRepeatingCharacters) - pwCharSet.Remove(ch); - - return ch; - } - - internal static void PrepareCharSet(PwCharSet pwCharSet, PwProfile pwProfile) - { - pwCharSet.Remove(PwCharSet.Invalid); - - if(pwProfile.ExcludeLookAlike) pwCharSet.Remove(PwCharSet.LookAlike); - - if(pwProfile.ExcludeCharacters.Length > 0) - pwCharSet.Remove(pwProfile.ExcludeCharacters); - } - - internal static void ShufflePassword(char[] pPassword, - CryptoRandomStream crsRandomSource) - { - Debug.Assert(pPassword != null); if(pPassword == null) return; - Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) return; - - if(pPassword.Length <= 1) return; // Nothing to shuffle - - for(int nSelect = 0; nSelect < pPassword.Length; ++nSelect) - { - ulong uRandomIndex = crsRandomSource.GetRandomUInt64(); - uRandomIndex %= (ulong)(pPassword.Length - nSelect); - - char chTemp = pPassword[nSelect]; - pPassword[nSelect] = pPassword[nSelect + (int)uRandomIndex]; - pPassword[nSelect + (int)uRandomIndex] = chTemp; - } - } - - private static PwgError GenerateCustom(out ProtectedString psOut, - PwProfile pwProfile, CryptoRandomStream crs, - CustomPwGeneratorPool pwAlgorithmPool) - { - psOut = ProtectedString.Empty; - - Debug.Assert(pwProfile.GeneratorType == PasswordGeneratorType.Custom); - if(pwAlgorithmPool == null) return PwgError.UnknownAlgorithm; - - string strID = pwProfile.CustomAlgorithmUuid; - if(string.IsNullOrEmpty(strID)) { Debug.Assert(false); return PwgError.UnknownAlgorithm; } - - byte[] pbUuid = Convert.FromBase64String(strID); - PwUuid uuid = new PwUuid(pbUuid); - CustomPwGenerator pwg = pwAlgorithmPool.Find(uuid); - if(pwg == null) { Debug.Assert(false); return PwgError.UnknownAlgorithm; } - - ProtectedString pwd = pwg.Generate(pwProfile.CloneDeep(), crs); - if(pwd == null) return PwgError.Unknown; - - psOut = pwd; - return PwgError.Success; - } - } -} diff --git a/ModernKeePassLib/Cryptography/PasswordGenerator/PwProfile.cs b/ModernKeePassLib/Cryptography/PasswordGenerator/PwProfile.cs deleted file mode 100644 index aa361e3..0000000 --- a/ModernKeePassLib/Cryptography/PasswordGenerator/PwProfile.cs +++ /dev/null @@ -1,276 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Xml.Serialization; -using System.ComponentModel; -using System.Diagnostics; - -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography.PasswordGenerator -{ - /// - /// Type of the password generator. Different types like generators - /// based on given patterns, based on character sets, etc. are - /// available. - /// - public enum PasswordGeneratorType - { - /// - /// Generator based on character spaces/sets, i.e. groups - /// of characters like lower-case, upper-case or numeric characters. - /// - CharSet = 0, - - /// - /// Password generation based on a pattern. The user has provided - /// a pattern, which describes how the generated password has to - /// look like. - /// - Pattern = 1, - - Custom = 2 - } - - public sealed class PwProfile : IDeepCloneable - { - private string m_strName = string.Empty; - [DefaultValue("")] - public string Name - { - get { return m_strName; } - set { m_strName = value; } - } - - private PasswordGeneratorType m_type = PasswordGeneratorType.CharSet; - public PasswordGeneratorType GeneratorType - { - get { return m_type; } - set { m_type = value; } - } - - private bool m_bUserEntropy = false; - [DefaultValue(false)] - public bool CollectUserEntropy - { - get { return m_bUserEntropy; } - set { m_bUserEntropy = value; } - } - - private uint m_uLength = 20; - public uint Length - { - get { return m_uLength; } - set { m_uLength = value; } - } - - private PwCharSet m_pwCharSet = new PwCharSet(PwCharSet.UpperCase + - PwCharSet.LowerCase + PwCharSet.Digits); - [XmlIgnore] - public PwCharSet CharSet - { - get { return m_pwCharSet; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_pwCharSet = value; - } - } - - private string m_strCharSetRanges = string.Empty; - [DefaultValue("")] - public string CharSetRanges - { - get { this.UpdateCharSet(true); return m_strCharSetRanges; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strCharSetRanges = value; - this.UpdateCharSet(false); - } - } - - private string m_strCharSetAdditional = string.Empty; - [DefaultValue("")] - public string CharSetAdditional - { - get { this.UpdateCharSet(true); return m_strCharSetAdditional; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strCharSetAdditional = value; - this.UpdateCharSet(false); - } - } - - private string m_strPattern = string.Empty; - [DefaultValue("")] - public string Pattern - { - get { return m_strPattern; } - set { m_strPattern = value; } - } - - private bool m_bPatternPermute = false; - [DefaultValue(false)] - public bool PatternPermutePassword - { - get { return m_bPatternPermute; } - set { m_bPatternPermute = value; } - } - - private bool m_bNoLookAlike = false; - [DefaultValue(false)] - public bool ExcludeLookAlike - { - get { return m_bNoLookAlike; } - set { m_bNoLookAlike = value; } - } - - private bool m_bNoRepeat = false; - [DefaultValue(false)] - public bool NoRepeatingCharacters - { - get { return m_bNoRepeat; } - set { m_bNoRepeat = value; } - } - - private string m_strExclude = string.Empty; - [DefaultValue("")] - public string ExcludeCharacters - { - get { return m_strExclude; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strExclude = value; - } - } - - private string m_strCustomID = string.Empty; - [DefaultValue("")] - public string CustomAlgorithmUuid - { - get { return m_strCustomID; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strCustomID = value; - } - } - - private string m_strCustomOpt = string.Empty; - [DefaultValue("")] - public string CustomAlgorithmOptions - { - get { return m_strCustomOpt; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strCustomOpt = value; - } - } - - public PwProfile() - { - } - - public PwProfile CloneDeep() - { - PwProfile p = new PwProfile(); - - p.m_strName = m_strName; - p.m_type = m_type; - p.m_bUserEntropy = m_bUserEntropy; - p.m_uLength = m_uLength; - p.m_pwCharSet = new PwCharSet(m_pwCharSet.ToString()); - p.m_strCharSetRanges = m_strCharSetRanges; - p.m_strCharSetAdditional = m_strCharSetAdditional; - p.m_strPattern = m_strPattern; - p.m_bPatternPermute = m_bPatternPermute; - p.m_bNoLookAlike = m_bNoLookAlike; - p.m_bNoRepeat = m_bNoRepeat; - p.m_strExclude = m_strExclude; - p.m_strCustomID = m_strCustomID; - p.m_strCustomOpt = m_strCustomOpt; - - return p; - } - - private void UpdateCharSet(bool bSetXml) - { - if(bSetXml) - { - PwCharSet pcs = new PwCharSet(m_pwCharSet.ToString()); - m_strCharSetRanges = pcs.PackAndRemoveCharRanges(); - m_strCharSetAdditional = pcs.ToString(); - } - else - { - PwCharSet pcs = new PwCharSet(m_strCharSetAdditional); - pcs.UnpackCharRanges(m_strCharSetRanges); - m_pwCharSet = pcs; - } - } - - public static PwProfile DeriveFromPassword(ProtectedString psPassword) - { - PwProfile pp = new PwProfile(); - Debug.Assert(psPassword != null); if(psPassword == null) return pp; - - char[] vChars = psPassword.ReadChars(); - - pp.GeneratorType = PasswordGeneratorType.CharSet; - pp.Length = (uint)vChars.Length; - - PwCharSet pcs = pp.CharSet; - pcs.Clear(); - - foreach(char ch in vChars) - { - if((ch >= 'A') && (ch <= 'Z')) pcs.Add(PwCharSet.UpperCase); - else if((ch >= 'a') && (ch <= 'z')) pcs.Add(PwCharSet.LowerCase); - else if((ch >= '0') && (ch <= '9')) pcs.Add(PwCharSet.Digits); - else if(PwCharSet.SpecialChars.IndexOf(ch) >= 0) - pcs.Add(PwCharSet.SpecialChars); - else if(ch == ' ') pcs.Add(' '); - else if(ch == '-') pcs.Add('-'); - else if(ch == '_') pcs.Add('_'); - else if(PwCharSet.Brackets.IndexOf(ch) >= 0) - pcs.Add(PwCharSet.Brackets); - else if(PwCharSet.HighAnsiChars.IndexOf(ch) >= 0) - pcs.Add(PwCharSet.HighAnsiChars); - else pcs.Add(ch); - } - - MemUtil.ZeroArray(vChars); - return pp; - } - - public bool HasSecurityReducingOption() - { - return (m_bNoLookAlike || m_bNoRepeat || (m_strExclude.Length > 0)); - } - } -} diff --git a/ModernKeePassLib/Cryptography/PopularPasswords.cs b/ModernKeePassLib/Cryptography/PopularPasswords.cs deleted file mode 100644 index 905ae7c..0000000 --- a/ModernKeePassLib/Cryptography/PopularPasswords.cs +++ /dev/null @@ -1,140 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography -{ - public static class PopularPasswords - { - private static Dictionary> m_dicts = - new Dictionary>(); - - internal static int MaxLength - { - get - { - Debug.Assert(m_dicts.Count > 0); // Should be initialized - - int iMaxLen = 0; - foreach(int iLen in m_dicts.Keys) - { - if(iLen > iMaxLen) iMaxLen = iLen; - } - - return iMaxLen; - } - } - - internal static bool ContainsLength(int nLength) - { - Dictionary dDummy; - return m_dicts.TryGetValue(nLength, out dDummy); - } - - public static bool IsPopularPassword(char[] vPassword) - { - ulong uDummy; - return IsPopularPassword(vPassword, out uDummy); - } - - public static bool IsPopularPassword(char[] vPassword, out ulong uDictSize) - { - if(vPassword == null) throw new ArgumentNullException("vPassword"); - if(vPassword.Length == 0) { uDictSize = 0; return false; } - -#if DEBUG -#if ModernKeePassLib - foreach (var ch in vPassword) - { - Debug.Assert(ch == char.ToLower(ch)); - } -#else - Array.ForEach(vPassword, ch => Debug.Assert(ch == char.ToLower(ch))); -#endif -#endif - - try { return IsPopularPasswordPriv(vPassword, out uDictSize); } - catch(Exception) { Debug.Assert(false); } - - uDictSize = 0; - return false; - } - - private static bool IsPopularPasswordPriv(char[] vPassword, out ulong uDictSize) - { - Debug.Assert(m_dicts.Count > 0); // Should be initialized with data - - Dictionary d; - if(!m_dicts.TryGetValue(vPassword.Length, out d)) - { - uDictSize = 0; - return false; - } - - uDictSize = (ulong)d.Count; - return d.ContainsKey(vPassword); - } - - public static void Add(byte[] pbData, bool bGZipped) - { - try - { - if(bGZipped) - pbData = MemUtil.Decompress(pbData); - - string strData = StrUtil.Utf8.GetString(pbData, 0, pbData.Length); - if(string.IsNullOrEmpty(strData)) { Debug.Assert(false); return; } - - StringBuilder sb = new StringBuilder(); - for(int i = 0; i <= strData.Length; ++i) - { - char ch = ((i == strData.Length) ? ' ' : strData[i]); - - if(char.IsWhiteSpace(ch)) - { - int cc = sb.Length; - if(cc > 0) - { - char[] vWord = new char[cc]; - sb.CopyTo(0, vWord, 0, cc); - - Dictionary d; - if(!m_dicts.TryGetValue(cc, out d)) - { - d = new Dictionary(MemUtil.ArrayHelperExOfChar); - m_dicts[cc] = d; - } - - d[vWord] = true; - sb.Remove(0, cc); - } - } - else sb.Append(char.ToLower(ch)); - } - } - catch(Exception) { Debug.Assert(false); } - } - } -} diff --git a/ModernKeePassLib/Cryptography/ProtectedData.cs b/ModernKeePassLib/Cryptography/ProtectedData.cs deleted file mode 100644 index c25562d..0000000 --- a/ModernKeePassLib/Cryptography/ProtectedData.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using ModernKeePassLib.Native; - -namespace ModernKeePassLib.Cryptography -{ - public static class ProtectedData - { - public static byte[] Unprotect(byte[] pbEnc, byte[] mPbOptEnt, DataProtectionScope currentUser) - { - throw new NotImplementedException(); - } - - public static byte[] Protect(byte[] pbPlain, byte[] mPbOptEnt, DataProtectionScope currentUser) - { - throw new NotImplementedException(); - } - } -} diff --git a/ModernKeePassLib/Cryptography/QualityEstimation.cs b/ModernKeePassLib/Cryptography/QualityEstimation.cs deleted file mode 100644 index a477a17..0000000 --- a/ModernKeePassLib/Cryptography/QualityEstimation.cs +++ /dev/null @@ -1,779 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Cryptography.PasswordGenerator; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography -{ - /// - /// A class that offers static functions to estimate the quality of - /// passwords. - /// - public static class QualityEstimation - { - private static class PatternID - { - public const char LowerAlpha = 'L'; - public const char UpperAlpha = 'U'; - public const char Digit = 'D'; - public const char Special = 'S'; - public const char High = 'H'; - public const char Other = 'X'; - - public const char Dictionary = 'W'; - public const char Repetition = 'R'; - public const char Number = 'N'; - public const char DiffSeq = 'C'; - - public const string All = "LUDSHXWRNC"; - } - - // private static class CharDistrib - // { - // public static readonly ulong[] LowerAlpha = new ulong[26] { - // 884, 211, 262, 249, 722, 98, 172, 234, 556, 124, 201, 447, 321, - // 483, 518, 167, 18, 458, 416, 344, 231, 105, 80, 48, 238, 76 - // }; - // public static readonly ulong[] UpperAlpha = new ulong[26] { - // 605, 188, 209, 200, 460, 81, 130, 163, 357, 122, 144, 332, 260, - // 317, 330, 132, 18, 320, 315, 250, 137, 76, 60, 36, 161, 54 - // }; - // public static readonly ulong[] Digit = new ulong[10] { - // 574, 673, 524, 377, 339, 336, 312, 310, 357, 386 - // }; - // } - - private sealed class QeCharType - { - private readonly char m_chTypeID; - public char TypeID { get { return m_chTypeID; } } - - private readonly string m_strAlph; - public string Alphabet { get { return m_strAlph; } } - - private readonly int m_nChars; - public int CharCount { get { return m_nChars; } } - - private readonly char m_chFirst; - private readonly char m_chLast; - - private readonly double m_dblCharSize; - public double CharSize { get { return m_dblCharSize; } } - - public QeCharType(char chTypeID, string strAlphabet, bool bIsConsecutive) - { - if(strAlphabet == null) throw new ArgumentNullException(); - if(strAlphabet.Length == 0) throw new ArgumentException(); - - m_chTypeID = chTypeID; - m_strAlph = strAlphabet; - m_nChars = m_strAlph.Length; - m_chFirst = (bIsConsecutive ? m_strAlph[0] : char.MinValue); - m_chLast = (bIsConsecutive ? m_strAlph[m_nChars - 1] : char.MinValue); - - m_dblCharSize = Log2(m_nChars); - - Debug.Assert(((int)(m_chLast - m_chFirst) == (m_nChars - 1)) || - !bIsConsecutive); - } - - public QeCharType(char chTypeID, int nChars) // Catch-none set - { - if(nChars <= 0) throw new ArgumentOutOfRangeException(); - - m_chTypeID = chTypeID; - m_strAlph = string.Empty; - m_nChars = nChars; - m_chFirst = char.MinValue; - m_chLast = char.MinValue; - - m_dblCharSize = Log2(m_nChars); - } - - public bool Contains(char ch) - { - if(m_chLast != char.MinValue) - return ((ch >= m_chFirst) && (ch <= m_chLast)); - - Debug.Assert(m_strAlph.Length > 0); // Don't call for catch-none set - return (m_strAlph.IndexOf(ch) >= 0); - } - } - - private sealed class EntropyEncoder - { - private readonly string m_strAlph; - private Dictionary m_dHisto = new Dictionary(); - private readonly ulong m_uBaseWeight; - private readonly ulong m_uCharWeight; - private readonly ulong m_uOccExclThreshold; - - public EntropyEncoder(string strAlphabet, ulong uBaseWeight, - ulong uCharWeight, ulong uOccExclThreshold) - { - if(strAlphabet == null) throw new ArgumentNullException(); - if(strAlphabet.Length == 0) throw new ArgumentException(); - - m_strAlph = strAlphabet; - m_uBaseWeight = uBaseWeight; - m_uCharWeight = uCharWeight; - m_uOccExclThreshold = uOccExclThreshold; - -#if DEBUG - Dictionary d = new Dictionary(); - foreach(char ch in m_strAlph) { d[ch] = true; } - Debug.Assert(d.Count == m_strAlph.Length); // No duplicates -#endif - } - - public void Reset() - { - m_dHisto.Clear(); - } - - public void Write(char ch) - { - Debug.Assert(m_strAlph.IndexOf(ch) >= 0); - - ulong uOcc; - m_dHisto.TryGetValue(ch, out uOcc); - Debug.Assert(m_dHisto.ContainsKey(ch) || (uOcc == 0)); - m_dHisto[ch] = uOcc + 1; - } - - public double GetOutputSize() - { - ulong uTotalWeight = m_uBaseWeight * (ulong)m_strAlph.Length; - foreach(ulong u in m_dHisto.Values) - { - Debug.Assert(u >= 1); - if(u > m_uOccExclThreshold) - uTotalWeight += (u - m_uOccExclThreshold) * m_uCharWeight; - } - - double dSize = 0.0, dTotalWeight = (double)uTotalWeight; - foreach(ulong u in m_dHisto.Values) - { - ulong uWeight = m_uBaseWeight; - if(u > m_uOccExclThreshold) - uWeight += (u - m_uOccExclThreshold) * m_uCharWeight; - - dSize -= (double)u * Log2((double)uWeight / dTotalWeight); - } - - return dSize; - } - } - - private sealed class MultiEntropyEncoder - { - private Dictionary m_dEncs = - new Dictionary(); - - public MultiEntropyEncoder() - { - } - - public void AddEncoder(char chTypeID, EntropyEncoder ec) - { - if(ec == null) { Debug.Assert(false); return; } - - Debug.Assert(!m_dEncs.ContainsKey(chTypeID)); - m_dEncs[chTypeID] = ec; - } - - public void Reset() - { - foreach(EntropyEncoder ec in m_dEncs.Values) { ec.Reset(); } - } - - public bool Write(char chTypeID, char chData) - { - EntropyEncoder ec; - if(!m_dEncs.TryGetValue(chTypeID, out ec)) - return false; - - ec.Write(chData); - return true; - } - - public double GetOutputSize() - { - double d = 0.0; - - foreach(EntropyEncoder ec in m_dEncs.Values) - { - d += ec.GetOutputSize(); - } - - return d; - } - } - - private sealed class QePatternInstance - { - private readonly int m_iPos; - public int Position { get { return m_iPos; } } - - private readonly int m_nLen; - public int Length { get { return m_nLen; } } - - private readonly char m_chPatternID; - public char PatternID { get { return m_chPatternID; } } - - private readonly double m_dblCost; - public double Cost { get { return m_dblCost; } } - - private readonly QeCharType m_ctSingle; - public QeCharType SingleCharType { get { return m_ctSingle; } } - - public QePatternInstance(int iPosition, int nLength, char chPatternID, - double dblCost) - { - m_iPos = iPosition; - m_nLen = nLength; - m_chPatternID = chPatternID; - m_dblCost = dblCost; - m_ctSingle = null; - } - - public QePatternInstance(int iPosition, int nLength, QeCharType ctSingle) - { - m_iPos = iPosition; - m_nLen = nLength; - m_chPatternID = ctSingle.TypeID; - m_dblCost = ctSingle.CharSize; - m_ctSingle = ctSingle; - } - } - - private sealed class QePathState - { - public readonly int Position; - public readonly List Path; - - public QePathState(int iPosition, List lPath) - { - this.Position = iPosition; - this.Path = lPath; - } - } - - private static readonly object m_objSyncInit = new object(); - private static List m_lCharTypes = null; - - private static void EnsureInitialized() - { - lock(m_objSyncInit) - { - if(m_lCharTypes == null) - { - string strSpecial = PwCharSet.PrintableAsciiSpecial; - if(strSpecial.IndexOf(' ') >= 0) { Debug.Assert(false); } - else strSpecial = strSpecial + " "; - - int nSp = strSpecial.Length; - int nHi = PwCharSet.HighAnsiChars.Length; - - m_lCharTypes = new List(); - - m_lCharTypes.Add(new QeCharType(PatternID.LowerAlpha, - PwCharSet.LowerCase, true)); - m_lCharTypes.Add(new QeCharType(PatternID.UpperAlpha, - PwCharSet.UpperCase, true)); - m_lCharTypes.Add(new QeCharType(PatternID.Digit, - PwCharSet.Digits, true)); - m_lCharTypes.Add(new QeCharType(PatternID.Special, - strSpecial, false)); - m_lCharTypes.Add(new QeCharType(PatternID.High, - PwCharSet.HighAnsiChars, false)); - m_lCharTypes.Add(new QeCharType(PatternID.Other, - 0x10000 - (2 * 26) - 10 - nSp - nHi)); - } - } - } - - /// - /// Estimate the quality of a password. - /// - /// Password to check. - /// Estimated bit-strength of the password. - public static uint EstimatePasswordBits(char[] vPassword) - { - if(vPassword == null) { Debug.Assert(false); return 0; } - if(vPassword.Length == 0) return 0; - - EnsureInitialized(); - - int n = vPassword.Length; - List[] vPatterns = new List[n]; - for(int i = 0; i < n; ++i) - { - vPatterns[i] = new List(); - - QePatternInstance piChar = new QePatternInstance(i, 1, - GetCharType(vPassword[i])); - vPatterns[i].Add(piChar); - } - - FindRepetitions(vPassword, vPatterns); - FindNumbers(vPassword, vPatterns); - FindDiffSeqs(vPassword, vPatterns); - FindPopularPasswords(vPassword, vPatterns); - - // Encoders must not be static, because the entropy estimation - // may run concurrently in multiple threads and the encoders are - // not read-only - EntropyEncoder ecPattern = new EntropyEncoder(PatternID.All, 0, 1, 0); - MultiEntropyEncoder mcData = new MultiEntropyEncoder(); - for(int i = 0; i < (m_lCharTypes.Count - 1); ++i) - { - // Let m be the alphabet size. In order to ensure that two same - // characters cost at least as much as a single character, for - // the probability p and weight w of the character it must hold: - // -log(1/m) >= -2*log(p) - // <=> log(1/m) <= log(p^2) <=> 1/m <= p^2 <=> p >= sqrt(1/m); - // sqrt(1/m) = (1+w)/(m+w) - // <=> m+w = (1+w)*sqrt(m) <=> m+w = sqrt(m) + w*sqrt(m) - // <=> w*(1-sqrt(m)) = sqrt(m) - m <=> w = (sqrt(m)-m)/(1-sqrt(m)) - // <=> w = (sqrt(m)-m)*(1+sqrt(m))/(1-m) - // <=> w = (sqrt(m)-m+m-m*sqrt(m))/(1-m) <=> w = sqrt(m) - ulong uw = (ulong)Math.Sqrt((double)m_lCharTypes[i].CharCount); - - mcData.AddEncoder(m_lCharTypes[i].TypeID, new EntropyEncoder( - m_lCharTypes[i].Alphabet, 1, uw, 1)); - } - - double dblMinCost = (double)int.MaxValue; - int tStart = Environment.TickCount; - - Stack sRec = new Stack(); - sRec.Push(new QePathState(0, new List())); - while(sRec.Count > 0) - { - int tDiff = Environment.TickCount - tStart; - if(tDiff > 500) break; - - QePathState s = sRec.Pop(); - - if(s.Position >= n) - { - Debug.Assert(s.Position == n); - - double dblCost = ComputePathCost(s.Path, vPassword, - ecPattern, mcData); - if(dblCost < dblMinCost) dblMinCost = dblCost; - } - else - { - List lSubs = vPatterns[s.Position]; - for(int i = lSubs.Count - 1; i >= 0; --i) - { - QePatternInstance pi = lSubs[i]; - Debug.Assert(pi.Position == s.Position); - Debug.Assert(pi.Length >= 1); - - List lNewPath = - new List(s.Path.Count + 1); - lNewPath.AddRange(s.Path); - lNewPath.Add(pi); - Debug.Assert(lNewPath.Capacity == (s.Path.Count + 1)); - - QePathState sNew = new QePathState(s.Position + - pi.Length, lNewPath); - sRec.Push(sNew); - } - } - } - - return (uint)Math.Ceiling(dblMinCost); - } - - /// - /// Estimate the quality of a password. - /// - /// Password to check, UTF-8 encoded. - /// Estimated bit-strength of the password. - public static uint EstimatePasswordBits(byte[] pbUnprotectedUtf8) - { - if(pbUnprotectedUtf8 == null) { Debug.Assert(false); return 0; } - - char[] v = StrUtil.Utf8.GetChars(pbUnprotectedUtf8); - uint r; - try { r = EstimatePasswordBits(v); } - finally { MemUtil.ZeroArray(v); } - - return r; - } - - private static QeCharType GetCharType(char ch) - { - int nTypes = m_lCharTypes.Count; - Debug.Assert((nTypes > 0) && (m_lCharTypes[nTypes - 1].CharCount > 256)); - - for(int i = 0; i < (nTypes - 1); ++i) - { - if(m_lCharTypes[i].Contains(ch)) - return m_lCharTypes[i]; - } - - return m_lCharTypes[nTypes - 1]; - } - - private static double ComputePathCost(List l, - char[] vPassword, EntropyEncoder ecPattern, MultiEntropyEncoder mcData) - { - ecPattern.Reset(); - for(int i = 0; i < l.Count; ++i) - ecPattern.Write(l[i].PatternID); - double dblPatternCost = ecPattern.GetOutputSize(); - - mcData.Reset(); - double dblDataCost = 0.0; - foreach(QePatternInstance pi in l) - { - QeCharType tChar = pi.SingleCharType; - if(tChar != null) - { - char ch = vPassword[pi.Position]; - if(!mcData.Write(tChar.TypeID, ch)) - dblDataCost += pi.Cost; - } - else dblDataCost += pi.Cost; - } - dblDataCost += mcData.GetOutputSize(); - - return (dblPatternCost + dblDataCost); - } - - private static void FindPopularPasswords(char[] vPassword, - List[] vPatterns) - { - int n = vPassword.Length; - - char[] vLower = new char[n]; - char[] vLeet = new char[n]; - for(int i = 0; i < n; ++i) - { - char ch = vPassword[i]; - - vLower[i] = char.ToLower(ch); - vLeet[i] = char.ToLower(DecodeLeetChar(ch)); - } - - char chErased = default(char); // The value that Array.Clear uses - Debug.Assert(chErased == char.MinValue); - - int nMaxLen = Math.Min(n, PopularPasswords.MaxLength); - for(int nSubLen = nMaxLen; nSubLen >= 3; --nSubLen) - { - if(!PopularPasswords.ContainsLength(nSubLen)) continue; - - char[] vSub = new char[nSubLen]; - - for(int i = 0; i <= (n - nSubLen); ++i) - { - if(Array.IndexOf(vLower, chErased, i, nSubLen) >= 0) - continue; - - Array.Copy(vLower, i, vSub, 0, nSubLen); - if(!EvalAddPopularPasswordPattern(vPatterns, vPassword, - i, vSub, 0.0)) - { - Array.Copy(vLeet, i, vSub, 0, nSubLen); - if(EvalAddPopularPasswordPattern(vPatterns, vPassword, - i, vSub, 1.5)) - { - Array.Clear(vLower, i, nSubLen); // Not vLeet - Debug.Assert(vLower[i] == chErased); - } - } - else - { - Array.Clear(vLower, i, nSubLen); - Debug.Assert(vLower[i] == chErased); - } - } - - MemUtil.ZeroArray(vSub); - } - - MemUtil.ZeroArray(vLower); - MemUtil.ZeroArray(vLeet); - } - - private static bool EvalAddPopularPasswordPattern(List[] vPatterns, - char[] vPassword, int i, char[] vSub, double dblCostPerMod) - { - ulong uDictSize; - if(!PopularPasswords.IsPopularPassword(vSub, out uDictSize)) - return false; - - int n = vSub.Length; - int d = HammingDist(vSub, 0, vPassword, i, n); - - double dblCost = Log2((double)uDictSize); - - // dblCost += log2(n binom d) - int k = Math.Min(d, n - d); - for(int j = n; j > (n - k); --j) - dblCost += Log2(j); - for(int j = k; j >= 2; --j) - dblCost -= Log2(j); - - dblCost += dblCostPerMod * (double)d; - - vPatterns[i].Add(new QePatternInstance(i, n, PatternID.Dictionary, - dblCost)); - return true; - } - - private static char DecodeLeetChar(char chLeet) - { - if((chLeet >= '\u00C0') && (chLeet <= '\u00C6')) return 'a'; - if((chLeet >= '\u00C8') && (chLeet <= '\u00CB')) return 'e'; - if((chLeet >= '\u00CC') && (chLeet <= '\u00CF')) return 'i'; - if((chLeet >= '\u00D2') && (chLeet <= '\u00D6')) return 'o'; - if((chLeet >= '\u00D9') && (chLeet <= '\u00DC')) return 'u'; - if((chLeet >= '\u00E0') && (chLeet <= '\u00E6')) return 'a'; - if((chLeet >= '\u00E8') && (chLeet <= '\u00EB')) return 'e'; - if((chLeet >= '\u00EC') && (chLeet <= '\u00EF')) return 'i'; - if((chLeet >= '\u00F2') && (chLeet <= '\u00F6')) return 'o'; - if((chLeet >= '\u00F9') && (chLeet <= '\u00FC')) return 'u'; - - char ch; - switch(chLeet) - { - case '4': - case '@': - case '?': - case '^': - case '\u00AA': ch = 'a'; break; - case '8': - case '\u00DF': ch = 'b'; break; - case '(': - case '{': - case '[': - case '<': - case '\u00A2': - case '\u00A9': - case '\u00C7': - case '\u00E7': ch = 'c'; break; - case '\u00D0': - case '\u00F0': ch = 'd'; break; - case '3': - case '\u20AC': - case '&': - case '\u00A3': ch = 'e'; break; - case '6': - case '9': ch = 'g'; break; - case '#': ch = 'h'; break; - case '1': - case '!': - case '|': - case '\u00A1': - case '\u00A6': ch = 'i'; break; - case '\u00D1': - case '\u00F1': ch = 'n'; break; - case '0': - case '*': - case '\u00A4': // Currency - case '\u00B0': // Degree - case '\u00D8': - case '\u00F8': ch = 'o'; break; - case '\u00AE': ch = 'r'; break; - case '$': - case '5': - case '\u00A7': ch = 's'; break; - case '+': - case '7': ch = 't'; break; - case '\u00B5': ch = 'u'; break; - case '%': - case '\u00D7': ch = 'x'; break; - case '\u00A5': - case '\u00DD': - case '\u00FD': - case '\u00FF': ch = 'y'; break; - case '2': ch = 'z'; break; - default: ch = chLeet; break; - } - - return ch; - } - - private static int HammingDist(char[] v1, int iOffset1, - char[] v2, int iOffset2, int nLength) - { - int nDist = 0; - for(int i = 0; i < nLength; ++i) - { - if(v1[iOffset1 + i] != v2[iOffset2 + i]) ++nDist; - } - - return nDist; - } - - private static void FindRepetitions(char[] vPassword, - List[] vPatterns) - { - int n = vPassword.Length; - char[] v = new char[n]; - Array.Copy(vPassword, v, n); - - char chErased = char.MaxValue; - for(int m = (n / 2); m >= 3; --m) - { - for(int x1 = 0; x1 <= (n - (2 * m)); ++x1) - { - bool bFoundRep = false; - - for(int x2 = (x1 + m); x2 <= (n - m); ++x2) - { - if(PartsEqual(v, x1, x2, m)) - { - double dblCost = Log2(x1 + 1) + Log2(m); - vPatterns[x2].Add(new QePatternInstance(x2, m, - PatternID.Repetition, dblCost)); - - ErasePart(v, x2, m, ref chErased); - bFoundRep = true; - } - } - - if(bFoundRep) ErasePart(v, x1, m, ref chErased); - } - } - - MemUtil.ZeroArray(v); - } - - private static bool PartsEqual(char[] v, int x1, int x2, int nLength) - { - for(int i = 0; i < nLength; ++i) - { - if(v[x1 + i] != v[x2 + i]) return false; - } - - return true; - } - - private static void ErasePart(char[] v, int i, int n, ref char chErased) - { - for(int j = 0; j < n; ++j) - { - v[i + j] = chErased; - --chErased; - } - } - - private static void FindNumbers(char[] vPassword, - List[] vPatterns) - { - int n = vPassword.Length; - StringBuilder sb = new StringBuilder(); - - for(int i = 0; i < n; ++i) - { - char ch = vPassword[i]; - if((ch >= '0') && (ch <= '9')) sb.Append(ch); - else - { - AddNumberPattern(vPatterns, sb, i - sb.Length); - sb.Remove(0, sb.Length); - } - } - AddNumberPattern(vPatterns, sb, n - sb.Length); - } - - private static void AddNumberPattern(List[] vPatterns, - StringBuilder sb, int i) - { - if(sb.Length <= 2) return; - string strNumber = sb.ToString(); - - int nZeros = 0; - for(int j = 0; j < strNumber.Length; ++j) - { - if(strNumber[j] != '0') break; - ++nZeros; - } - - double dblCost = Log2(nZeros + 1); - if(nZeros < strNumber.Length) - { - string strNonZero = strNumber.Substring(nZeros); - -#if KeePassLibSD - try { dblCost += Log2(double.Parse(strNonZero)); } - catch(Exception) { Debug.Assert(false); return; } -#else - double d; - if(double.TryParse(strNonZero, out d)) - dblCost += Log2(d); - else { Debug.Assert(false); return; } -#endif - } - - vPatterns[i].Add(new QePatternInstance(i, strNumber.Length, - PatternID.Number, dblCost)); - } - - private static void FindDiffSeqs(char[] vPassword, - List[] vPatterns) - { - int n = vPassword.Length; - int d = int.MaxValue, p = 0; - - for(int i = 1; i <= n; ++i) - { - int dCur = ((i == n) ? int.MinValue : - ((int)vPassword[i] - (int)vPassword[i - 1])); - if(dCur != d) - { - if((i - p) >= 3) // At least 3 chars involved - { - QeCharType ct = GetCharType(vPassword[p]); - double dblCost = ct.CharSize + Log2(i - p - 1); - - vPatterns[p].Add(new QePatternInstance(p, - i - p, PatternID.DiffSeq, dblCost)); - } - - d = dCur; - p = i - 1; - } - } - } - - private static double Log2(double dblValue) - { -#if KeePassLibSD - return (Math.Log(dblValue) / Math.Log(2.0)); -#else - return Math.Log(dblValue, 2.0); -#endif - } - } -} diff --git a/ModernKeePassLib/Cryptography/SelfTest.cs b/ModernKeePassLib/Cryptography/SelfTest.cs deleted file mode 100644 index d8ecc26..0000000 --- a/ModernKeePassLib/Cryptography/SelfTest.cs +++ /dev/null @@ -1,1141 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; - -#if ModernKeePassLib || KeePassUAP -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Parameters; -#else -using System.Security.Cryptography; -#endif - -using ModernKeePassLib.Cryptography.Cipher; -using ModernKeePassLib.Cryptography.Hash; -using ModernKeePassLib.Cryptography.KeyDerivation; -using ModernKeePassLib.Keys; -using ModernKeePassLib.Native; -using ModernKeePassLib.Resources; -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Cryptography -{ - /// - /// Class containing self-test methods. - /// - // TODO: move all this into the Unit Tests project - public static class SelfTest - { - /// - /// Perform a self-test. - /// - public static void Perform() - { -#if KeePassUAP - Debug.Assert(Marshal.SizeOf() == 4); - Debug.Assert(Marshal.SizeOf() == 4); - Debug.Assert(Marshal.SizeOf() == 8); - Debug.Assert(Marshal.SizeOf() == 8); - Debug.Assert(Marshal.SizeOf() == IntPtr.Size); -#else - Debug.Assert(Marshal.SizeOf(typeof(int)) == 4); - Debug.Assert(Marshal.SizeOf(typeof(uint)) == 4); - Debug.Assert(Marshal.SizeOf(typeof(long)) == 8); - Debug.Assert(Marshal.SizeOf(typeof(ulong)) == 8); - Debug.Assert(Marshal.SizeOf(typeof(IntPtr)) == IntPtr.Size); -#endif - Debug.Assert((IntPtr.Size == 4) || (IntPtr.Size == 8)); - - Debug.Assert((int)PwIcon.World == 1); - Debug.Assert((int)PwIcon.Warning == 2); - Debug.Assert((int)PwIcon.BlackBerry == 68); - - Random r = CryptoRandom.NewWeakRandom(); - - TestFipsComplianceProblems(); // Must be the first test - - TestAes(); - TestSalsa20(r); - TestChaCha20(r); - TestBlake2b(r); - TestArgon2(); - TestHmac(); - - TestKeyTransform(r); - TestNativeKeyTransform(r); - - TestHmacOtp(); - - TestProtectedObjects(r); - TestMemUtil(r); - TestStrUtil(); - TestUrlUtil(); - -#if KeePassUAP - SelfTestEx.Perform(); -#endif - } - - internal static void TestFipsComplianceProblems() - { -#if !ModernKeePassLib - try { using(RijndaelManaged r = new RijndaelManaged()) { } } - catch(Exception exAes) - { - throw new SecurityException("AES/Rijndael: " + exAes.Message); - } -#endif - - try { using(SHA256Managed h = new SHA256Managed()) { } } - catch(Exception exSha256) - { - throw new SecurityException("SHA-256: " + exSha256.Message); - } - } - - private static void TestAes() - { - // Test vector (official ECB test vector #356) - byte[] pbIV = new byte[16]; - byte[] pbTestKey = new byte[32]; - byte[] pbTestData = new byte[16]; - byte[] pbReferenceCT = new byte[16] { - 0x75, 0xD1, 0x1B, 0x0E, 0x3A, 0x68, 0xC4, 0x22, - 0x3D, 0x88, 0xDB, 0xF0, 0x17, 0x97, 0x7D, 0xD7 }; - int i; - - for(i = 0; i < 16; ++i) pbIV[i] = 0; - for(i = 0; i < 32; ++i) pbTestKey[i] = 0; - for(i = 0; i < 16; ++i) pbTestData[i] = 0; - pbTestData[0] = 0x04; - -#if ModernKeePassLib || KeePassUAP - AesEngine r = new AesEngine(); - r.Init(true, new KeyParameter(pbTestKey)); - if(r.GetBlockSize() != pbTestData.Length) - throw new SecurityException("AES (BC)"); - r.ProcessBlock(pbTestData, 0, pbTestData, 0); -#else - SymmetricAlgorithm a = CryptoUtil.CreateAes(); - if(a.BlockSize != 128) // AES block size - { - Debug.Assert(false); - a.BlockSize = 128; - } - - a.IV = pbIV; - a.KeySize = 256; - a.Key = pbTestKey; - a.Mode = CipherMode.ECB; - ICryptoTransform iCrypt = a.CreateEncryptor(); - - iCrypt.TransformBlock(pbTestData, 0, 16, pbTestData, 0); -#endif - - if(!MemUtil.ArraysEqual(pbTestData, pbReferenceCT)) - throw new SecurityException("AES"); - } - - private static void TestSalsa20(Random r) - { -#if DEBUG - // Test values from official set 6, vector 3 - byte[] pbKey = new byte[32] { - 0x0F, 0x62, 0xB5, 0x08, 0x5B, 0xAE, 0x01, 0x54, - 0xA7, 0xFA, 0x4D, 0xA0, 0xF3, 0x46, 0x99, 0xEC, - 0x3F, 0x92, 0xE5, 0x38, 0x8B, 0xDE, 0x31, 0x84, - 0xD7, 0x2A, 0x7D, 0xD0, 0x23, 0x76, 0xC9, 0x1C - }; - byte[] pbIV = new byte[8] { 0x28, 0x8F, 0xF6, 0x5D, - 0xC4, 0x2B, 0x92, 0xF9 }; - byte[] pbExpected = new byte[16] { - 0x5E, 0x5E, 0x71, 0xF9, 0x01, 0x99, 0x34, 0x03, - 0x04, 0xAB, 0xB2, 0x2A, 0x37, 0xB6, 0x62, 0x5B - }; - - byte[] pb = new byte[16]; - Salsa20Cipher c = new Salsa20Cipher(pbKey, pbIV); - c.Encrypt(pb, 0, pb.Length); - if(!MemUtil.ArraysEqual(pb, pbExpected)) - throw new SecurityException("Salsa20-1"); - - // Extended test - byte[] pbExpected2 = new byte[16] { - 0xAB, 0xF3, 0x9A, 0x21, 0x0E, 0xEE, 0x89, 0x59, - 0x8B, 0x71, 0x33, 0x37, 0x70, 0x56, 0xC2, 0xFE - }; - byte[] pbExpected3 = new byte[16] { - 0x1B, 0xA8, 0x9D, 0xBD, 0x3F, 0x98, 0x83, 0x97, - 0x28, 0xF5, 0x67, 0x91, 0xD5, 0xB7, 0xCE, 0x23 - }; - - int nPos = Salsa20ToPos(c, r, pb.Length, 65536); - Array.Clear(pb, 0, pb.Length); - c.Encrypt(pb, 0, pb.Length); - if(!MemUtil.ArraysEqual(pb, pbExpected2)) - throw new SecurityException("Salsa20-2"); - - nPos = Salsa20ToPos(c, r, nPos + pb.Length, 131008); - Array.Clear(pb, 0, pb.Length); - c.Encrypt(pb, 0, pb.Length); - if(!MemUtil.ArraysEqual(pb, pbExpected3)) - throw new SecurityException("Salsa20-3"); - - Dictionary d = new Dictionary(); - const int nRounds = 100; - for(int i = 0; i < nRounds; ++i) - { - byte[] z = new byte[32]; - c = new Salsa20Cipher(z, MemUtil.Int64ToBytes(i)); - c.Encrypt(z, 0, z.Length); - d[MemUtil.ByteArrayToHexString(z)] = true; - } - if(d.Count != nRounds) throw new SecurityException("Salsa20-4"); -#endif - } - -#if DEBUG - private static int Salsa20ToPos(Salsa20Cipher c, Random r, int nPos, - int nTargetPos) - { - byte[] pb = new byte[512]; - - while(nPos < nTargetPos) - { - int x = r.Next(1, 513); - int nGen = Math.Min(nTargetPos - nPos, x); - c.Encrypt(pb, 0, nGen); - nPos += nGen; - } - - return nTargetPos; - } -#endif - - private static void TestChaCha20(Random r) - { - // ====================================================== - // Test vector from RFC 7539, section 2.3.2 - - byte[] pbKey = new byte[32]; - for(int i = 0; i < 32; ++i) pbKey[i] = (byte)i; - - byte[] pbIV = new byte[12]; - pbIV[3] = 0x09; - pbIV[7] = 0x4A; - - byte[] pbExpc = new byte[64] { - 0x10, 0xF1, 0xE7, 0xE4, 0xD1, 0x3B, 0x59, 0x15, - 0x50, 0x0F, 0xDD, 0x1F, 0xA3, 0x20, 0x71, 0xC4, - 0xC7, 0xD1, 0xF4, 0xC7, 0x33, 0xC0, 0x68, 0x03, - 0x04, 0x22, 0xAA, 0x9A, 0xC3, 0xD4, 0x6C, 0x4E, - 0xD2, 0x82, 0x64, 0x46, 0x07, 0x9F, 0xAA, 0x09, - 0x14, 0xC2, 0xD7, 0x05, 0xD9, 0x8B, 0x02, 0xA2, - 0xB5, 0x12, 0x9C, 0xD1, 0xDE, 0x16, 0x4E, 0xB9, - 0xCB, 0xD0, 0x83, 0xE8, 0xA2, 0x50, 0x3C, 0x4E - }; - - byte[] pb = new byte[64]; - - using(ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV)) - { - c.Seek(64, SeekOrigin.Begin); // Skip first block - c.Encrypt(pb, 0, pb.Length); - - if(!MemUtil.ArraysEqual(pb, pbExpc)) - throw new SecurityException("ChaCha20-1"); - } - -#if DEBUG - // ====================================================== - // Test vector from RFC 7539, section 2.4.2 - - pbIV[3] = 0; - - pb = StrUtil.Utf8.GetBytes("Ladies and Gentlemen of the clas" + - @"s of '99: If I could offer you only one tip for " + - @"the future, sunscreen would be it."); - - pbExpc = new byte[] { - 0x6E, 0x2E, 0x35, 0x9A, 0x25, 0x68, 0xF9, 0x80, - 0x41, 0xBA, 0x07, 0x28, 0xDD, 0x0D, 0x69, 0x81, - 0xE9, 0x7E, 0x7A, 0xEC, 0x1D, 0x43, 0x60, 0xC2, - 0x0A, 0x27, 0xAF, 0xCC, 0xFD, 0x9F, 0xAE, 0x0B, - 0xF9, 0x1B, 0x65, 0xC5, 0x52, 0x47, 0x33, 0xAB, - 0x8F, 0x59, 0x3D, 0xAB, 0xCD, 0x62, 0xB3, 0x57, - 0x16, 0x39, 0xD6, 0x24, 0xE6, 0x51, 0x52, 0xAB, - 0x8F, 0x53, 0x0C, 0x35, 0x9F, 0x08, 0x61, 0xD8, - 0x07, 0xCA, 0x0D, 0xBF, 0x50, 0x0D, 0x6A, 0x61, - 0x56, 0xA3, 0x8E, 0x08, 0x8A, 0x22, 0xB6, 0x5E, - 0x52, 0xBC, 0x51, 0x4D, 0x16, 0xCC, 0xF8, 0x06, - 0x81, 0x8C, 0xE9, 0x1A, 0xB7, 0x79, 0x37, 0x36, - 0x5A, 0xF9, 0x0B, 0xBF, 0x74, 0xA3, 0x5B, 0xE6, - 0xB4, 0x0B, 0x8E, 0xED, 0xF2, 0x78, 0x5E, 0x42, - 0x87, 0x4D - }; - - byte[] pb64 = new byte[64]; - - using(ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV)) - { - c.Encrypt(pb64, 0, pb64.Length); // Skip first block - c.Encrypt(pb, 0, pb.Length); - - if(!MemUtil.ArraysEqual(pb, pbExpc)) - throw new SecurityException("ChaCha20-2"); - } - - // ====================================================== - // Test vector from RFC 7539, appendix A.2 #2 - - Array.Clear(pbKey, 0, pbKey.Length); - pbKey[31] = 1; - - Array.Clear(pbIV, 0, pbIV.Length); - pbIV[11] = 2; - - pb = StrUtil.Utf8.GetBytes("Any submission to the IETF inten" + - "ded by the Contributor for publication as all or" + - " part of an IETF Internet-Draft or RFC and any s" + - "tatement made within the context of an IETF acti" + - "vity is considered an \"IETF Contribution\". Such " + - "statements include oral statements in IETF sessi" + - "ons, as well as written and electronic communica" + - "tions made at any time or place, which are addressed to"); - - pbExpc = MemUtil.HexStringToByteArray( - "A3FBF07DF3FA2FDE4F376CA23E82737041605D9F4F4F57BD8CFF2C1D4B7955EC" + - "2A97948BD3722915C8F3D337F7D370050E9E96D647B7C39F56E031CA5EB6250D" + - "4042E02785ECECFA4B4BB5E8EAD0440E20B6E8DB09D881A7C6132F420E527950" + - "42BDFA7773D8A9051447B3291CE1411C680465552AA6C405B7764D5E87BEA85A" + - "D00F8449ED8F72D0D662AB052691CA66424BC86D2DF80EA41F43ABF937D3259D" + - "C4B2D0DFB48A6C9139DDD7F76966E928E635553BA76C5C879D7B35D49EB2E62B" + - "0871CDAC638939E25E8A1E0EF9D5280FA8CA328B351C3C765989CBCF3DAA8B6C" + - "CC3AAF9F3979C92B3720FC88DC95ED84A1BE059C6499B9FDA236E7E818B04B0B" + - "C39C1E876B193BFE5569753F88128CC08AAA9B63D1A16F80EF2554D7189C411F" + - "5869CA52C5B83FA36FF216B9C1D30062BEBCFD2DC5BCE0911934FDA79A86F6E6" + - "98CED759C3FF9B6477338F3DA4F9CD8514EA9982CCAFB341B2384DD902F3D1AB" + - "7AC61DD29C6F21BA5B862F3730E37CFDC4FD806C22F221"); - - using(MemoryStream msEnc = new MemoryStream()) - { - using(ChaCha20Stream c = new ChaCha20Stream(msEnc, true, pbKey, pbIV)) - { - r.NextBytes(pb64); - c.Write(pb64, 0, pb64.Length); // Skip first block - - int p = 0; - while(p < pb.Length) - { - int cb = r.Next(1, pb.Length - p + 1); - c.Write(pb, p, cb); - p += cb; - } - Debug.Assert(p == pb.Length); - } - - byte[] pbEnc0 = msEnc.ToArray(); - byte[] pbEnc = MemUtil.Mid(pbEnc0, 64, pbEnc0.Length - 64); - if(!MemUtil.ArraysEqual(pbEnc, pbExpc)) - throw new SecurityException("ChaCha20-3"); - - using(MemoryStream msCT = new MemoryStream(pbEnc0, false)) - { - using(ChaCha20Stream cDec = new ChaCha20Stream(msCT, false, - pbKey, pbIV)) - { - byte[] pbPT = MemUtil.Read(cDec, pbEnc0.Length); - if(cDec.ReadByte() >= 0) - throw new SecurityException("ChaCha20-4"); - if(!MemUtil.ArraysEqual(MemUtil.Mid(pbPT, 0, 64), pb64)) - throw new SecurityException("ChaCha20-5"); - if(!MemUtil.ArraysEqual(MemUtil.Mid(pbPT, 64, pbEnc.Length), pb)) - throw new SecurityException("ChaCha20-6"); - } - } - } - - // ====================================================== - // Test vector TC8 from RFC draft by J. Strombergson: - // https://tools.ietf.org/html/draft-strombergson-chacha-test-vectors-01 - - pbKey = new byte[32] { - 0xC4, 0x6E, 0xC1, 0xB1, 0x8C, 0xE8, 0xA8, 0x78, - 0x72, 0x5A, 0x37, 0xE7, 0x80, 0xDF, 0xB7, 0x35, - 0x1F, 0x68, 0xED, 0x2E, 0x19, 0x4C, 0x79, 0xFB, - 0xC6, 0xAE, 0xBE, 0xE1, 0xA6, 0x67, 0x97, 0x5D - }; - - // The first 4 bytes are set to zero and a large counter - // is used; this makes the RFC 7539 version of ChaCha20 - // compatible with the original specification by - // D. J. Bernstein. - pbIV = new byte[12] { 0x00, 0x00, 0x00, 0x00, - 0x1A, 0xDA, 0x31, 0xD5, 0xCF, 0x68, 0x82, 0x21 - }; - - pb = new byte[128]; - - pbExpc = new byte[128] { - 0xF6, 0x3A, 0x89, 0xB7, 0x5C, 0x22, 0x71, 0xF9, - 0x36, 0x88, 0x16, 0x54, 0x2B, 0xA5, 0x2F, 0x06, - 0xED, 0x49, 0x24, 0x17, 0x92, 0x30, 0x2B, 0x00, - 0xB5, 0xE8, 0xF8, 0x0A, 0xE9, 0xA4, 0x73, 0xAF, - 0xC2, 0x5B, 0x21, 0x8F, 0x51, 0x9A, 0xF0, 0xFD, - 0xD4, 0x06, 0x36, 0x2E, 0x8D, 0x69, 0xDE, 0x7F, - 0x54, 0xC6, 0x04, 0xA6, 0xE0, 0x0F, 0x35, 0x3F, - 0x11, 0x0F, 0x77, 0x1B, 0xDC, 0xA8, 0xAB, 0x92, - - 0xE5, 0xFB, 0xC3, 0x4E, 0x60, 0xA1, 0xD9, 0xA9, - 0xDB, 0x17, 0x34, 0x5B, 0x0A, 0x40, 0x27, 0x36, - 0x85, 0x3B, 0xF9, 0x10, 0xB0, 0x60, 0xBD, 0xF1, - 0xF8, 0x97, 0xB6, 0x29, 0x0F, 0x01, 0xD1, 0x38, - 0xAE, 0x2C, 0x4C, 0x90, 0x22, 0x5B, 0xA9, 0xEA, - 0x14, 0xD5, 0x18, 0xF5, 0x59, 0x29, 0xDE, 0xA0, - 0x98, 0xCA, 0x7A, 0x6C, 0xCF, 0xE6, 0x12, 0x27, - 0x05, 0x3C, 0x84, 0xE4, 0x9A, 0x4A, 0x33, 0x32 - }; - - using(ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV, true)) - { - c.Decrypt(pb, 0, pb.Length); - - if(!MemUtil.ArraysEqual(pb, pbExpc)) - throw new SecurityException("ChaCha20-7"); - } -#endif - } - - private static void TestBlake2b(Random r) - { -#if DEBUG - Blake2b h = new Blake2b(); - - // ====================================================== - // From https://tools.ietf.org/html/rfc7693 - - byte[] pbData = StrUtil.Utf8.GetBytes("abc"); - byte[] pbExpc = new byte[64] { - 0xBA, 0x80, 0xA5, 0x3F, 0x98, 0x1C, 0x4D, 0x0D, - 0x6A, 0x27, 0x97, 0xB6, 0x9F, 0x12, 0xF6, 0xE9, - 0x4C, 0x21, 0x2F, 0x14, 0x68, 0x5A, 0xC4, 0xB7, - 0x4B, 0x12, 0xBB, 0x6F, 0xDB, 0xFF, 0xA2, 0xD1, - 0x7D, 0x87, 0xC5, 0x39, 0x2A, 0xAB, 0x79, 0x2D, - 0xC2, 0x52, 0xD5, 0xDE, 0x45, 0x33, 0xCC, 0x95, - 0x18, 0xD3, 0x8A, 0xA8, 0xDB, 0xF1, 0x92, 0x5A, - 0xB9, 0x23, 0x86, 0xED, 0xD4, 0x00, 0x99, 0x23 - }; - - byte[] pbC = h.ComputeHash(pbData); - if(!MemUtil.ArraysEqual(pbC, pbExpc)) - throw new SecurityException("Blake2b-1"); - - // ====================================================== - // Computed using the official b2sum tool - - pbExpc = new byte[64] { - 0x78, 0x6A, 0x02, 0xF7, 0x42, 0x01, 0x59, 0x03, - 0xC6, 0xC6, 0xFD, 0x85, 0x25, 0x52, 0xD2, 0x72, - 0x91, 0x2F, 0x47, 0x40, 0xE1, 0x58, 0x47, 0x61, - 0x8A, 0x86, 0xE2, 0x17, 0xF7, 0x1F, 0x54, 0x19, - 0xD2, 0x5E, 0x10, 0x31, 0xAF, 0xEE, 0x58, 0x53, - 0x13, 0x89, 0x64, 0x44, 0x93, 0x4E, 0xB0, 0x4B, - 0x90, 0x3A, 0x68, 0x5B, 0x14, 0x48, 0xB7, 0x55, - 0xD5, 0x6F, 0x70, 0x1A, 0xFE, 0x9B, 0xE2, 0xCE - }; - - pbC = h.ComputeHash(MemUtil.EmptyByteArray); - if(!MemUtil.ArraysEqual(pbC, pbExpc)) - throw new SecurityException("Blake2b-2"); - - // ====================================================== - // Computed using the official b2sum tool - - string strS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:,;_-\r\n"; - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < 1000; ++i) sb.Append(strS); - pbData = StrUtil.Utf8.GetBytes(sb.ToString()); - - pbExpc = new byte[64] { - 0x59, 0x69, 0x8D, 0x3B, 0x83, 0xF4, 0x02, 0x4E, - 0xD8, 0x99, 0x26, 0x0E, 0xF4, 0xE5, 0x9F, 0x20, - 0xDC, 0x31, 0xEE, 0x5B, 0x45, 0xEA, 0xBB, 0xFC, - 0x1C, 0x0A, 0x8E, 0xED, 0xAA, 0x7A, 0xFF, 0x50, - 0x82, 0xA5, 0x8F, 0xBC, 0x4A, 0x46, 0xFC, 0xC5, - 0xEF, 0x44, 0x4E, 0x89, 0x80, 0x7D, 0x3F, 0x1C, - 0xC1, 0x94, 0x45, 0xBB, 0xC0, 0x2C, 0x95, 0xAA, - 0x3F, 0x08, 0x8A, 0x93, 0xF8, 0x75, 0x91, 0xB0 - }; - - int p = 0; - while(p < pbData.Length) - { - int cb = r.Next(1, pbData.Length - p + 1); - h.TransformBlock(pbData, p, cb, pbData, p); - p += cb; - } - Debug.Assert(p == pbData.Length); - - h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); - - if(!MemUtil.ArraysEqual(h.Hash, pbExpc)) - throw new SecurityException("Blake2b-3"); - - h.Clear(); -#endif - } - - private static void TestArgon2() - { -#if DEBUG - Argon2Kdf kdf = new Argon2Kdf(); - - // ====================================================== - // From the official Argon2 1.3 reference code package - // (test vector for Argon2d 1.3); also on - // https://tools.ietf.org/html/draft-irtf-cfrg-argon2-00 - - var p = kdf.GetDefaultParameters(); - kdf.Randomize(p); - - Debug.Assert(p.GetUInt32(Argon2Kdf.ParamVersion, 0) == 0x13U); - - byte[] pbMsg = new byte[32]; - for(int i = 0; i < pbMsg.Length; ++i) pbMsg[i] = 1; - - p.SetUInt64(Argon2Kdf.ParamMemory, 32 * 1024); - p.SetUInt64(Argon2Kdf.ParamIterations, 3); - p.SetUInt32(Argon2Kdf.ParamParallelism, 4); - - byte[] pbSalt = new byte[16]; - for(int i = 0; i < pbSalt.Length; ++i) pbSalt[i] = 2; - p.SetByteArray(Argon2Kdf.ParamSalt, pbSalt); - - byte[] pbKey = new byte[8]; - for(int i = 0; i < pbKey.Length; ++i) pbKey[i] = 3; - p.SetByteArray(Argon2Kdf.ParamSecretKey, pbKey); - - byte[] pbAssoc = new byte[12]; - for(int i = 0; i < pbAssoc.Length; ++i) pbAssoc[i] = 4; - p.SetByteArray(Argon2Kdf.ParamAssocData, pbAssoc); - - byte[] pbExpc = new byte[32] { - 0x51, 0x2B, 0x39, 0x1B, 0x6F, 0x11, 0x62, 0x97, - 0x53, 0x71, 0xD3, 0x09, 0x19, 0x73, 0x42, 0x94, - 0xF8, 0x68, 0xE3, 0xBE, 0x39, 0x84, 0xF3, 0xC1, - 0xA1, 0x3A, 0x4D, 0xB9, 0xFA, 0xBE, 0x4A, 0xCB - }; - - byte[] pb = kdf.Transform(pbMsg, p); - - if(!MemUtil.ArraysEqual(pb, pbExpc)) - throw new SecurityException("Argon2-1"); - - // ====================================================== - // From the official Argon2 1.3 reference code package - // (test vector for Argon2d 1.0) - - p.SetUInt32(Argon2Kdf.ParamVersion, 0x10); - - pbExpc = new byte[32] { - 0x96, 0xA9, 0xD4, 0xE5, 0xA1, 0x73, 0x40, 0x92, - 0xC8, 0x5E, 0x29, 0xF4, 0x10, 0xA4, 0x59, 0x14, - 0xA5, 0xDD, 0x1F, 0x5C, 0xBF, 0x08, 0xB2, 0x67, - 0x0D, 0xA6, 0x8A, 0x02, 0x85, 0xAB, 0xF3, 0x2B - }; - - pb = kdf.Transform(pbMsg, p); - - if(!MemUtil.ArraysEqual(pb, pbExpc)) - throw new SecurityException("Argon2-2"); - - // ====================================================== - // From the official 'phc-winner-argon2-20151206.zip' - // (test vector for Argon2d 1.0) - - p.SetUInt64(Argon2Kdf.ParamMemory, 16 * 1024); - - pbExpc = new byte[32] { - 0x57, 0xB0, 0x61, 0x3B, 0xFD, 0xD4, 0x13, 0x1A, - 0x0C, 0x34, 0x88, 0x34, 0xC6, 0x72, 0x9C, 0x2C, - 0x72, 0x29, 0x92, 0x1E, 0x6B, 0xBA, 0x37, 0x66, - 0x5D, 0x97, 0x8C, 0x4F, 0xE7, 0x17, 0x5E, 0xD2 - }; - - pb = kdf.Transform(pbMsg, p); - - if(!MemUtil.ArraysEqual(pb, pbExpc)) - throw new SecurityException("Argon2-3"); - -#if SELFTEST_ARGON2_LONG - // ====================================================== - // Computed using the official 'argon2' application - // (test vectors for Argon2d 1.3) - - p = kdf.GetDefaultParameters(); - - pbMsg = StrUtil.Utf8.GetBytes("ABC1234"); - - p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 11) * 1024); // 2 MB - p.SetUInt64(Argon2Kdf.ParamIterations, 2); - p.SetUInt32(Argon2Kdf.ParamParallelism, 2); - - pbSalt = StrUtil.Utf8.GetBytes("somesalt"); - p.SetByteArray(Argon2Kdf.ParamSalt, pbSalt); - - pbExpc = new byte[32] { - 0x29, 0xCB, 0xD3, 0xA1, 0x93, 0x76, 0xF7, 0xA2, - 0xFC, 0xDF, 0xB0, 0x68, 0xAC, 0x0B, 0x99, 0xBA, - 0x40, 0xAC, 0x09, 0x01, 0x73, 0x42, 0xCE, 0xF1, - 0x29, 0xCC, 0xA1, 0x4F, 0xE1, 0xC1, 0xB7, 0xA3 - }; - - pb = kdf.Transform(pbMsg, p); - - if(!MemUtil.ArraysEqual(pb, pbExpc)) - throw new SecurityException("Argon2-4"); - - p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 10) * 1024); // 1 MB - p.SetUInt64(Argon2Kdf.ParamIterations, 3); - - pbExpc = new byte[32] { - 0x7A, 0xBE, 0x1C, 0x1C, 0x8D, 0x7F, 0xD6, 0xDC, - 0x7C, 0x94, 0x06, 0x3E, 0xD8, 0xBC, 0xD8, 0x1C, - 0x2F, 0x87, 0x84, 0x99, 0x12, 0x83, 0xFE, 0x76, - 0x00, 0x64, 0xC4, 0x58, 0xA4, 0xDA, 0x35, 0x70 - }; - - pb = kdf.Transform(pbMsg, p); - - if(!MemUtil.ArraysEqual(pb, pbExpc)) - throw new SecurityException("Argon2-5"); - -#if SELFTEST_ARGON2_LONGER - p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 20) * 1024); // 1 GB - p.SetUInt64(Argon2Kdf.ParamIterations, 2); - p.SetUInt32(Argon2Kdf.ParamParallelism, 3); - - pbExpc = new byte[32] { - 0xE6, 0xE7, 0xCB, 0xF5, 0x5A, 0x06, 0x93, 0x05, - 0x32, 0xBA, 0x86, 0xC6, 0x1F, 0x45, 0x17, 0x99, - 0x65, 0x41, 0x77, 0xF9, 0x30, 0x55, 0x9A, 0xE8, - 0x3D, 0x21, 0x48, 0xC6, 0x2D, 0x0C, 0x49, 0x11 - }; - - pb = kdf.Transform(pbMsg, p); - - if(!MemUtil.ArraysEqual(pb, pbExpc)) - throw new SecurityException("Argon2-6"); -#endif // SELFTEST_ARGON2_LONGER -#endif // SELFTEST_ARGON2_LONG -#endif // DEBUG - } - - private static void TestHmac() - { -#if DEBUG - // Test vectors from RFC 4231 - - byte[] pbKey = new byte[20]; - for(int i = 0; i < pbKey.Length; ++i) pbKey[i] = 0x0B; - byte[] pbMsg = StrUtil.Utf8.GetBytes("Hi There"); - byte[] pbExpc = new byte[32] { - 0xB0, 0x34, 0x4C, 0x61, 0xD8, 0xDB, 0x38, 0x53, - 0x5C, 0xA8, 0xAF, 0xCE, 0xAF, 0x0B, 0xF1, 0x2B, - 0x88, 0x1D, 0xC2, 0x00, 0xC9, 0x83, 0x3D, 0xA7, - 0x26, 0xE9, 0x37, 0x6C, 0x2E, 0x32, 0xCF, 0xF7 - }; - HmacEval(pbKey, pbMsg, pbExpc, "1"); - - pbKey = new byte[131]; - for(int i = 0; i < pbKey.Length; ++i) pbKey[i] = 0xAA; - pbMsg = StrUtil.Utf8.GetBytes( - "This is a test using a larger than block-size key and " + - "a larger than block-size data. The key needs to be " + - "hashed before being used by the HMAC algorithm."); - pbExpc = new byte[32] { - 0x9B, 0x09, 0xFF, 0xA7, 0x1B, 0x94, 0x2F, 0xCB, - 0x27, 0x63, 0x5F, 0xBC, 0xD5, 0xB0, 0xE9, 0x44, - 0xBF, 0xDC, 0x63, 0x64, 0x4F, 0x07, 0x13, 0x93, - 0x8A, 0x7F, 0x51, 0x53, 0x5C, 0x3A, 0x35, 0xE2 - }; - HmacEval(pbKey, pbMsg, pbExpc, "2"); -#endif - } - -#if DEBUG - private static void HmacEval(byte[] pbKey, byte[] pbMsg, - byte[] pbExpc, string strID) - { - using(HMACSHA256 h = new HMACSHA256(pbKey)) - { - h.TransformBlock(pbMsg, 0, pbMsg.Length, pbMsg, 0); - h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); - - byte[] pbHash = h.Hash; - if(!MemUtil.ArraysEqual(pbHash, pbExpc)) - throw new SecurityException("HMAC-SHA-256-" + strID); - - // Reuse the object - h.Initialize(); - h.TransformBlock(pbMsg, 0, pbMsg.Length, pbMsg, 0); - h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); - - pbHash = h.Hash; - if(!MemUtil.ArraysEqual(pbHash, pbExpc)) - throw new SecurityException("HMAC-SHA-256-" + strID + "-R"); - } - } -#endif - - private static void TestKeyTransform(Random r) - { -#if DEBUG - // Up to KeePass 2.34, the OtpKeyProv plugin used the public - // CompositeKey.TransformKeyManaged method (and a finalizing - // SHA-256 computation), which became an internal method of - // the AesKdf class in KeePass 2.35, thus OtpKeyProv now - // uses the AesKdf class; here we ensure that the results - // are the same - - byte[] pbKey = new byte[32]; - r.NextBytes(pbKey); - byte[] pbSeed = new byte[32]; - r.NextBytes(pbSeed); - ulong uRounds = (ulong)r.Next(1, 0x7FFF); - - byte[] pbMan = new byte[pbKey.Length]; - Array.Copy(pbKey, pbMan, pbKey.Length); - if(!AesKdf.TransformKeyManaged(pbMan, pbSeed, uRounds)) - throw new SecurityException("AES-KDF-1"); - pbMan = CryptoUtil.HashSha256(pbMan); - - AesKdf kdf = new AesKdf(); - var p = kdf.GetDefaultParameters(); - p.SetUInt64(AesKdf.ParamRounds, uRounds); - p.SetByteArray(AesKdf.ParamSeed, pbSeed); - byte[] pbKdf = kdf.Transform(pbKey, p); - - if(!MemUtil.ArraysEqual(pbMan, pbKdf)) - throw new SecurityException("AES-KDF-2"); -#endif - } - - private static void TestNativeKeyTransform(Random r) - { -#if !ModernKeePassLib && DEBUG - byte[] pbOrgKey = CryptoRandom.Instance.GetRandomBytes(32); - byte[] pbSeed = CryptoRandom.Instance.GetRandomBytes(32); - ulong uRounds = (ulong)r.Next(1, 0x3FFF); - - byte[] pbManaged = new byte[32]; - Array.Copy(pbOrgKey, pbManaged, 32); - if(!AesKdf.TransformKeyManaged(pbManaged, pbSeed, uRounds)) - throw new SecurityException("AES-KDF-1"); - - byte[] pbNative = new byte[32]; - Array.Copy(pbOrgKey, pbNative, 32); - if(!NativeLib.TransformKey256(pbNative, pbSeed, uRounds)) - return; // Native library not available ("success") - - if(!MemUtil.ArraysEqual(pbManaged, pbNative)) - throw new SecurityException("AES-KDF-2"); -#endif - } - - private static void TestMemUtil(Random r) - { -#if DEBUG - byte[] pb = CryptoRandom.Instance.GetRandomBytes((uint)r.Next( - 0, 0x2FFFF)); - - byte[] pbCompressed = MemUtil.Compress(pb); - if(!MemUtil.ArraysEqual(MemUtil.Decompress(pbCompressed), pb)) - throw new InvalidOperationException("GZip"); - - Encoding enc = StrUtil.Utf8; - pb = enc.GetBytes("012345678901234567890a"); - byte[] pbN = enc.GetBytes("9012"); - if(MemUtil.IndexOf(pb, pbN) != 9) - throw new InvalidOperationException("MemUtil-1"); - pbN = enc.GetBytes("01234567890123"); - if(MemUtil.IndexOf(pb, pbN) != 0) - throw new InvalidOperationException("MemUtil-2"); - pbN = enc.GetBytes("a"); - if(MemUtil.IndexOf(pb, pbN) != 21) - throw new InvalidOperationException("MemUtil-3"); - pbN = enc.GetBytes("0a"); - if(MemUtil.IndexOf(pb, pbN) != 20) - throw new InvalidOperationException("MemUtil-4"); - pbN = enc.GetBytes("1"); - if(MemUtil.IndexOf(pb, pbN) != 1) - throw new InvalidOperationException("MemUtil-5"); - pbN = enc.GetBytes("b"); - if(MemUtil.IndexOf(pb, pbN) >= 0) - throw new InvalidOperationException("MemUtil-6"); - pbN = enc.GetBytes("012b"); - if(MemUtil.IndexOf(pb, pbN) >= 0) - throw new InvalidOperationException("MemUtil-7"); - - byte[] pbRes = MemUtil.ParseBase32("MY======"); - byte[] pbExp = Encoding.UTF8.GetBytes("f"); - if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-1"); - - pbRes = MemUtil.ParseBase32("MZXQ===="); - pbExp = Encoding.UTF8.GetBytes("fo"); - if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-2"); - - pbRes = MemUtil.ParseBase32("MZXW6==="); - pbExp = Encoding.UTF8.GetBytes("foo"); - if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-3"); - - pbRes = MemUtil.ParseBase32("MZXW6YQ="); - pbExp = Encoding.UTF8.GetBytes("foob"); - if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-4"); - - pbRes = MemUtil.ParseBase32("MZXW6YTB"); - pbExp = Encoding.UTF8.GetBytes("fooba"); - if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-5"); - - pbRes = MemUtil.ParseBase32("MZXW6YTBOI======"); - pbExp = Encoding.UTF8.GetBytes("foobar"); - if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-6"); - - pbRes = MemUtil.ParseBase32("JNSXSIDQOJXXM2LEMVZCAYTBONSWIIDPNYQG63TFFV2GS3LFEBYGC43TO5XXEZDTFY======"); - pbExp = Encoding.UTF8.GetBytes("Key provider based on one-time passwords."); - if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-7"); - - int i = 0 - 0x10203040; - pbRes = MemUtil.Int32ToBytes(i); - if(MemUtil.ByteArrayToHexString(pbRes) != "C0CFDFEF") - throw new Exception("MemUtil-8"); // Must be little-endian - if(MemUtil.BytesToUInt32(pbRes) != (uint)i) - throw new Exception("MemUtil-9"); - if(MemUtil.BytesToInt32(pbRes) != i) - throw new Exception("MemUtil-10"); - - ArrayHelperEx ah = MemUtil.ArrayHelperExOfChar; - for(int j = 0; j < 30; ++j) - { - string strA = r.Next(30).ToString(); - string strB = r.Next(30).ToString(); - char[] vA = strA.ToCharArray(); - char[] vB = strB.ToCharArray(); - - if(ah.Equals(vA, vB) != string.Equals(strA, strB)) - throw new Exception("MemUtil-11"); - if((vA.Length == vB.Length) && (Math.Sign(ah.Compare(vA, vB)) != - Math.Sign(string.CompareOrdinal(strA, strB)))) - throw new Exception("MemUtil-12"); - } -#endif - } - - private static void TestHmacOtp() - { -#if (DEBUG && !KeePassLibSD) - byte[] pbSecret = StrUtil.Utf8.GetBytes("12345678901234567890"); - string[] vExp = new string[]{ "755224", "287082", "359152", - "969429", "338314", "254676", "287922", "162583", "399871", - "520489" }; - - for(int i = 0; i < vExp.Length; ++i) - { - if(HmacOtp.Generate(pbSecret, (ulong)i, 6, false, -1) != vExp[i]) - throw new InvalidOperationException("HmacOtp"); - } -#endif - } - - private static void TestProtectedObjects(Random r) - { -#if DEBUG - Encoding enc = StrUtil.Utf8; - - byte[] pbData = enc.GetBytes("Test Test Test Test"); - ProtectedBinary pb = new ProtectedBinary(true, pbData); - if(!pb.IsProtected) throw new SecurityException("ProtectedBinary-1"); - - byte[] pbDec = pb.ReadData(); - if(!MemUtil.ArraysEqual(pbData, pbDec)) - throw new SecurityException("ProtectedBinary-2"); - if(!pb.IsProtected) throw new SecurityException("ProtectedBinary-3"); - - byte[] pbData2 = enc.GetBytes("Test Test Test Test"); - byte[] pbData3 = enc.GetBytes("Test Test Test Test Test"); - ProtectedBinary pb2 = new ProtectedBinary(true, pbData2); - ProtectedBinary pb3 = new ProtectedBinary(true, pbData3); - if(!pb.Equals(pb2)) throw new SecurityException("ProtectedBinary-4"); - if(pb.Equals(pb3)) throw new SecurityException("ProtectedBinary-5"); - if(pb2.Equals(pb3)) throw new SecurityException("ProtectedBinary-6"); - - if(pb.GetHashCode() != pb2.GetHashCode()) - throw new SecurityException("ProtectedBinary-7"); - if(!((object)pb).Equals((object)pb2)) - throw new SecurityException("ProtectedBinary-8"); - if(((object)pb).Equals((object)pb3)) - throw new SecurityException("ProtectedBinary-9"); - if(((object)pb2).Equals((object)pb3)) - throw new SecurityException("ProtectedBinary-10"); - - ProtectedString ps = new ProtectedString(); - if(ps.Length != 0) throw new SecurityException("ProtectedString-1"); - if(!ps.IsEmpty) throw new SecurityException("ProtectedString-2"); - if(ps.ReadString().Length != 0) - throw new SecurityException("ProtectedString-3"); - - ps = new ProtectedString(true, "Test"); - ProtectedString ps2 = new ProtectedString(true, enc.GetBytes("Test")); - if(ps.IsEmpty) throw new SecurityException("ProtectedString-4"); - pbData = ps.ReadUtf8(); - pbData2 = ps2.ReadUtf8(); - if(!MemUtil.ArraysEqual(pbData, pbData2)) - throw new SecurityException("ProtectedString-5"); - if(pbData.Length != 4) - throw new SecurityException("ProtectedString-6"); - if(ps.ReadString() != ps2.ReadString()) - throw new SecurityException("ProtectedString-7"); - pbData = ps.ReadUtf8(); - pbData2 = ps2.ReadUtf8(); - if(!MemUtil.ArraysEqual(pbData, pbData2)) - throw new SecurityException("ProtectedString-8"); - if(!ps.IsProtected) throw new SecurityException("ProtectedString-9"); - if(!ps2.IsProtected) throw new SecurityException("ProtectedString-10"); - - string str = string.Empty; - ps = new ProtectedString(); - for(int i = 0; i < 100; ++i) - { - bool bProt = ((r.Next() % 4) != 0); - ps = ps.WithProtection(bProt); - - int x = r.Next(str.Length + 1); - int c = r.Next(20); - char ch = (char)r.Next(1, 256); - - string strIns = new string(ch, c); - str = str.Insert(x, strIns); - ps = ps.Insert(x, strIns); - - if(ps.IsProtected != bProt) - throw new SecurityException("ProtectedString-11"); - if(ps.ReadString() != str) - throw new SecurityException("ProtectedString-12"); - - ps = ps.WithProtection(bProt); - - x = r.Next(str.Length); - c = r.Next(str.Length - x + 1); - - str = str.Remove(x, c); - ps = ps.Remove(x, c); - - if(ps.IsProtected != bProt) - throw new SecurityException("ProtectedString-13"); - if(ps.ReadString() != str) - throw new SecurityException("ProtectedString-14"); - } - - ps = new ProtectedString(false, "ABCD"); - ps2 = new ProtectedString(true, "EFG"); - ps += (ps2 + "HI"); - if(!ps.Equals(new ProtectedString(true, "ABCDEFGHI"), true)) - throw new SecurityException("ProtectedString-15"); - if(!ps.Equals(new ProtectedString(false, "ABCDEFGHI"), false)) - throw new SecurityException("ProtectedString-16"); -#endif - } - - private static void TestStrUtil() - { -#if DEBUG - string[] vSeps = new string[]{ "ax", "b", "c" }; - const string str1 = "axbqrstcdeax"; - List v1 = StrUtil.SplitWithSep(str1, vSeps, true); - - if(v1.Count != 9) throw new InvalidOperationException("StrUtil-1"); - if(v1[0].Length > 0) throw new InvalidOperationException("StrUtil-2"); - if(!v1[1].Equals("ax")) throw new InvalidOperationException("StrUtil-3"); - if(v1[2].Length > 0) throw new InvalidOperationException("StrUtil-4"); - if(!v1[3].Equals("b")) throw new InvalidOperationException("StrUtil-5"); - if(!v1[4].Equals("qrst")) throw new InvalidOperationException("StrUtil-6"); - if(!v1[5].Equals("c")) throw new InvalidOperationException("StrUtil-7"); - if(!v1[6].Equals("de")) throw new InvalidOperationException("StrUtil-8"); - if(!v1[7].Equals("ax")) throw new InvalidOperationException("StrUtil-9"); - if(v1[8].Length > 0) throw new InvalidOperationException("StrUtil-10"); - - const string str2 = "12ab56"; - List v2 = StrUtil.SplitWithSep(str2, new string[]{ "AB" }, false); - if(v2.Count != 3) throw new InvalidOperationException("StrUtil-11"); - if(!v2[0].Equals("12")) throw new InvalidOperationException("StrUtil-12"); - if(!v2[1].Equals("AB")) throw new InvalidOperationException("StrUtil-13"); - if(!v2[2].Equals("56")) throw new InvalidOperationException("StrUtil-14"); - - List v3 = StrUtil.SplitWithSep("pqrs", vSeps, false); - if(v3.Count != 1) throw new InvalidOperationException("StrUtil-15"); - if(!v3[0].Equals("pqrs")) throw new InvalidOperationException("StrUtil-16"); - - if(StrUtil.VersionToString(0x000F000E000D000CUL) != "15.14.13.12") - throw new InvalidOperationException("StrUtil-V1"); - if(StrUtil.VersionToString(0x00FF000E00010000UL) != "255.14.1") - throw new InvalidOperationException("StrUtil-V2"); - if(StrUtil.VersionToString(0x000F00FF00000000UL) != "15.255") - throw new InvalidOperationException("StrUtil-V3"); - if(StrUtil.VersionToString(0x00FF000000000000UL) != "255") - throw new InvalidOperationException("StrUtil-V4"); - if(StrUtil.VersionToString(0x00FF000000000000UL, 2) != "255.0") - throw new InvalidOperationException("StrUtil-V5"); - if(StrUtil.VersionToString(0x0000000000070000UL) != "0.0.7") - throw new InvalidOperationException("StrUtil-V6"); - if(StrUtil.VersionToString(0x0000000000000000UL) != "0") - throw new InvalidOperationException("StrUtil-V7"); - if(StrUtil.VersionToString(0x00000000FFFF0000UL, 4) != "0.0.65535.0") - throw new InvalidOperationException("StrUtil-V8"); - if(StrUtil.VersionToString(0x0000000000000000UL, 4) != "0.0.0.0") - throw new InvalidOperationException("StrUtil-V9"); - - if(StrUtil.RtfEncodeChar('\u0000') != "\\u0?") - throw new InvalidOperationException("StrUtil-Rtf1"); - if(StrUtil.RtfEncodeChar('\u7FFF') != "\\u32767?") - throw new InvalidOperationException("StrUtil-Rtf2"); - if(StrUtil.RtfEncodeChar('\u8000') != "\\u-32768?") - throw new InvalidOperationException("StrUtil-Rtf3"); - if(StrUtil.RtfEncodeChar('\uFFFF') != "\\u-1?") - throw new InvalidOperationException("StrUtil-Rtf4"); - - if(!StrUtil.StringToBool(Boolean.TrueString)) - throw new InvalidOperationException("StrUtil-Bool1"); - if(StrUtil.StringToBool(Boolean.FalseString)) - throw new InvalidOperationException("StrUtil-Bool2"); - - if(StrUtil.Count("Abracadabra", "a") != 4) - throw new InvalidOperationException("StrUtil-Count1"); - if(StrUtil.Count("Bla", "U") != 0) - throw new InvalidOperationException("StrUtil-Count2"); - if(StrUtil.Count("AAAAA", "AA") != 4) - throw new InvalidOperationException("StrUtil-Count3"); - - const string sU = "data:mytype;base64,"; - if(!StrUtil.IsDataUri(sU)) - throw new InvalidOperationException("StrUtil-DataUri1"); - if(!StrUtil.IsDataUri(sU, "mytype")) - throw new InvalidOperationException("StrUtil-DataUri2"); - if(StrUtil.IsDataUri(sU, "notmytype")) - throw new InvalidOperationException("StrUtil-DataUri3"); - - uint u = 0x7FFFFFFFU; - if(u.ToString(NumberFormatInfo.InvariantInfo) != "2147483647") - throw new InvalidOperationException("StrUtil-Inv1"); - if(uint.MaxValue.ToString(NumberFormatInfo.InvariantInfo) != - "4294967295") - throw new InvalidOperationException("StrUtil-Inv2"); - if(long.MinValue.ToString(NumberFormatInfo.InvariantInfo) != - "-9223372036854775808") - throw new InvalidOperationException("StrUtil-Inv3"); - if(short.MinValue.ToString(NumberFormatInfo.InvariantInfo) != - "-32768") - throw new InvalidOperationException("StrUtil-Inv4"); - - if(!string.Equals("abcd", "aBcd", StrUtil.CaseIgnoreCmp)) - throw new InvalidOperationException("StrUtil-Case1"); - if(string.Equals(@"ab", StrUtil.CaseIgnoreCmp)) - throw new InvalidOperationException("StrUtil-Case2"); - - const string strNL = "\n01\r23\n45\r\n67\r"; - string strW = StrUtil.NormalizeNewLines(strNL, true); - string strL = StrUtil.NormalizeNewLines(strNL, false); - if(strW != "\r\n01\r\n23\r\n45\r\n67\r\n") - throw new InvalidOperationException("StrUtil-NewLine1"); - if(strL != "\n01\n23\n45\n67\n") - throw new InvalidOperationException("StrUtil-NewLine2"); - if(StrUtil.IsNewLineNormalized(strNL.ToCharArray(), true)) - throw new InvalidOperationException("StrUtil-NewLine3"); - if(StrUtil.IsNewLineNormalized(strNL.ToCharArray(), false)) - throw new InvalidOperationException("StrUtil-NewLine4"); - if(!StrUtil.IsNewLineNormalized(strW.ToCharArray(), true)) - throw new InvalidOperationException("StrUtil-NewLine5"); - if(StrUtil.IsNewLineNormalized(strW.ToCharArray(), false)) - throw new InvalidOperationException("StrUtil-NewLine6"); - if(StrUtil.IsNewLineNormalized(strL.ToCharArray(), true)) - throw new InvalidOperationException("StrUtil-NewLine7"); - if(!StrUtil.IsNewLineNormalized(strL.ToCharArray(), false)) - throw new InvalidOperationException("StrUtil-NewLine8"); - if(!StrUtil.IsNewLineNormalized(string.Empty.ToCharArray(), true)) - throw new InvalidOperationException("StrUtil-NewLine9"); - if(!StrUtil.IsNewLineNormalized(string.Empty.ToCharArray(), false)) - throw new InvalidOperationException("StrUtil-NewLine10"); -#endif - } - - private static void TestUrlUtil() - { -#if DEBUG -#if !ModernKeePassLib && !KeePassUAP - Debug.Assert(Uri.UriSchemeHttp.Equals("http", StrUtil.CaseIgnoreCmp)); - Debug.Assert(Uri.UriSchemeHttps.Equals("https", StrUtil.CaseIgnoreCmp)); -#endif - - if(UrlUtil.GetHost(@"scheme://domain:port/path?query_string#fragment_id") != - "domain") - throw new InvalidOperationException("UrlUtil-H1"); - if(UrlUtil.GetHost(@"https://example.org:443") != "example.org") - throw new InvalidOperationException("UrlUtil-H2"); - if(UrlUtil.GetHost(@"mailto:bob@example.com") != "example.com") - throw new InvalidOperationException("UrlUtil-H3"); - if(UrlUtil.GetHost(@"ftp://asmith@ftp.example.org") != "ftp.example.org") - throw new InvalidOperationException("UrlUtil-H4"); - if(UrlUtil.GetHost(@"scheme://username:password@domain:port/path?query_string#fragment_id") != - "domain") - throw new InvalidOperationException("UrlUtil-H5"); - if(UrlUtil.GetHost(@"bob@example.com") != "example.com") - throw new InvalidOperationException("UrlUtil-H6"); - if(UrlUtil.GetHost(@"s://u:p@d.tld:p/p?q#f") != "d.tld") - throw new InvalidOperationException("UrlUtil-H7"); - - if(NativeLib.IsUnix()) return; - - string strBase = "\\\\HOMESERVER\\Apps\\KeePass\\KeePass.exe"; - string strDoc = "\\\\HOMESERVER\\Documents\\KeePass\\NewDatabase.kdbx"; - string strRel = "..\\..\\Documents\\KeePass\\NewDatabase.kdbx"; - - string str = UrlUtil.MakeRelativePath(strBase, strDoc); - if(!str.Equals(strRel)) throw new InvalidOperationException("UrlUtil-R1"); - - str = UrlUtil.MakeAbsolutePath(strBase, strRel); - if(!str.Equals(strDoc)) throw new InvalidOperationException("UrlUtil-R2"); - - str = UrlUtil.GetQuotedAppPath(" \"Test\" \"%1\" "); - if(str != "Test") throw new InvalidOperationException("UrlUtil-Q1"); - str = UrlUtil.GetQuotedAppPath("C:\\Program Files\\Test.exe"); - if(str != "C:\\Program Files\\Test.exe") throw new InvalidOperationException("UrlUtil-Q2"); - str = UrlUtil.GetQuotedAppPath("Reg.exe \"Test\" \"Test 2\""); - if(str != "Reg.exe \"Test\" \"Test 2\"") throw new InvalidOperationException("UrlUtil-Q3"); -#endif - } - } -} diff --git a/ModernKeePassLib/Delegates/Handlers.cs b/ModernKeePassLib/Delegates/Handlers.cs deleted file mode 100644 index 5c3786b..0000000 --- a/ModernKeePassLib/Delegates/Handlers.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; - -namespace ModernKeePassLib.Delegates -{ - /// - /// Function definition of a method that performs an action on a group. - /// When traversing the internal tree, this function will be invoked - /// for all visited groups. - /// - /// Currently visited group. - /// You must return true if you want to continue the - /// traversal. If you want to immediately stop the whole traversal, - /// return false. - public delegate bool GroupHandler(PwGroup pg); - - /// - /// Function definition of a method that performs an action on an entry. - /// When traversing the internal tree, this function will be invoked - /// for all visited entries. - /// - /// Currently visited entry. - /// You must return true if you want to continue the - /// traversal. If you want to immediately stop the whole traversal, - /// return false. - public delegate bool EntryHandler(PwEntry pe); - - public delegate void VoidDelegate(); - public delegate string StrPwEntryDelegate(string str, PwEntry pe); - - // Action<...> with 0 or >= 2 parameters has been introduced in .NET 3.5 - public delegate void GAction(); - public delegate void GAction(T o); - public delegate void GAction(T1 o1, T2 o2); - public delegate void GAction(T1 o1, T2 o2, T3 o3); - public delegate void GAction(T1 o1, T2 o2, T3 o3, T4 o4); - public delegate void GAction(T1 o1, T2 o2, T3 o3, T4 o4, T5 o5); - public delegate void GAction(T1 o1, T2 o2, T3 o3, T4 o4, T5 o5, T6 o6); - - // Func<...> has been introduced in .NET 3.5 - public delegate TResult GFunc(); - public delegate TResult GFunc(T o); - public delegate TResult GFunc(T1 o1, T2 o2); - public delegate TResult GFunc(T1 o1, T2 o2, T3 o3); - public delegate TResult GFunc(T1 o1, T2 o2, T3 o3, T4 o4); - public delegate TResult GFunc(T1 o1, T2 o2, T3 o3, T4 o4, T5 o5); - public delegate TResult GFunc(T1 o1, T2 o2, T3 o3, T4 o4, T5 o5, T6 o6); -} diff --git a/ModernKeePassLib/Interfaces/IDeepCloneable.cs b/ModernKeePassLib/Interfaces/IDeepCloneable.cs deleted file mode 100644 index ffaad06..0000000 --- a/ModernKeePassLib/Interfaces/IDeepCloneable.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; - -namespace ModernKeePassLib.Interfaces -{ - /// - /// Interface for objects that are deeply cloneable. - /// - /// Reference type. - public interface IDeepCloneable where T : class - { - /// - /// Deeply clone the object. - /// - /// Cloned object. - T CloneDeep(); - } -} diff --git a/ModernKeePassLib/Interfaces/IStatusLogger.cs b/ModernKeePassLib/Interfaces/IStatusLogger.cs deleted file mode 100644 index 980ca3d..0000000 --- a/ModernKeePassLib/Interfaces/IStatusLogger.cs +++ /dev/null @@ -1,105 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; - -namespace ModernKeePassLib.Interfaces -{ - /// - /// Status message types. - /// - public enum LogStatusType - { - /// - /// Default type: simple information type. - /// - Info = 0, - - /// - /// Warning message. - /// - Warning, - - /// - /// Error message. - /// - Error, - - /// - /// Additional information. Depends on lines above. - /// - AdditionalInfo - } - - /// - /// Status logging interface. - /// - public interface IStatusLogger - { - /// - /// Function which needs to be called when logging is started. - /// - /// This string should roughly describe - /// the operation, of which the status is logged. - /// Specifies whether the - /// operation is written to the log or not. - void StartLogging(string strOperation, bool bWriteOperationToLog); - - /// - /// Function which needs to be called when logging is ended - /// (i.e. when no more messages will be logged and when the - /// percent value won't change any more). - /// - void EndLogging(); - - /// - /// Set the current progress in percent. - /// - /// Percent of work finished. - /// Returns true if the caller should continue - /// the current work. - bool SetProgress(uint uPercent); - - /// - /// Set the current status text. - /// - /// Status text. - /// Type of the message. - /// Returns true if the caller should continue - /// the current work. - bool SetText(string strNewText, LogStatusType lsType); - - /// - /// Check if the user cancelled the current work. - /// - /// Returns true if the caller should continue - /// the current work. - bool ContinueWork(); - } - - public sealed class NullStatusLogger : IStatusLogger - { - public void StartLogging(string strOperation, bool bWriteOperationToLog) { } - public void EndLogging() { } - public bool SetProgress(uint uPercent) { return true; } - public bool SetText(string strNewText, LogStatusType lsType) { return true; } - public bool ContinueWork() { return true; } - } -} diff --git a/ModernKeePassLib/Interfaces/IStructureItem.cs b/ModernKeePassLib/Interfaces/IStructureItem.cs deleted file mode 100644 index 9fc2eed..0000000 --- a/ModernKeePassLib/Interfaces/IStructureItem.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; - -namespace ModernKeePassLib.Interfaces -{ - public interface IStructureItem : ITimeLogger // Provides LocationChanged - { - PwUuid Uuid - { - get; - set; - } - - PwGroup ParentGroup - { - get; - } - } -} diff --git a/ModernKeePassLib/Interfaces/ITimeLogger.cs b/ModernKeePassLib/Interfaces/ITimeLogger.cs deleted file mode 100644 index 6611e3b..0000000 --- a/ModernKeePassLib/Interfaces/ITimeLogger.cs +++ /dev/null @@ -1,105 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; - -namespace ModernKeePassLib.Interfaces -{ - /// - /// Interface for objects that support various times (creation time, last - /// access time, last modification time and expiry time). Offers - /// several helper functions (for example a function to touch the current - /// object). - /// - public interface ITimeLogger - { - /// - /// The date/time when the object was created. - /// - DateTime CreationTime - { - get; - set; - } - - /// - /// The date/time when the object was last modified. - /// - DateTime LastModificationTime - { - get; - set; - } - - /// - /// The date/time when the object was last accessed. - /// - DateTime LastAccessTime - { - get; - set; - } - - /// - /// The date/time when the object expires. - /// - DateTime ExpiryTime - { - get; - set; - } - - /// - /// Flag that determines if the object does expire. - /// - bool Expires - { - get; - set; - } - - /// - /// Get or set the usage count of the object. To increase the usage - /// count by one, use the Touch function. - /// - ulong UsageCount - { - get; - set; - } - - /// - /// The date/time when the location of the object was last changed. - /// - DateTime LocationChanged - { - get; - set; - } - - /// - /// Touch the object. This function updates the internal last access - /// time. If the parameter is true, - /// the last modification time gets updated, too. Each time you call - /// Touch, the usage count of the object is increased by one. - /// - /// Update last modification time. - void Touch(bool bModified); - } -} diff --git a/ModernKeePassLib/Interfaces/IUIOperations.cs b/ModernKeePassLib/Interfaces/IUIOperations.cs deleted file mode 100644 index be8fee6..0000000 --- a/ModernKeePassLib/Interfaces/IUIOperations.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace ModernKeePassLib.Interfaces -{ - public interface IUIOperations - { - /// - /// Let the user interface save the current database. - /// - /// If true, the UI will not ask for - /// whether to synchronize or overwrite, it'll simply overwrite the - /// file. - /// Returns true if the file has been saved. - bool UIFileSave(bool bForceSave); - } -} diff --git a/ModernKeePassLib/Interfaces/IXmlSerializerEx.cs b/ModernKeePassLib/Interfaces/IXmlSerializerEx.cs deleted file mode 100644 index 8712e5e..0000000 --- a/ModernKeePassLib/Interfaces/IXmlSerializerEx.cs +++ /dev/null @@ -1,33 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using System.Xml; - -namespace ModernKeePassLib.Interfaces -{ - public interface IXmlSerializerEx - { - void Serialize(XmlWriter xmlWriter, object o); - object Deserialize(Stream s); - } -} diff --git a/ModernKeePassLib/KeePassLib.pfx b/ModernKeePassLib/KeePassLib.pfx deleted file mode 100644 index 19b0155..0000000 Binary files a/ModernKeePassLib/KeePassLib.pfx and /dev/null differ diff --git a/ModernKeePassLib/Keys/CompositeKey.cs b/ModernKeePassLib/Keys/CompositeKey.cs deleted file mode 100644 index 4159ad7..0000000 --- a/ModernKeePassLib/Keys/CompositeKey.cs +++ /dev/null @@ -1,295 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Cryptography.KeyDerivation; -using ModernKeePassLib.Resources; -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Keys -{ - /// - /// Represents a key. A key can be build up using several user key data sources - /// like a password, a key file, the currently logged on user credentials, - /// the current computer ID, etc. - /// - public sealed class CompositeKey - { - private List m_vUserKeys = new List(); - - /// - /// List of all user keys contained in the current composite key. - /// - public IEnumerable UserKeys - { - get { return m_vUserKeys; } - } - - public uint UserKeyCount - { - get { return (uint)m_vUserKeys.Count; } - } - - /// - /// Construct a new, empty key object. - /// - public CompositeKey() - { - } - - // /// - // /// Deconstructor, clears up the key. - // /// - // ~CompositeKey() - // { - // Clear(); - // } - - // /// - // /// Clears the key. This function also erases all previously stored - // /// user key data objects. - // /// - // public void Clear() - // { - // foreach(IUserKey pKey in m_vUserKeys) - // pKey.Clear(); - // m_vUserKeys.Clear(); - // } - - /// - /// Add a user key. - /// - /// User key to add. - public void AddUserKey(IUserKey pKey) - { - Debug.Assert(pKey != null); if(pKey == null) throw new ArgumentNullException("pKey"); - - m_vUserKeys.Add(pKey); - } - - /// - /// Remove a user key. - /// - /// User key to remove. - /// Returns true if the key was removed successfully. - public bool RemoveUserKey(IUserKey pKey) - { - Debug.Assert(pKey != null); if(pKey == null) throw new ArgumentNullException("pKey"); - - Debug.Assert(m_vUserKeys.IndexOf(pKey) >= 0); - return m_vUserKeys.Remove(pKey); - } - - /// - /// Test whether the composite key contains a specific type of - /// user keys (password, key file, ...). If at least one user - /// key of that type is present, the function returns true. - /// - /// User key type. - /// Returns true, if the composite key contains - /// a user key of the specified type. - public bool ContainsType(Type tUserKeyType) - { - Debug.Assert(tUserKeyType != null); - if(tUserKeyType == null) throw new ArgumentNullException("tUserKeyType"); - - foreach(IUserKey pKey in m_vUserKeys) - { - if(pKey == null) { Debug.Assert(false); continue; } - -#if ModernKeePassLib || KeePassUAP - if(pKey.GetType() == tUserKeyType) - return true; -#else - if(tUserKeyType.IsInstanceOfType(pKey)) - return true; -#endif - } - - return false; - } - - /// - /// Get the first user key of a specified type. - /// - /// Type of the user key to get. - /// Returns the first user key of the specified type - /// or null if no key of that type is found. - public IUserKey GetUserKey(Type tUserKeyType) - { - Debug.Assert(tUserKeyType != null); - if(tUserKeyType == null) throw new ArgumentNullException("tUserKeyType"); - - foreach(IUserKey pKey in m_vUserKeys) - { - if(pKey == null) { Debug.Assert(false); continue; } - -#if ModernKeePassLib || KeePassUAP - if(pKey.GetType() == tUserKeyType) - return pKey; -#else - if(tUserKeyType.IsInstanceOfType(pKey)) - return pKey; -#endif - } - - return null; - } - - /// - /// Creates the composite key from the supplied user key sources (password, - /// key file, user account, computer ID, etc.). - /// - private byte[] CreateRawCompositeKey32() - { - ValidateUserKeys(); - - // Concatenate user key data - List lData = new List(); - int cbData = 0; - foreach(IUserKey pKey in m_vUserKeys) - { - ProtectedBinary b = pKey.KeyData; - if(b != null) - { - byte[] pbKeyData = b.ReadData(); - lData.Add(pbKeyData); - cbData += pbKeyData.Length; - } - } - - byte[] pbAllData = new byte[cbData]; - int p = 0; - foreach(byte[] pbData in lData) - { - Array.Copy(pbData, 0, pbAllData, p, pbData.Length); - p += pbData.Length; - MemUtil.ZeroByteArray(pbData); - } - Debug.Assert(p == cbData); - - byte[] pbHash = CryptoUtil.HashSha256(pbAllData); - MemUtil.ZeroByteArray(pbAllData); - return pbHash; - } - - public bool EqualsValue(CompositeKey ckOther) - { - if(ckOther == null) throw new ArgumentNullException("ckOther"); - - byte[] pbThis = CreateRawCompositeKey32(); - byte[] pbOther = ckOther.CreateRawCompositeKey32(); - bool bResult = MemUtil.ArraysEqual(pbThis, pbOther); - MemUtil.ZeroByteArray(pbOther); - MemUtil.ZeroByteArray(pbThis); - - return bResult; - } - - [Obsolete] - public ProtectedBinary GenerateKey32(byte[] pbKeySeed32, ulong uNumRounds) - { - Debug.Assert(pbKeySeed32 != null); - if(pbKeySeed32 == null) throw new ArgumentNullException("pbKeySeed32"); - Debug.Assert(pbKeySeed32.Length == 32); - if(pbKeySeed32.Length != 32) throw new ArgumentException("pbKeySeed32"); - - AesKdf kdf = new AesKdf(); - KdfParameters p = kdf.GetDefaultParameters(); - p.SetUInt64(AesKdf.ParamRounds, uNumRounds); - p.SetByteArray(AesKdf.ParamSeed, pbKeySeed32); - - return GenerateKey32(p); - } - - /// - /// Generate a 32-byte (256-bit) key from the composite key. - /// - public ProtectedBinary GenerateKey32(KdfParameters p) - { - if(p == null) { Debug.Assert(false); throw new ArgumentNullException("p"); } - - byte[] pbRaw32 = CreateRawCompositeKey32(); - if((pbRaw32 == null) || (pbRaw32.Length != 32)) - { Debug.Assert(false); return null; } - - KdfEngine kdf = KdfPool.Get(p.KdfUuid); - if(kdf == null) // CryptographicExceptions are translated to "file corrupted" - throw new Exception(KLRes.UnknownKdf + MessageService.NewParagraph + - KLRes.FileNewVerOrPlgReq + MessageService.NewParagraph + - "UUID: " + p.KdfUuid.ToHexString() + "."); - - byte[] pbTrf32 = kdf.Transform(pbRaw32, p); - if(pbTrf32 == null) { Debug.Assert(false); return null; } - - if(pbTrf32.Length != 32) - { - Debug.Assert(false); - pbTrf32 = CryptoUtil.HashSha256(pbTrf32); - } - - ProtectedBinary pbRet = new ProtectedBinary(true, pbTrf32); - MemUtil.ZeroByteArray(pbTrf32); - MemUtil.ZeroByteArray(pbRaw32); - return pbRet; - } - - private void ValidateUserKeys() - { - int nAccounts = 0; - - foreach(IUserKey uKey in m_vUserKeys) - { - if(uKey is KcpUserAccount) - ++nAccounts; - } - - if(nAccounts >= 2) - { - Debug.Assert(false); - throw new InvalidOperationException(); - } - } - } - - public sealed class InvalidCompositeKeyException : Exception - { - public override string Message - { - get - { - return KLRes.InvalidCompositeKey + MessageService.NewParagraph + - KLRes.InvalidCompositeKeyHint; - } - } - - /// - /// Construct a new invalid composite key exception. - /// - public InvalidCompositeKeyException() - { - } - } -} diff --git a/ModernKeePassLib/Keys/IUserKey.cs b/ModernKeePassLib/Keys/IUserKey.cs deleted file mode 100644 index f3ae8bf..0000000 --- a/ModernKeePassLib/Keys/IUserKey.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; - -using ModernKeePassLib.Security; - -namespace ModernKeePassLib.Keys -{ - /// - /// Interface to a user key, like a password, key file data, etc. - /// - public interface IUserKey - { - /// - /// Get key data. Querying this property is fast (it returns a - /// reference to a cached ProtectedBinary object). - /// If no key data is available, null is returned. - /// - ProtectedBinary KeyData - { - get; - } - - // /// - // /// Clear the key and securely erase all security-critical information. - // /// - // void Clear(); - } -} diff --git a/ModernKeePassLib/Keys/KcpCustomKey.cs b/ModernKeePassLib/Keys/KcpCustomKey.cs deleted file mode 100644 index d263cc5..0000000 --- a/ModernKeePassLib/Keys/KcpCustomKey.cs +++ /dev/null @@ -1,68 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Security; - -namespace ModernKeePassLib.Keys -{ - public sealed class KcpCustomKey : IUserKey - { - private readonly string m_strName; - private ProtectedBinary m_pbKey; - - /// - /// Name of the provider that generated the custom key. - /// - public string Name - { - get { return m_strName; } - } - - public ProtectedBinary KeyData - { - get { return m_pbKey; } - } - - public KcpCustomKey(string strName, byte[] pbKeyData, bool bPerformHash) - { - Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); - Debug.Assert(pbKeyData != null); if(pbKeyData == null) throw new ArgumentNullException("pbKeyData"); - - m_strName = strName; - - if(bPerformHash) - { - byte[] pbRaw = CryptoUtil.HashSha256(pbKeyData); - m_pbKey = new ProtectedBinary(true, pbRaw); - } - else m_pbKey = new ProtectedBinary(true, pbKeyData); - } - - // public void Clear() - // { - // m_pbKey = null; - // } - } -} diff --git a/ModernKeePassLib/Keys/KcpKeyFile.cs b/ModernKeePassLib/Keys/KcpKeyFile.cs deleted file mode 100644 index fde69b7..0000000 --- a/ModernKeePassLib/Keys/KcpKeyFile.cs +++ /dev/null @@ -1,350 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Diagnostics; -using System.IO; -using System.Security; -using System.Text; -using System.Xml; -#if ModernKeePassLib -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; -using Windows.Security.Cryptography; -using Windows.Security.Cryptography.Core; -using Windows.Storage; -#else -using System.Security.Cryptography; -#endif - -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Resources; -using ModernKeePassLib.Security; -using ModernKeePassLib.Serialization; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Keys -{ - /// - /// Key files as provided by the user. - /// - public sealed class KcpKeyFile : IUserKey - { - private string m_strPath; - private ProtectedBinary m_pbKeyData; - - /// - /// Path to the key file. - /// - public string Path - { - get { return m_strPath; } - } - - /// - /// Get key data. Querying this property is fast (it returns a - /// reference to a cached ProtectedBinary object). - /// If no key data is available, null is returned. - /// - public ProtectedBinary KeyData - { - get { return m_pbKeyData; } - } - -#if ModernKeePassLib - public KcpKeyFile(StorageFile strKeyFile) - { - Construct(IOConnectionInfo.FromFile(strKeyFile), false); - } -#endif - - public KcpKeyFile(string strKeyFile) - { - Construct(IOConnectionInfo.FromPath(strKeyFile), false); - } - - public KcpKeyFile(string strKeyFile, bool bThrowIfDbFile) - { - Construct(IOConnectionInfo.FromPath(strKeyFile), bThrowIfDbFile); - } - - public KcpKeyFile(IOConnectionInfo iocKeyFile) - { - Construct(iocKeyFile, false); - } - - public KcpKeyFile(IOConnectionInfo iocKeyFile, bool bThrowIfDbFile) - { - Construct(iocKeyFile, bThrowIfDbFile); - } - - private void Construct(IOConnectionInfo iocFile, bool bThrowIfDbFile) - { - byte[] pbFileData = IOConnection.ReadFile(iocFile); - if(pbFileData == null) throw new FileNotFoundException(); - - if(bThrowIfDbFile && (pbFileData.Length >= 8)) - { - uint uSig1 = MemUtil.BytesToUInt32(MemUtil.Mid(pbFileData, 0, 4)); - uint uSig2 = MemUtil.BytesToUInt32(MemUtil.Mid(pbFileData, 4, 4)); - - if(((uSig1 == KdbxFile.FileSignature1) && - (uSig2 == KdbxFile.FileSignature2)) || - ((uSig1 == KdbxFile.FileSignaturePreRelease1) && - (uSig2 == KdbxFile.FileSignaturePreRelease2)) || - ((uSig1 == KdbxFile.FileSignatureOld1) && - (uSig2 == KdbxFile.FileSignatureOld2))) -#if KeePassLibSD - throw new Exception(KLRes.KeyFileDbSel); -#else - throw new InvalidDataException(KLRes.KeyFileDbSel); -#endif - } - - byte[] pbKey = LoadXmlKeyFile(pbFileData); - if(pbKey == null) pbKey = LoadKeyFile(pbFileData); - - if(pbKey == null) throw new InvalidOperationException(); - - m_strPath = iocFile.Path; - m_pbKeyData = new ProtectedBinary(true, pbKey); - - MemUtil.ZeroByteArray(pbKey); - } - - // public void Clear() - // { - // m_strPath = string.Empty; - // m_pbKeyData = null; - // } - - private static byte[] LoadKeyFile(byte[] pbFileData) - { - if(pbFileData == null) { Debug.Assert(false); return null; } - - int iLength = pbFileData.Length; - - byte[] pbKey = null; - if(iLength == 32) pbKey = LoadBinaryKey32(pbFileData); - else if(iLength == 64) pbKey = LoadHexKey32(pbFileData); - - if(pbKey == null) - pbKey = CryptoUtil.HashSha256(pbFileData); - - return pbKey; - } - - private static byte[] LoadBinaryKey32(byte[] pbFileData) - { - if(pbFileData == null) { Debug.Assert(false); return null; } - if(pbFileData.Length != 32) { Debug.Assert(false); return null; } - - return pbFileData; - } - - private static byte[] LoadHexKey32(byte[] pbFileData) - { - if(pbFileData == null) { Debug.Assert(false); return null; } - if(pbFileData.Length != 64) { Debug.Assert(false); return null; } - - try - { - if(!StrUtil.IsHexString(pbFileData, true)) return null; - - string strHex = StrUtil.Utf8.GetString(pbFileData, 0, pbFileData.Length); - byte[] pbKey = MemUtil.HexStringToByteArray(strHex); - if((pbKey == null) || (pbKey.Length != 32)) - { - Debug.Assert(false); - return null; - } - - return pbKey; - } - catch(Exception) { Debug.Assert(false); } - - return null; - } - - /// - /// Create a new, random key-file. - /// - /// Path where the key-file should be saved to. - /// If the file exists already, it will be overwritten. - /// Additional entropy used to generate - /// the random key. May be null (in this case only the KeePass-internal - /// random number generator is used). - /// Returns a FileSaveResult error code. -#if ModernKeePassLib - public static void Create(StorageFile strFilePath, byte[] pbAdditionalEntropy) -#else - public static void Create(string strFilePath, byte[] pbAdditionalEntropy) -#endif - { - byte[] pbKey32 = CryptoRandom.Instance.GetRandomBytes(32); - if(pbKey32 == null) throw new SecurityException(); - - byte[] pbFinalKey32; - if((pbAdditionalEntropy == null) || (pbAdditionalEntropy.Length == 0)) - pbFinalKey32 = pbKey32; - else - { - using(MemoryStream ms = new MemoryStream()) - { - MemUtil.Write(ms, pbAdditionalEntropy); - MemUtil.Write(ms, pbKey32); - - pbFinalKey32 = CryptoUtil.HashSha256(ms.ToArray()); - } - } - - CreateXmlKeyFile(strFilePath, pbFinalKey32); - } - - // ================================================================ - // XML Key Files - // ================================================================ - - // Sample XML file: - // - // - // - // 1.00 - // - // - // ySFoKuCcJblw8ie6RkMBdVCnAf4EedSch7ItujK6bmI= - // - // - - private const string RootElementName = "KeyFile"; - private const string MetaElementName = "Meta"; - private const string VersionElementName = "Version"; - private const string KeyElementName = "Key"; - private const string KeyDataElementName = "Data"; - - private static byte[] LoadXmlKeyFile(byte[] pbFileData) - { - if(pbFileData == null) { Debug.Assert(false); return null; } - - MemoryStream ms = new MemoryStream(pbFileData, false); - byte[] pbKeyData = null; - - try - { -#if ModernKeePassLib - - var doc = XDocument.Load(ms); - - var el = doc.Root; - - if((el == null) || !el.Name.LocalName.Equals(RootElementName)) - return null; - if(el.DescendantNodes().Count() < 2) - return null; - - foreach(var xmlChild in el.Descendants()) - { - if(xmlChild.Name == MetaElementName) { } // Ignore Meta - else if(xmlChild.Name == KeyElementName) - { - foreach(var xmlKeyChild in xmlChild.Descendants()) - { - if(xmlKeyChild.Name == KeyDataElementName) - { - if(pbKeyData == null) - pbKeyData = Convert.FromBase64String(xmlKeyChild.Value); - } - } - } - } -#else - XmlDocument doc = XmlUtilEx.CreateXmlDocument(); - doc.Load(ms); - - XmlElement el = doc.DocumentElement; - if((el == null) || !el.Name.Equals(RootElementName)) return null; - if(el.ChildNodes.Count < 2) return null; - - foreach(XmlNode xmlChild in el.ChildNodes) - { - if(xmlChild.Name.Equals(MetaElementName)) { } // Ignore Meta - else if(xmlChild.Name == KeyElementName) - { - foreach(XmlNode xmlKeyChild in xmlChild.ChildNodes) - { - if(xmlKeyChild.Name == KeyDataElementName) - { - if(pbKeyData == null) - pbKeyData = Convert.FromBase64String(xmlKeyChild.InnerText); - } - } - } - } -#endif - } - catch(Exception) { pbKeyData = null; } - finally { ms.Dispose(); } - - return pbKeyData; - } -#if ModernKeePassLib - private static void CreateXmlKeyFile(StorageFile strFile, byte[] pbKeyData) -#else - private static void CreateXmlKeyFile(string strFile, byte[] pbKeyData) -#endif - { - Debug.Assert(strFile != null); - if(strFile == null) throw new ArgumentNullException("strFile"); - Debug.Assert(pbKeyData != null); - if(pbKeyData == null) throw new ArgumentNullException("pbKeyData"); - -#if ModernKeePassLib - IOConnectionInfo ioc = IOConnectionInfo.FromFile(strFile); -#else - IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile); -#endif - using(Stream s = IOConnection.OpenWrite(ioc)) - { - using(XmlWriter xw = XmlUtilEx.CreateXmlWriter(s)) - { - xw.WriteStartDocument(); - xw.WriteStartElement(RootElementName); // - - xw.WriteStartElement(MetaElementName); // - xw.WriteStartElement(VersionElementName); // - xw.WriteString("1.00"); - xw.WriteEndElement(); // - xw.WriteEndElement(); // - - xw.WriteStartElement(KeyElementName); // - - xw.WriteStartElement(KeyDataElementName); // - xw.WriteString(Convert.ToBase64String(pbKeyData)); - xw.WriteEndElement(); // - - xw.WriteEndElement(); // - - xw.WriteEndElement(); // - xw.WriteEndDocument(); - } - } - } - } -} diff --git a/ModernKeePassLib/Keys/KcpPassword.cs b/ModernKeePassLib/Keys/KcpPassword.cs deleted file mode 100644 index 940515c..0000000 --- a/ModernKeePassLib/Keys/KcpPassword.cs +++ /dev/null @@ -1,106 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; -using ModernKeePassLib.Cryptography; - -namespace ModernKeePassLib.Keys -{ - /// - /// Master password / passphrase as provided by the user. - /// - public sealed class KcpPassword : IUserKey - { - private ProtectedString m_psPassword; - private ProtectedBinary m_pbKeyData; - - /// - /// Get the password as protected string. - /// - public ProtectedString Password - { - get { return m_psPassword; } - } - - /// - /// Get key data. Querying this property is fast (it returns a - /// reference to a cached ProtectedBinary object). - /// If no key data is available, null is returned. - /// - public ProtectedBinary KeyData - { - get { return m_pbKeyData; } - } - - public KcpPassword(byte[] pbPasswordUtf8) - { - SetKey(pbPasswordUtf8); - } - - public KcpPassword(string strPassword) - { - SetKey(StrUtil.Utf8.GetBytes(strPassword)); - } - - private void SetKey(byte[] pbPasswordUtf8) - { - Debug.Assert(pbPasswordUtf8 != null); - if(pbPasswordUtf8 == null) throw new ArgumentNullException("pbPasswordUtf8"); - -#if (DEBUG && !KeePassLibSD) - Debug.Assert(ValidatePassword(pbPasswordUtf8)); -#endif - - byte[] pbRaw = CryptoUtil.HashSha256(pbPasswordUtf8); - - m_psPassword = new ProtectedString(true, pbPasswordUtf8); - m_pbKeyData = new ProtectedBinary(true, pbRaw); - } - - // public void Clear() - // { - // m_psPassword = null; - // m_pbKeyData = null; - // } - -#if (DEBUG && !KeePassLibSD) - private static bool ValidatePassword(byte[] pb) - { - try - { -#if ModernKeePassLib - // TODO: find a way to implement this - return true; -#else - string str = StrUtil.Utf8.GetString(pb); - return str.IsNormalized(NormalizationForm.FormC); -#endif - } - catch(Exception) { Debug.Assert(false); } - - return false; - } -#endif - } -} diff --git a/ModernKeePassLib/Keys/KcpUserAccount.cs b/ModernKeePassLib/Keys/KcpUserAccount.cs deleted file mode 100644 index 6e71bb0..0000000 --- a/ModernKeePassLib/Keys/KcpUserAccount.cs +++ /dev/null @@ -1,167 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Diagnostics; -using System.IO; -using System.Security; - -#if ModernKeePassLib -using Windows.Storage; -using Windows.Security.Cryptography; -#endif - -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Native; -using ModernKeePassLib.Resources; -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Keys -{ - /// - /// A user key depending on the currently logged on Windows user account. - /// - public sealed class KcpUserAccount : IUserKey - { - private ProtectedBinary m_pbKeyData = null; - - // Constant initialization vector (unique for KeePass) - private static readonly byte[] m_pbEntropy = new byte[] { - 0xDE, 0x13, 0x5B, 0x5F, 0x18, 0xA3, 0x46, 0x70, - 0xB2, 0x57, 0x24, 0x29, 0x69, 0x88, 0x98, 0xE6 - }; - - private const string UserKeyFileName = "ProtectedUserKey.bin"; - - /// - /// Get key data. Querying this property is fast (it returns a - /// reference to a cached ProtectedBinary object). - /// If no key data is available, null is returned. - /// - public ProtectedBinary KeyData - { - get { return m_pbKeyData; } - } - - /// - /// Construct a user account key. - /// - public KcpUserAccount() - { - if(!CryptoUtil.IsProtectedDataSupported) - throw new PlatformNotSupportedException(); // Windows 98/ME - - byte[] pbKey = LoadUserKey(false); - if(pbKey == null) pbKey = CreateUserKey(); - if(pbKey == null) // Should never happen - { - Debug.Assert(false); - throw new SecurityException(KLRes.UserAccountKeyError); - } - - m_pbKeyData = new ProtectedBinary(true, pbKey); - MemUtil.ZeroByteArray(pbKey); - } - - // public void Clear() - // { - // m_pbKeyData = null; - // } - - private static string GetUserKeyFilePath(bool bCreate) - { -#if ModernKeePassLib - string strUserDir = Windows.Storage.ApplicationData.Current.RoamingFolder.Path; -#else - string strUserDir = Environment.GetFolderPath( - Environment.SpecialFolder.ApplicationData); -#endif - - strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false); - strUserDir += PwDefs.ShortProductName; - -#if !ModernKeePassLib - - if(bCreate && !Directory.Exists(strUserDir)) - Directory.CreateDirectory(strUserDir); -#endif - - strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false); - return (strUserDir + UserKeyFileName); - } - - private static byte[] LoadUserKey(bool bThrow) - { - byte[] pbKey = null; - -#if !KeePassLibSD - try - { - string strFilePath = GetUserKeyFilePath(false); - -#if ModernKeePassLib - var fileStream = StorageFile.GetFileFromPathAsync(strFilePath).GetAwaiter().GetResult().OpenStreamForReadAsync().GetAwaiter().GetResult(); - var pbProtectedKey = new byte[(int)fileStream.Length]; - fileStream.Read(pbProtectedKey, 0, (int)fileStream.Length); - fileStream.Dispose(); -#else - byte[] pbProtectedKey = File.ReadAllBytes(strFilePath); -#endif - - pbKey = CryptoUtil.UnprotectData(pbProtectedKey, m_pbEntropy, - DataProtectionScope.CurrentUser); - } - catch(Exception) - { - if(bThrow) throw; - pbKey = null; - } -#endif - - return pbKey; - } - - private static byte[] CreateUserKey() - { -#if KeePassLibSD - return null; -#else - string strFilePath = GetUserKeyFilePath(true); - - byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64); - byte[] pbProtectedKey = CryptoUtil.ProtectData(pbRandomKey, - m_pbEntropy, DataProtectionScope.CurrentUser); -#if ModernKeePassLib - var fileStream = StorageFile.GetFileFromPathAsync(strFilePath).GetAwaiter().GetResult().OpenStreamForWriteAsync().GetAwaiter().GetResult(); - fileStream.Write(pbProtectedKey, 0, (int)fileStream.Length); - fileStream.Dispose(); -#else - File.WriteAllBytes(strFilePath, pbProtectedKey); -#endif - - byte[] pbKey = LoadUserKey(true); - Debug.Assert(MemUtil.ArraysEqual(pbKey, pbRandomKey)); - - MemUtil.ZeroByteArray(pbRandomKey); - return pbKey; -#endif - } - } -} diff --git a/ModernKeePassLib/Keys/KeyProvider.cs b/ModernKeePassLib/Keys/KeyProvider.cs deleted file mode 100644 index 812c77b..0000000 --- a/ModernKeePassLib/Keys/KeyProvider.cs +++ /dev/null @@ -1,152 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -using ModernKeePassLib.Serialization; - -namespace ModernKeePassLib.Keys -{ - public sealed class KeyProviderQueryContext - { - private IOConnectionInfo m_ioInfo; - public IOConnectionInfo DatabaseIOInfo - { - get { return m_ioInfo; } - } - - public string DatabasePath - { - get { return m_ioInfo.Path; } - } - - private bool m_bCreatingNewKey; - public bool CreatingNewKey - { - get { return m_bCreatingNewKey; } - } - - private bool m_bSecDesktop; - public bool IsOnSecureDesktop - { - get { return m_bSecDesktop; } - } - - public KeyProviderQueryContext(IOConnectionInfo ioInfo, bool bCreatingNewKey, - bool bOnSecDesktop) - { - if(ioInfo == null) throw new ArgumentNullException("ioInfo"); - - m_ioInfo = ioInfo.CloneDeep(); - m_bCreatingNewKey = bCreatingNewKey; - m_bSecDesktop = bOnSecDesktop; - } - } - - public abstract class KeyProvider - { - /// - /// Name of your key provider (should be unique). - /// - public abstract string Name - { - get; - } - - /// - /// Property indicating whether the provider is exclusive. - /// If the provider is exclusive, KeePass doesn't allow other - /// key sources (master password, Windows user account, ...) - /// to be combined with the provider. - /// Key providers typically should return false - /// (to allow non-exclusive use), i.e. don't override this - /// property. - /// - public virtual bool Exclusive - { - get { return false; } - } - - /// - /// Property that specifies whether the returned key data - /// gets hashed by KeePass first or is written directly to - /// the user key data stream. - /// Standard key provider plugins should return false - /// (i.e. don't overwrite this property). Returning true - /// may cause severe security problems and is highly - /// discouraged. - /// - public virtual bool DirectKey - { - get { return false; } - } - - // public virtual PwIcon ImageIndex - // { - // get { return PwIcon.UserKey; } - // } - - /// - /// This property specifies whether the GetKey method might - /// show a form or dialog. If there is any chance that the method shows - /// one, this property must return true. Only if it's guaranteed - /// that the GetKey method doesn't show any form or dialog, this - /// property should return false. - /// - public virtual bool GetKeyMightShowGui - { - get { return true; } - } - - /// - /// This property specifies whether the key provider is compatible - /// with the secure desktop mode. This almost never is the case, - /// so you usually won't override this property. - /// - public virtual bool SecureDesktopCompatible - { - get { return false; } - } - - public abstract byte[] GetKey(KeyProviderQueryContext ctx); - } - -#if DEBUG - public sealed class SampleKeyProvider : KeyProvider - { - public override string Name - { - get { return "Built-In Sample Key Provider"; } - } - - // Do not just copy this to your own key provider class! See above. - public override bool GetKeyMightShowGui - { - get { return false; } - } - - public override byte[] GetKey(KeyProviderQueryContext ctx) - { - return new byte[]{ 2, 3, 5, 7, 11, 13 }; - } - } -#endif -} diff --git a/ModernKeePassLib/Keys/KeyProviderPool.cs b/ModernKeePassLib/Keys/KeyProviderPool.cs deleted file mode 100644 index 06163a6..0000000 --- a/ModernKeePassLib/Keys/KeyProviderPool.cs +++ /dev/null @@ -1,105 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -namespace ModernKeePassLib.Keys -{ - public sealed class KeyProviderPool : IEnumerable - { - private List m_vProviders = new List(); - - public int Count - { - get { return m_vProviders.Count; } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return m_vProviders.GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - return m_vProviders.GetEnumerator(); - } - - public void Add(KeyProvider prov) - { - Debug.Assert(prov != null); if(prov == null) throw new ArgumentNullException("prov"); - - m_vProviders.Add(prov); - } - - public bool Remove(KeyProvider prov) - { - Debug.Assert(prov != null); if(prov == null) throw new ArgumentNullException("prov"); - - return m_vProviders.Remove(prov); - } - - public KeyProvider Get(string strProviderName) - { - if(strProviderName == null) throw new ArgumentNullException("strProviderName"); - - foreach(KeyProvider prov in m_vProviders) - { - if(prov.Name == strProviderName) return prov; - } - - return null; - } - - public bool IsKeyProvider(string strName) - { - Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); - - foreach(KeyProvider prov in m_vProviders) - { - if(prov.Name == strName) return true; - } - - return false; - } - - internal byte[] GetKey(string strProviderName, KeyProviderQueryContext ctx, - out bool bPerformHash) - { - Debug.Assert(strProviderName != null); if(strProviderName == null) throw new ArgumentNullException("strProviderName"); - - bPerformHash = true; - - foreach(KeyProvider prov in m_vProviders) - { - if(prov.Name == strProviderName) - { - bPerformHash = !prov.DirectKey; - return prov.GetKey(ctx); - } - } - - Debug.Assert(false); - return null; - } - } -} diff --git a/ModernKeePassLib/Keys/KeyValidator.cs b/ModernKeePassLib/Keys/KeyValidator.cs deleted file mode 100644 index df7fbd6..0000000 --- a/ModernKeePassLib/Keys/KeyValidator.cs +++ /dev/null @@ -1,51 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace ModernKeePassLib.Keys -{ - public enum KeyValidationType - { - MasterPassword = 0 - } - - public abstract class KeyValidator - { - /// - /// Name of your key validator (should be unique). - /// - public abstract string Name - { - get; - } - - /// - /// Validate a key. - /// - /// Key to validate. - /// Type of the validation to perform. - /// Returns null, if the validation is successful. - /// If there's a problem with the key, the returned string describes - /// the problem. - public abstract string Validate(string strKey, KeyValidationType t); - } -} diff --git a/ModernKeePassLib/Keys/KeyValidatorPool.cs b/ModernKeePassLib/Keys/KeyValidatorPool.cs deleted file mode 100644 index 66a0cd3..0000000 --- a/ModernKeePassLib/Keys/KeyValidatorPool.cs +++ /dev/null @@ -1,86 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Keys -{ - public sealed class KeyValidatorPool : IEnumerable - { - private List m_vValidators = new List(); - - public int Count - { - get { return m_vValidators.Count; } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return m_vValidators.GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - return m_vValidators.GetEnumerator(); - } - - public void Add(KeyValidator v) - { - Debug.Assert(v != null); if(v == null) throw new ArgumentNullException("v"); - - m_vValidators.Add(v); - } - - public bool Remove(KeyValidator v) - { - Debug.Assert(v != null); if(v == null) throw new ArgumentNullException("v"); - - return m_vValidators.Remove(v); - } - - public string Validate(string strKey, KeyValidationType t) - { - Debug.Assert(strKey != null); if(strKey == null) throw new ArgumentNullException("strKey"); - - foreach(KeyValidator v in m_vValidators) - { - string strResult = v.Validate(strKey, t); - if(strResult != null) return strResult; - } - - return null; - } - - public string Validate(byte[] pbKeyUtf8, KeyValidationType t) - { - Debug.Assert(pbKeyUtf8 != null); if(pbKeyUtf8 == null) throw new ArgumentNullException("pbKeyUtf8"); - - if(m_vValidators.Count == 0) return null; - - string strKey = StrUtil.Utf8.GetString(pbKeyUtf8, 0, pbKeyUtf8.Length); - return Validate(strKey, t); - } - } -} diff --git a/ModernKeePassLib/Keys/UserKeyType.cs b/ModernKeePassLib/Keys/UserKeyType.cs deleted file mode 100644 index ad8f84e..0000000 --- a/ModernKeePassLib/Keys/UserKeyType.cs +++ /dev/null @@ -1,33 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; - -namespace ModernKeePassLib.Keys -{ - [Flags] - public enum UserKeyType - { - None = 0, - Other = 1, - Password = 2, - KeyFile = 4, - UserAccount = 8 - } -} diff --git a/ModernKeePassLib/ModernKeePass.Lib.csproj b/ModernKeePassLib/ModernKeePass.Lib.csproj deleted file mode 100644 index 0865971..0000000 --- a/ModernKeePassLib/ModernKeePass.Lib.csproj +++ /dev/null @@ -1,188 +0,0 @@ - - - - Debug - AnyCPU - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {2E710089-9559-4967-846C-E763DD1F3ACB} - Library - Properties - ModernKeePassLib - ModernKeePassLib - false - - - 2.0 - - - - - v5.0 - KeePassLib.pfx - - - 14.0 - - - true - full - false - bin\Debug - DEBUG;ModernKeePassLib - prompt - 4 - AnyCPU - - - true - bin\Release - prompt - 4 - ModernKeePassLib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - Libs\Windows.winmd - False - - - - \ No newline at end of file diff --git a/ModernKeePassLib/ModernKeePassLib.nuget.targets b/ModernKeePassLib/ModernKeePassLib.nuget.targets deleted file mode 100644 index a00610d..0000000 --- a/ModernKeePassLib/ModernKeePassLib.nuget.targets +++ /dev/null @@ -1,9 +0,0 @@ - - - - $(UserProfile)\.nuget\packages\ - - - - - \ No newline at end of file diff --git a/ModernKeePassLib/ModernKeePassLib.nuspec b/ModernKeePassLib/ModernKeePassLib.nuspec deleted file mode 100644 index e6e594b..0000000 --- a/ModernKeePassLib/ModernKeePassLib.nuspec +++ /dev/null @@ -1,36 +0,0 @@ - - - - ModernKeePassLib - 2.39.1 - ModernKeePassLib - Geoffroy Bonneville - Geoffroy Bonneville - https://www.gnu.org/licenses/gpl-3.0.en.html - https://github.com/wismna/ModernKeePass - false - Portable KeePass Password Management Library that targets .Net Standard and WinRT. Allows reading, editing and writing to KeePass 2.x databases. - Implementation of KeePass library version 2.39.1 - Copyright © 2018 Geoffroy Bonneville - KeePass KeePassLib Portable PCL NetStandard - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ModernKeePassLib/ModernKeePassLibPCL.nuget.targets b/ModernKeePassLib/ModernKeePassLibPCL.nuget.targets deleted file mode 100644 index 8930d73..0000000 --- a/ModernKeePassLib/ModernKeePassLibPCL.nuget.targets +++ /dev/null @@ -1,9 +0,0 @@ - - - - $(UserProfile)\.nuget\packages\ - - - - - \ No newline at end of file diff --git a/ModernKeePassLib/Native/ClipboardU.cs b/ModernKeePassLib/Native/ClipboardU.cs deleted file mode 100644 index 87760b4..0000000 --- a/ModernKeePassLib/Native/ClipboardU.cs +++ /dev/null @@ -1,190 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Reflection; -using System.Text; - -namespace ModernKeePassLib.Native -{ - internal static class ClipboardU - { - private const string XSel = "xsel"; - private const string XSelV = "--version"; - private const string XSelR = "--output --clipboard"; - private const string XSelC = "--clear --clipboard"; - private const string XSelW = "--input --clipboard"; - private const string XSelND = " --nodetach"; - private const AppRunFlags XSelWF = AppRunFlags.WaitForExit; - - private static bool? g_obXSel = null; - - public static string GetText() - { - // System.Windows.Forms.Clipboard doesn't work properly, - // see Mono workaround 1530 - - // string str = GtkGetText(); - // if(str != null) return str; - - return XSelGetText(); - } - - public static bool SetText(string strText, bool bMayBlock) - { - string str = (strText ?? string.Empty); - - // System.Windows.Forms.Clipboard doesn't work properly, - // see Mono workaround 1530 - - // if(GtkSetText(str)) return true; - - return XSelSetText(str, bMayBlock); - } - - // ============================================================= - // LibGTK - - // Even though GTK+ 3 appears to be loaded already, performing a - // P/Invoke of LibGTK's gtk_init_check function terminates the - // process (!) with the following error message: - // "Gtk-ERROR **: GTK+ 2.x symbols detected. Using GTK+ 2.x and - // GTK+ 3 in the same process is not supported". - - /* private static bool GtkInit() - { - try - { - // GTK requires GLib; - // the following throws if and only if GLib is unavailable - NativeMethods.g_free(IntPtr.Zero); - - if(NativeMethods.gtk_init_check(IntPtr.Zero, IntPtr.Zero) != - NativeMethods.G_FALSE) - return true; - - Debug.Assert(false); - } - catch(Exception) { Debug.Assert(false); } - - return false; - } - - private static string GtkGetText() - { - IntPtr lpText = IntPtr.Zero; - try - { - if(GtkInit()) - { - IntPtr h = NativeMethods.gtk_clipboard_get( - NativeMethods.GDK_SELECTION_CLIPBOARD); - if(h != IntPtr.Zero) - { - lpText = NativeMethods.gtk_clipboard_wait_for_text(h); - if(lpText != IntPtr.Zero) - return NativeMethods.Utf8ZToString(lpText); - } - } - } - catch(Exception) { Debug.Assert(false); } - finally - { - try { NativeMethods.g_free(lpText); } - catch(Exception) { Debug.Assert(false); } - } - - return null; - } - - private static bool GtkSetText(string str) - { - IntPtr lpText = IntPtr.Zero; - try - { - if(GtkInit()) - { - lpText = NativeMethods.Utf8ZFromString(str ?? string.Empty); - if(lpText == IntPtr.Zero) { Debug.Assert(false); return false; } - - bool b = false; - for(int i = 0; i < 2; ++i) - { - IntPtr h = NativeMethods.gtk_clipboard_get((i == 0) ? - NativeMethods.GDK_SELECTION_PRIMARY : - NativeMethods.GDK_SELECTION_CLIPBOARD); - if(h != IntPtr.Zero) - { - NativeMethods.gtk_clipboard_clear(h); - NativeMethods.gtk_clipboard_set_text(h, lpText, -1); - NativeMethods.gtk_clipboard_store(h); - b = true; - } - } - - return b; - } - } - catch(Exception) { Debug.Assert(false); } - finally { NativeMethods.Utf8ZFree(lpText); } - - return false; - } */ - - // ============================================================= - // XSel - - private static bool XSelInit() - { - if(g_obXSel.HasValue) return g_obXSel.Value; - - string strTest = NativeLib.RunConsoleApp(XSel, XSelV); - - bool b = (strTest != null); - g_obXSel = b; - return b; - } - - private static string XSelGetText() - { - if(!XSelInit()) return null; - - return NativeLib.RunConsoleApp(XSel, XSelR); - } - - private static bool XSelSetText(string str, bool bMayBlock) - { - if(!XSelInit()) return false; - - string strOpt = (bMayBlock ? XSelND : string.Empty); - - // xsel with an empty input can hang, thus use --clear - if(str.Length == 0) - return (NativeLib.RunConsoleApp(XSel, XSelC + strOpt, - null, XSelWF) != null); - - // Use --nodetach to prevent clipboard corruption; - // https://sourceforge.net/p/keepass/bugs/1603/ - return (NativeLib.RunConsoleApp(XSel, XSelW + strOpt, - str, XSelWF) != null); - } - } -} diff --git a/ModernKeePassLib/Native/Native.PCL.cs b/ModernKeePassLib/Native/Native.PCL.cs deleted file mode 100644 index a9a777c..0000000 --- a/ModernKeePassLib/Native/Native.PCL.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; - -using PlatformID = System.UInt32; - -namespace ModernKeePassLib.Native -{ - internal static class NativeLib - { - public static ulong MonoVersion { - get { throw new NotImplementedException(); } - } - - public static bool IsUnix() - { - return true; - } - } - - internal static class NativeMethods - { - public static bool SupportsStrCmpNaturally => false; - - internal const int GCRY_CIPHER_AES256 = 9; - internal const int GCRY_CIPHER_MODE_ECB = 1; - - public static int StrCmpNaturally (string s1, string s2) - { - throw new NotImplementedException(); - } - - internal static void gcry_check_version(IntPtr zero) - { - throw new NotImplementedException(); - } - - public static void gcry_cipher_open(ref IntPtr intPtr, object gcryCipherAes256, object gcryCipherModeEcb, int i) - { - throw new NotImplementedException(); - } - - internal static int gcry_cipher_setkey(IntPtr h, IntPtr pSeed32, IntPtr n32) - { - throw new NotImplementedException(); - } - - internal static void gcry_cipher_close(IntPtr h) - { - throw new NotImplementedException(); - } - - internal static int gcry_cipher_encrypt(IntPtr h, IntPtr pData32, IntPtr n32, IntPtr zero1, IntPtr zero2) - { - throw new NotImplementedException(); - } - - public static string GetUserRuntimeDir() - { - throw new NotImplementedException(); - } - } - - public enum DataProtectionScope - { - CurrentUser, - LocalMachine - } - - internal enum MemoryProtectionScope - { - CrossProcess, - SameLogon, - SameProcess - } - - internal static class ProtectedMemory - { - public static byte[] Protect(byte[] userData, MemoryProtectionScope scope) - { - throw new NotImplementedException(); - } - - public static byte[] Unprotect(byte[] userData, MemoryProtectionScope scope) - { - throw new NotImplementedException(); - } - } -} - diff --git a/ModernKeePassLib/Native/NativeLib.cs b/ModernKeePassLib/Native/NativeLib.cs deleted file mode 100644 index bfaee1e..0000000 --- a/ModernKeePassLib/Native/NativeLib.cs +++ /dev/null @@ -1,449 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.RegularExpressions; - -#if !KeePassUAP -using System.IO; -using System.Threading; -using System.Windows.Forms; -#endif - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Native -{ - /// - /// Interface to native library (library containing fast versions of - /// several cryptographic functions). - /// - public static class NativeLib - { - private static bool m_bAllowNative = true; - - /// - /// If this property is set to true, the native library is used. - /// If it is false, all calls to functions in this class will fail. - /// - public static bool AllowNative - { - get { return m_bAllowNative; } - set { m_bAllowNative = value; } - } - - private static ulong? m_ouMonoVersion = null; - public static ulong MonoVersion - { - get - { - if(m_ouMonoVersion.HasValue) return m_ouMonoVersion.Value; - - ulong uVersion = 0; - try - { - Type t = Type.GetType("Mono.Runtime"); - if(t != null) - { - MethodInfo mi = t.GetMethod("GetDisplayName", - BindingFlags.NonPublic | BindingFlags.Static); - if(mi != null) - { - string strName = (mi.Invoke(null, null) as string); - if(!string.IsNullOrEmpty(strName)) - { - Match m = Regex.Match(strName, "\\d+(\\.\\d+)+"); - if(m.Success) - uVersion = StrUtil.ParseVersion(m.Value); - else { Debug.Assert(false); } - } - else { Debug.Assert(false); } - } - else { Debug.Assert(false); } - } - } - catch(Exception) { Debug.Assert(false); } - - m_ouMonoVersion = uVersion; - return uVersion; - } - } - - /// - /// Determine if the native library is installed. - /// - /// Returns true, if the native library is installed. - public static bool IsLibraryInstalled() - { - byte[] pDummy0 = new byte[32]; - byte[] pDummy1 = new byte[32]; - - // Save the native state - bool bCachedNativeState = m_bAllowNative; - - // Temporarily allow native functions and try to load the library - m_bAllowNative = true; - bool bResult = TransformKey256(pDummy0, pDummy1, 16); - - // Pop native state and return result - m_bAllowNative = bCachedNativeState; - return bResult; - } - - private static bool? m_bIsUnix = null; - public static bool IsUnix() - { - if(m_bIsUnix.HasValue) return m_bIsUnix.Value; - - PlatformID p = GetPlatformID(); - - // Mono defines Unix as 128 in early .NET versions -#if !KeePassLibSD - m_bIsUnix = ((p == PlatformID.Unix) || (p == PlatformID.MacOSX) || - ((int)p == 128)); -#else - m_bIsUnix = (((int)p == 4) || ((int)p == 6) || ((int)p == 128)); -#endif - return m_bIsUnix.Value; - } - - private static PlatformID? m_platID = null; - public static PlatformID GetPlatformID() - { - if(m_platID.HasValue) return m_platID.Value; - -#if KeePassUAP - m_platID = EnvironmentExt.OSVersion.Platform; -#else - m_platID = Environment.OSVersion.Platform; -#endif - -#if (!KeePassLibSD && !KeePassUAP) - // Mono returns PlatformID.Unix on Mac OS X, workaround this - if(m_platID.Value == PlatformID.Unix) - { - if((RunConsoleApp("uname", null) ?? string.Empty).Trim().Equals( - "Darwin", StrUtil.CaseIgnoreCmp)) - m_platID = PlatformID.MacOSX; - } -#endif - - return m_platID.Value; - } - - private static DesktopType? m_tDesktop = null; - public static DesktopType GetDesktopType() - { - if(!m_tDesktop.HasValue) - { - DesktopType t = DesktopType.None; - if(!IsUnix()) t = DesktopType.Windows; - else - { - try - { - string strXdg = (Environment.GetEnvironmentVariable( - "XDG_CURRENT_DESKTOP") ?? string.Empty).Trim(); - string strGdm = (Environment.GetEnvironmentVariable( - "GDMSESSION") ?? string.Empty).Trim(); - StringComparison sc = StrUtil.CaseIgnoreCmp; - - if(strXdg.Equals("Unity", sc)) - t = DesktopType.Unity; - else if(strXdg.Equals("LXDE", sc)) - t = DesktopType.Lxde; - else if(strXdg.Equals("XFCE", sc)) - t = DesktopType.Xfce; - else if(strXdg.Equals("MATE", sc)) - t = DesktopType.Mate; - else if(strXdg.Equals("X-Cinnamon", sc)) // Mint 18.3 - t = DesktopType.Cinnamon; - else if(strXdg.Equals("Pantheon", sc)) // Elementary OS - t = DesktopType.Pantheon; - else if(strXdg.Equals("KDE", sc) || // Mint 16, Kubuntu 17.10 - strGdm.Equals("kde-plasma", sc)) // Ubuntu 12.04 - t = DesktopType.Kde; - else if(strXdg.Equals("GNOME", sc)) - { - if(strGdm.Equals("cinnamon", sc)) // Mint 13 - t = DesktopType.Cinnamon; - else t = DesktopType.Gnome; // Fedora 27 - } - else if(strXdg.Equals("ubuntu:GNOME", sc)) - t = DesktopType.Gnome; - } - catch(Exception) { Debug.Assert(false); } - } - - m_tDesktop = t; - } - - return m_tDesktop.Value; - } - -#if (!KeePassLibSD && !KeePassUAP) - public static string RunConsoleApp(string strAppPath, string strParams) - { - return RunConsoleApp(strAppPath, strParams, null); - } - - public static string RunConsoleApp(string strAppPath, string strParams, - string strStdInput) - { - return RunConsoleApp(strAppPath, strParams, strStdInput, - (AppRunFlags.GetStdOutput | AppRunFlags.WaitForExit)); - } - - private delegate string RunProcessDelegate(); - - public static string RunConsoleApp(string strAppPath, string strParams, - string strStdInput, AppRunFlags f) - { - if(strAppPath == null) throw new ArgumentNullException("strAppPath"); - if(strAppPath.Length == 0) throw new ArgumentException("strAppPath"); - - bool bStdOut = ((f & AppRunFlags.GetStdOutput) != AppRunFlags.None); - - RunProcessDelegate fnRun = delegate() - { - Process pToDispose = null; - try - { - ProcessStartInfo psi = new ProcessStartInfo(); - - psi.CreateNoWindow = true; - psi.FileName = strAppPath; - psi.WindowStyle = ProcessWindowStyle.Hidden; - psi.UseShellExecute = false; - psi.RedirectStandardOutput = bStdOut; - - if(strStdInput != null) psi.RedirectStandardInput = true; - - if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams; - - Process p = Process.Start(psi); - pToDispose = p; - - if(strStdInput != null) - { - EnsureNoBom(p.StandardInput); - - p.StandardInput.Write(strStdInput); - p.StandardInput.Close(); - } - - string strOutput = string.Empty; - if(bStdOut) strOutput = p.StandardOutput.ReadToEnd(); - - if((f & AppRunFlags.WaitForExit) != AppRunFlags.None) - p.WaitForExit(); - else if((f & AppRunFlags.GCKeepAlive) != AppRunFlags.None) - { - pToDispose = null; // Thread disposes it - - Thread th = new Thread(delegate() - { - try { p.WaitForExit(); p.Dispose(); } - catch(Exception) { Debug.Assert(false); } - }); - th.Start(); - } - - return strOutput; - } -#if DEBUG - catch(Exception ex) { Debug.Assert(ex is ThreadAbortException); } -#else - catch(Exception) { } -#endif - finally - { - try { if(pToDispose != null) pToDispose.Dispose(); } - catch(Exception) { Debug.Assert(false); } - } - - return null; - }; - - if((f & AppRunFlags.DoEvents) != AppRunFlags.None) - { - List
lDisabledForms = new List(); - if((f & AppRunFlags.DisableForms) != AppRunFlags.None) - { - foreach(Form form in Application.OpenForms) - { - if(!form.Enabled) continue; - - lDisabledForms.Add(form); - form.Enabled = false; - } - } - - IAsyncResult ar = fnRun.BeginInvoke(null, null); - - while(!ar.AsyncWaitHandle.WaitOne(0)) - { - Application.DoEvents(); - Thread.Sleep(2); - } - - string strRet = fnRun.EndInvoke(ar); - - for(int i = lDisabledForms.Count - 1; i >= 0; --i) - lDisabledForms[i].Enabled = true; - - return strRet; - } - - return fnRun(); - } - - private static void EnsureNoBom(StreamWriter sw) - { - if(sw == null) { Debug.Assert(false); return; } - if(!MonoWorkarounds.IsRequired(1219)) return; - - try - { - Encoding enc = sw.Encoding; - if(enc == null) { Debug.Assert(false); return; } - byte[] pbBom = enc.GetPreamble(); - if((pbBom == null) || (pbBom.Length == 0)) return; - - // For Mono >= 4.0 (using Microsoft's reference source) - try - { - FieldInfo fi = typeof(StreamWriter).GetField("haveWrittenPreamble", - BindingFlags.Instance | BindingFlags.NonPublic); - if(fi != null) - { - fi.SetValue(sw, true); - return; - } - } - catch(Exception) { Debug.Assert(false); } - - // For Mono < 4.0 - FieldInfo fiPD = typeof(StreamWriter).GetField("preamble_done", - BindingFlags.Instance | BindingFlags.NonPublic); - if(fiPD != null) fiPD.SetValue(sw, true); - else { Debug.Assert(false); } - } - catch(Exception) { Debug.Assert(false); } - } -#endif - - /// - /// Transform a key. - /// - /// Source and destination buffer. - /// Key to use in the transformation. - /// Number of transformation rounds. - /// Returns true, if the key was transformed successfully. - public static bool TransformKey256(byte[] pBuf256, byte[] pKey256, - ulong uRounds) - { -#if KeePassUAP - return false; -#else - if(!m_bAllowNative) return false; - - KeyValuePair kvp = PrepareArrays256(pBuf256, pKey256); - bool bResult = false; - - try - { - bResult = NativeMethods.TransformKey(kvp.Key, kvp.Value, uRounds); - } - catch(Exception) { bResult = false; } - - if(bResult) GetBuffers256(kvp, pBuf256, pKey256); - - FreeArrays(kvp); - return bResult; -#endif - } - - /// - /// Benchmark key transformation. - /// - /// Number of milliseconds to perform the benchmark. - /// Number of transformations done. - /// Returns true, if the benchmark was successful. - public static bool TransformKeyBenchmark256(uint uTimeMs, out ulong puRounds) - { - puRounds = 0; - -#if KeePassUAP - return false; -#else - if(!m_bAllowNative) return false; - - try { puRounds = NativeMethods.TransformKeyBenchmark(uTimeMs); } - catch(Exception) { return false; } - - return true; -#endif - } - - private static KeyValuePair PrepareArrays256(byte[] pBuf256, - byte[] pKey256) - { - Debug.Assert((pBuf256 != null) && (pBuf256.Length == 32)); - if(pBuf256 == null) throw new ArgumentNullException("pBuf256"); - if(pBuf256.Length != 32) throw new ArgumentException(); - - Debug.Assert((pKey256 != null) && (pKey256.Length == 32)); - if(pKey256 == null) throw new ArgumentNullException("pKey256"); - if(pKey256.Length != 32) throw new ArgumentException(); - - IntPtr hBuf = Marshal.AllocHGlobal(pBuf256.Length); - Marshal.Copy(pBuf256, 0, hBuf, pBuf256.Length); - - IntPtr hKey = Marshal.AllocHGlobal(pKey256.Length); - Marshal.Copy(pKey256, 0, hKey, pKey256.Length); - - return new KeyValuePair(hBuf, hKey); - } - - private static void GetBuffers256(KeyValuePair kvpSource, - byte[] pbDestBuf, byte[] pbDestKey) - { - if(kvpSource.Key != IntPtr.Zero) - Marshal.Copy(kvpSource.Key, pbDestBuf, 0, pbDestBuf.Length); - - if(kvpSource.Value != IntPtr.Zero) - Marshal.Copy(kvpSource.Value, pbDestKey, 0, pbDestKey.Length); - } - - private static void FreeArrays(KeyValuePair kvpPointers) - { - if(kvpPointers.Key != IntPtr.Zero) - Marshal.FreeHGlobal(kvpPointers.Key); - - if(kvpPointers.Value != IntPtr.Zero) - Marshal.FreeHGlobal(kvpPointers.Value); - } - } -} diff --git a/ModernKeePassLib/Native/NativeMethods.Unix.cs b/ModernKeePassLib/Native/NativeMethods.Unix.cs deleted file mode 100644 index 04a8b99..0000000 --- a/ModernKeePassLib/Native/NativeMethods.Unix.cs +++ /dev/null @@ -1,216 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; - -#if !KeePassUAP -using System.Windows.Forms; -#endif - -namespace ModernKeePassLib.Native -{ - internal static partial class NativeMethods - { -#if (!KeePassLibSD && !KeePassUAP) - [StructLayout(LayoutKind.Sequential)] - private struct XClassHint - { - public IntPtr res_name; - public IntPtr res_class; - } - - [DllImport("libX11")] - private static extern int XSetClassHint(IntPtr display, IntPtr window, IntPtr class_hints); - - private static Type m_tXplatUIX11 = null; - private static Type GetXplatUIX11Type(bool bThrowOnError) - { - if(m_tXplatUIX11 == null) - { - // CheckState is in System.Windows.Forms - string strTypeCS = typeof(CheckState).AssemblyQualifiedName; - string strTypeX11 = strTypeCS.Replace("CheckState", "XplatUIX11"); - m_tXplatUIX11 = Type.GetType(strTypeX11, bThrowOnError, true); - } - - return m_tXplatUIX11; - } - - private static Type m_tHwnd = null; - private static Type GetHwndType(bool bThrowOnError) - { - if(m_tHwnd == null) - { - // CheckState is in System.Windows.Forms - string strTypeCS = typeof(CheckState).AssemblyQualifiedName; - string strTypeHwnd = strTypeCS.Replace("CheckState", "Hwnd"); - m_tHwnd = Type.GetType(strTypeHwnd, bThrowOnError, true); - } - - return m_tHwnd; - } - - internal static void SetWmClass(Form f, string strName, string strClass) - { - if(f == null) { Debug.Assert(false); return; } - - // The following crashes under Mac OS X (SIGSEGV in native code, - // not just an exception), thus skip it when we're on Mac OS X; - // https://sourceforge.net/projects/keepass/forums/forum/329221/topic/5860588 - if(NativeLib.GetPlatformID() == PlatformID.MacOSX) return; - - try - { - Type tXplatUIX11 = GetXplatUIX11Type(true); - FieldInfo fiDisplayHandle = tXplatUIX11.GetField("DisplayHandle", - BindingFlags.NonPublic | BindingFlags.Static); - IntPtr hDisplay = (IntPtr)fiDisplayHandle.GetValue(null); - - Type tHwnd = GetHwndType(true); - MethodInfo miObjectFromHandle = tHwnd.GetMethod("ObjectFromHandle", - BindingFlags.Public | BindingFlags.Static); - object oHwnd = miObjectFromHandle.Invoke(null, new object[] { f.Handle }); - - FieldInfo fiWholeWindow = tHwnd.GetField("whole_window", - BindingFlags.NonPublic | BindingFlags.Instance); - IntPtr hWindow = (IntPtr)fiWholeWindow.GetValue(oHwnd); - - XClassHint xch = new XClassHint(); - xch.res_name = Marshal.StringToCoTaskMemAnsi(strName ?? string.Empty); - xch.res_class = Marshal.StringToCoTaskMemAnsi(strClass ?? string.Empty); - IntPtr pXch = Marshal.AllocCoTaskMem(Marshal.SizeOf(xch)); - Marshal.StructureToPtr(xch, pXch, false); - - XSetClassHint(hDisplay, hWindow, pXch); - - Marshal.FreeCoTaskMem(pXch); - Marshal.FreeCoTaskMem(xch.res_name); - Marshal.FreeCoTaskMem(xch.res_class); - } - catch(Exception) { Debug.Assert(false); } - } -#endif - - // ============================================================= - // LibGCrypt 1.8.1 - - private const string LibGCrypt = "libgcrypt.so.20"; - - internal const int GCRY_CIPHER_AES256 = 9; - internal const int GCRY_CIPHER_MODE_ECB = 1; - - [DllImport(LibGCrypt)] - internal static extern IntPtr gcry_check_version(IntPtr lpReqVersion); - - [DllImport(LibGCrypt)] - internal static extern uint gcry_cipher_open(ref IntPtr ph, int nAlgo, - int nMode, uint uFlags); - - [DllImport(LibGCrypt)] - internal static extern void gcry_cipher_close(IntPtr h); - - [DllImport(LibGCrypt)] - internal static extern uint gcry_cipher_setkey(IntPtr h, IntPtr pbKey, - IntPtr cbKey); // cbKey is size_t - - [DllImport(LibGCrypt)] - internal static extern uint gcry_cipher_encrypt(IntPtr h, IntPtr pbOut, - IntPtr cbOut, IntPtr pbIn, IntPtr cbIn); // cb* are size_t - - /* internal static IntPtr Utf8ZFromString(string str) - { - byte[] pb = StrUtil.Utf8.GetBytes(str ?? string.Empty); - - IntPtr p = Marshal.AllocCoTaskMem(pb.Length + 1); - if(p != IntPtr.Zero) - { - Marshal.Copy(pb, 0, p, pb.Length); - Marshal.WriteByte(p, pb.Length, 0); - } - else { Debug.Assert(false); } - - return p; - } - - internal static string Utf8ZToString(IntPtr p) - { - if(p == IntPtr.Zero) { Debug.Assert(false); return null; } - - List l = new List(); - for(int i = 0; i < int.MaxValue; ++i) - { - byte bt = Marshal.ReadByte(p, i); - if(bt == 0) break; - - l.Add(bt); - } - - return StrUtil.Utf8.GetString(l.ToArray()); - } - - internal static void Utf8ZFree(IntPtr p) - { - if(p != IntPtr.Zero) Marshal.FreeCoTaskMem(p); - } */ - - /* // ============================================================= - // LibGLib 2 - - private const string LibGLib = "libglib-2.0.so.0"; - - internal const int G_FALSE = 0; - - // https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html - [DllImport(LibGLib)] - internal static extern void g_free(IntPtr pMem); // pMem may be null - - // ============================================================= - // LibGTK 3 (3.22.11 / 3.22.24) - - private const string LibGtk = "libgtk-3.so.0"; - - internal static readonly IntPtr GDK_SELECTION_PRIMARY = new IntPtr(1); - internal static readonly IntPtr GDK_SELECTION_CLIPBOARD = new IntPtr(69); - - [DllImport(LibGtk)] - internal static extern int gtk_init_check(IntPtr pArgc, IntPtr pArgv); - - [DllImport(LibGtk)] - // The returned handle is owned by GTK and must not be freed - internal static extern IntPtr gtk_clipboard_get(IntPtr pSelection); - - [DllImport(LibGtk)] - internal static extern void gtk_clipboard_clear(IntPtr hClipboard); - - [DllImport(LibGtk)] - internal static extern IntPtr gtk_clipboard_wait_for_text(IntPtr hClipboard); - - [DllImport(LibGtk)] - internal static extern void gtk_clipboard_set_text(IntPtr hClipboard, - IntPtr lpText, int cbLen); - - [DllImport(LibGtk)] - internal static extern void gtk_clipboard_store(IntPtr hClipboard); */ - } -} diff --git a/ModernKeePassLib/Native/NativeMethods.cs b/ModernKeePassLib/Native/NativeMethods.cs deleted file mode 100644 index c6fbdeb..0000000 --- a/ModernKeePassLib/Native/NativeMethods.cs +++ /dev/null @@ -1,260 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using System.Text; - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Native -{ - internal static partial class NativeMethods - { - internal const int MAX_PATH = 260; - - internal const long INVALID_HANDLE_VALUE = -1; - - internal const uint MOVEFILE_REPLACE_EXISTING = 0x00000001; - internal const uint MOVEFILE_COPY_ALLOWED = 0x00000002; - - internal const uint FILE_SUPPORTS_TRANSACTIONS = 0x00200000; - internal const int MAX_TRANSACTION_DESCRIPTION_LENGTH = 64; - - // internal const uint TF_SFT_SHOWNORMAL = 0x00000001; - // internal const uint TF_SFT_HIDDEN = 0x00000008; - - /* [DllImport("KeePassNtv32.dll", EntryPoint = "TransformKey")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool TransformKey32(IntPtr pBuf256, - IntPtr pKey256, UInt64 uRounds); - - [DllImport("KeePassNtv64.dll", EntryPoint = "TransformKey")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool TransformKey64(IntPtr pBuf256, - IntPtr pKey256, UInt64 uRounds); - - internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256, - UInt64 uRounds) - { - if(IntPtr.Size == 4) - return TransformKey32(pBuf256, pKey256, uRounds); - return TransformKey64(pBuf256, pKey256, uRounds); - } - - [DllImport("KeePassNtv32.dll", EntryPoint = "TransformKeyTimed")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool TransformKeyTimed32(IntPtr pBuf256, - IntPtr pKey256, ref UInt64 puRounds, UInt32 uSeconds); - - [DllImport("KeePassNtv64.dll", EntryPoint = "TransformKeyTimed")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool TransformKeyTimed64(IntPtr pBuf256, - IntPtr pKey256, ref UInt64 puRounds, UInt32 uSeconds); - - internal static bool TransformKeyTimed(IntPtr pBuf256, IntPtr pKey256, - ref UInt64 puRounds, UInt32 uSeconds) - { - if(IntPtr.Size == 4) - return TransformKeyTimed32(pBuf256, pKey256, ref puRounds, uSeconds); - return TransformKeyTimed64(pBuf256, pKey256, ref puRounds, uSeconds); - } */ - -#if !KeePassUAP - [DllImport("KeePassLibC32.dll", EntryPoint = "TransformKey256")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool TransformKey32(IntPtr pBuf256, - IntPtr pKey256, UInt64 uRounds); - - [DllImport("KeePassLibC64.dll", EntryPoint = "TransformKey256")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool TransformKey64(IntPtr pBuf256, - IntPtr pKey256, UInt64 uRounds); - - internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256, - UInt64 uRounds) - { - if(IntPtr.Size == 4) - return TransformKey32(pBuf256, pKey256, uRounds); - return TransformKey64(pBuf256, pKey256, uRounds); - } - - [DllImport("KeePassLibC32.dll", EntryPoint = "TransformKeyBenchmark256")] - private static extern UInt64 TransformKeyBenchmark32(UInt32 uTimeMs); - - [DllImport("KeePassLibC64.dll", EntryPoint = "TransformKeyBenchmark256")] - private static extern UInt64 TransformKeyBenchmark64(UInt32 uTimeMs); - - internal static UInt64 TransformKeyBenchmark(UInt32 uTimeMs) - { - if(IntPtr.Size == 4) - return TransformKeyBenchmark32(uTimeMs); - return TransformKeyBenchmark64(uTimeMs); - } -#endif - - /* [DllImport("KeePassLibC32.dll", EntryPoint = "TF_ShowLangBar")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool TF_ShowLangBar32(UInt32 dwFlags); - - [DllImport("KeePassLibC64.dll", EntryPoint = "TF_ShowLangBar")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool TF_ShowLangBar64(UInt32 dwFlags); - - internal static bool TfShowLangBar(uint dwFlags) - { - if(IntPtr.Size == 4) return TF_ShowLangBar32(dwFlags); - return TF_ShowLangBar64(dwFlags); - } */ - - [DllImport("KeePassLibC32.dll", EntryPoint = "ProtectProcessWithDacl")] - private static extern void ProtectProcessWithDacl32(); - - [DllImport("KeePassLibC64.dll", EntryPoint = "ProtectProcessWithDacl")] - private static extern void ProtectProcessWithDacl64(); - - internal static void ProtectProcessWithDacl() - { - try - { - if(NativeLib.IsUnix()) return; - - if(IntPtr.Size == 4) ProtectProcessWithDacl32(); - else ProtectProcessWithDacl64(); - } - catch(Exception) { Debug.Assert(false); } - } - - [DllImport("Kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool CloseHandle(IntPtr hObject); - - [DllImport("Kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false, - SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool GetVolumeInformation(string lpRootPathName, - StringBuilder lpVolumeNameBuffer, UInt32 nVolumeNameSize, - ref UInt32 lpVolumeSerialNumber, ref UInt32 lpMaximumComponentLength, - ref UInt32 lpFileSystemFlags, StringBuilder lpFileSystemNameBuffer, - UInt32 nFileSystemNameSize); - - [DllImport("Kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false, - SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool MoveFileEx(string lpExistingFileName, - string lpNewFileName, UInt32 dwFlags); - - [DllImport("KtmW32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, - SetLastError = true)] - internal static extern IntPtr CreateTransaction(IntPtr lpTransactionAttributes, - IntPtr lpUOW, UInt32 dwCreateOptions, UInt32 dwIsolationLevel, - UInt32 dwIsolationFlags, UInt32 dwTimeout, string lpDescription); - - [DllImport("KtmW32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool CommitTransaction(IntPtr hTransaction); - - [DllImport("Kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false, - SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool MoveFileTransacted(string lpExistingFileName, - string lpNewFileName, IntPtr lpProgressRoutine, IntPtr lpData, - UInt32 dwFlags, IntPtr hTransaction); - -#if (!KeePassLibSD && !KeePassUAP) - [DllImport("ShlWApi.dll", CharSet = CharSet.Auto)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool PathRelativePathTo([Out] StringBuilder pszPath, - [In] string pszFrom, uint dwAttrFrom, [In] string pszTo, uint dwAttrTo); - - [DllImport("ShlWApi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] - private static extern int StrCmpLogicalW(string x, string y); - - private static bool? m_obSupportsLogicalCmp = null; - - private static void TestNaturalComparisonsSupport() - { - try - { - StrCmpLogicalW("0", "0"); // Throws exception if unsupported - m_obSupportsLogicalCmp = true; - } - catch(Exception) { m_obSupportsLogicalCmp = false; } - } -#endif - - internal static bool SupportsStrCmpNaturally - { - get - { -#if (!KeePassLibSD && !KeePassUAP) - if(!m_obSupportsLogicalCmp.HasValue) - TestNaturalComparisonsSupport(); - - return m_obSupportsLogicalCmp.Value; -#else - return false; -#endif - } - } - - internal static int StrCmpNaturally(string x, string y) - { -#if (!KeePassLibSD && !KeePassUAP) - if(!NativeMethods.SupportsStrCmpNaturally) - { - Debug.Assert(false); - return string.Compare(x, y, true); - } - - return StrCmpLogicalW(x, y); -#else - Debug.Assert(false); - return string.Compare(x, y, true); -#endif - } - - internal static string GetUserRuntimeDir() - { -#if KeePassLibSD - return Path.GetTempPath(); -#else -#if KeePassUAP - string strRtDir = EnvironmentExt.AppDataLocalFolderPath; -#else - string strRtDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR"); - if(string.IsNullOrEmpty(strRtDir)) - strRtDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - if(string.IsNullOrEmpty(strRtDir)) - { - Debug.Assert(false); - return Path.GetTempPath(); // Not UrlUtil (otherwise cyclic) - } -#endif - - strRtDir = UrlUtil.EnsureTerminatingSeparator(strRtDir, false); - strRtDir += PwDefs.ShortProductName; - - return strRtDir; -#endif - } - } -} diff --git a/ModernKeePassLib/Properties/AssemblyInfo.cs b/ModernKeePassLib/Properties/AssemblyInfo.cs deleted file mode 100644 index 121fd60..0000000 --- a/ModernKeePassLib/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General assembly properties -[assembly: AssemblyTitle("ModernKeePassLib")] -[assembly: AssemblyDescription("KeePass Password Management Library for .Net Standard")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("wismna")] -[assembly: AssemblyProduct("ModernKeePassLib")] -[assembly: AssemblyCopyright("Copyright © 2018 Geoffroy Bonneville")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// COM settings -[assembly: ComVisible(false)] - -#if !ModernKeePassLib -// Assembly GUID -[assembly: Guid("395f6eec-a1e0-4438-aa82-b75099348134")] -#endif - -// Assembly version information -[assembly: AssemblyVersion("2.39.1.*")] -[assembly: AssemblyFileVersion("2.39.1.0")] diff --git a/ModernKeePassLib/PwCustomIcon.cs b/ModernKeePassLib/PwCustomIcon.cs deleted file mode 100644 index 103d3d4..0000000 --- a/ModernKeePassLib/PwCustomIcon.cs +++ /dev/null @@ -1,131 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -#if ModernKeePassLib -using Image = Splat.IBitmap; -#else -using System.Drawing; -#endif - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib -{ - /// - /// Custom icon. PwCustomIcon objects are immutable. - /// - public sealed class PwCustomIcon - { - private readonly PwUuid m_pwUuid; - private readonly byte[] m_pbImageDataPng; - - private readonly Image m_imgOrg; - private Dictionary m_dImageCache = new Dictionary(); - - // Recommended maximum sizes, not obligatory - internal const int MaxWidth = 128; - internal const int MaxHeight = 128; - - public PwUuid Uuid - { - get { return m_pwUuid; } - } - - public byte[] ImageDataPng - { - get { return m_pbImageDataPng; } - } - - [Obsolete("Use GetImage instead.")] - public Image Image - { -#if (!KeePassLibSD && !KeePassUAP) - get { return GetImage(16, 16); } // Backward compatibility -#else - get { return GetImage(); } // Backward compatibility -#endif - } - - public PwCustomIcon(PwUuid pwUuid, byte[] pbImageDataPng) - { - Debug.Assert(pwUuid != null); - if(pwUuid == null) throw new ArgumentNullException("pwUuid"); - Debug.Assert(!pwUuid.Equals(PwUuid.Zero)); - if(pwUuid.Equals(PwUuid.Zero)) throw new ArgumentException("pwUuid == 0."); - Debug.Assert(pbImageDataPng != null); - if(pbImageDataPng == null) throw new ArgumentNullException("pbImageDataPng"); - - m_pwUuid = pwUuid; - m_pbImageDataPng = pbImageDataPng; - - // MemoryStream ms = new MemoryStream(m_pbImageDataPng, false); - // m_imgOrg = Image.FromStream(ms); - // ms.Close(); - try { m_imgOrg = GfxUtil.LoadImage(m_pbImageDataPng); } - catch(Exception) { Debug.Assert(false); m_imgOrg = null; } - - if(m_imgOrg != null) - m_dImageCache[GetID((int)m_imgOrg.Width, (int)m_imgOrg.Height)] = - m_imgOrg; - } - - private static long GetID(int w, int h) - { - return (((long)w << 32) ^ (long)h); - } - - /// - /// Get the icon as an Image (original size). - /// - public Image GetImage() - { - return m_imgOrg; - } - -#if (!KeePassLibSD && !KeePassUAP) - /// - /// Get the icon as an Image (with the specified size). - /// - /// Width of the returned image. - /// Height of the returned image. - public Image GetImage(int w, int h) - { - if(w < 0) { Debug.Assert(false); return m_imgOrg; } - if(h < 0) { Debug.Assert(false); return m_imgOrg; } - if(m_imgOrg == null) return null; - - long lID = GetID(w, h); - - Image img; - if(m_dImageCache.TryGetValue(lID, out img)) return img; - -#if ModernKeePassLib - img = GfxUtil.ScaleImage(m_pbImageDataPng, w, h); -#else - img = GfxUtil.ScaleImage(m_imgOrg, w, h, ScaleTransformFlags.UIIcon); -#endif - m_dImageCache[lID] = img; - return img; - } -#endif - } -} diff --git a/ModernKeePassLib/PwDatabase.cs b/ModernKeePassLib/PwDatabase.cs deleted file mode 100644 index f903985..0000000 --- a/ModernKeePassLib/PwDatabase.cs +++ /dev/null @@ -1,2077 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Drawing; - -#if ModernKeePassLib -using Image = Splat.IBitmap; -#endif - -using ModernKeePassLib.Collections; -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Cryptography.Cipher; -using ModernKeePassLib.Cryptography.KeyDerivation; -using ModernKeePassLib.Delegates; -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Keys; -using ModernKeePassLib.Resources; -using ModernKeePassLib.Security; -using ModernKeePassLib.Serialization; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib -{ - /// - /// The core password manager class. It contains a number of groups, which - /// contain the actual entries. - /// - public sealed class PwDatabase - { - internal const int DefaultHistoryMaxItems = 10; // -1 = unlimited - internal const long DefaultHistoryMaxSize = 6 * 1024 * 1024; // -1 = unlimited - - private static bool m_bPrimaryCreated = false; - - // Initializations: see Clear() - private PwGroup m_pgRootGroup = null; - private PwObjectList m_vDeletedObjects = new PwObjectList(); - - private PwUuid m_uuidDataCipher = StandardAesEngine.AesUuid; - private PwCompressionAlgorithm m_caCompression = PwCompressionAlgorithm.GZip; - // private ulong m_uKeyEncryptionRounds = PwDefs.DefaultKeyEncryptionRounds; - private KdfParameters m_kdfParams = KdfPool.GetDefaultParameters(); - - private CompositeKey m_pwUserKey = null; - private MemoryProtectionConfig m_memProtConfig = new MemoryProtectionConfig(); - - private List m_vCustomIcons = new List(); - private bool m_bUINeedsIconUpdate = true; - - private DateTime m_dtSettingsChanged = PwDefs.DtDefaultNow; - private string m_strName = string.Empty; - private DateTime m_dtNameChanged = PwDefs.DtDefaultNow; - private string m_strDesc = string.Empty; - private DateTime m_dtDescChanged = PwDefs.DtDefaultNow; - private string m_strDefaultUserName = string.Empty; - private DateTime m_dtDefaultUserChanged = PwDefs.DtDefaultNow; - private uint m_uMntncHistoryDays = 365; - private Color m_clr = Color.Empty; - - private DateTime m_dtKeyLastChanged = PwDefs.DtDefaultNow; - private long m_lKeyChangeRecDays = -1; - private long m_lKeyChangeForceDays = -1; - private bool m_bKeyChangeForceOnce = false; - - private IOConnectionInfo m_ioSource = new IOConnectionInfo(); - private bool m_bDatabaseOpened = false; - private bool m_bModified = false; - - private PwUuid m_pwLastSelectedGroup = PwUuid.Zero; - private PwUuid m_pwLastTopVisibleGroup = PwUuid.Zero; - - private bool m_bUseRecycleBin = true; - private PwUuid m_pwRecycleBin = PwUuid.Zero; - private DateTime m_dtRecycleBinChanged = PwDefs.DtDefaultNow; - private PwUuid m_pwEntryTemplatesGroup = PwUuid.Zero; - private DateTime m_dtEntryTemplatesChanged = PwDefs.DtDefaultNow; - - private int m_nHistoryMaxItems = DefaultHistoryMaxItems; - private long m_lHistoryMaxSize = DefaultHistoryMaxSize; // In bytes - - private StringDictionaryEx m_dCustomData = new StringDictionaryEx(); - private VariantDictionary m_dPublicCustomData = new VariantDictionary(); - - private byte[] m_pbHashOfFileOnDisk = null; - private byte[] m_pbHashOfLastIO = null; - - private bool m_bUseFileTransactions = false; - private bool m_bUseFileLocks = false; - - private IStatusLogger m_slStatus = null; - - private static string m_strLocalizedAppName = string.Empty; - - // private const string StrBackupExtension = ".bak"; - - /// - /// Get the root group that contains all groups and entries stored in the - /// database. - /// - /// Root group. The return value is null, if no database - /// has been opened. - public PwGroup RootGroup - { - get { return m_pgRootGroup; } - set - { - Debug.Assert(value != null); - if(value == null) throw new ArgumentNullException("value"); - - m_pgRootGroup = value; - } - } - - /// - /// IOConnection of the currently opened database file. - /// Is never null. - /// - public IOConnectionInfo IOConnectionInfo - { - get { return m_ioSource; } - } - - /// - /// If this is true, a database is currently open. - /// - public bool IsOpen - { - get { return m_bDatabaseOpened; } - } - - /// - /// Modification flag. If true, the class has been modified and the - /// user interface should prompt the user to save the changes before - /// closing the database for example. - /// - public bool Modified - { - get { return m_bModified; } - set { m_bModified = value; } - } - - /// - /// The user key used for database encryption. This key must be created - /// and set before using any of the database load/save functions. - /// - public CompositeKey MasterKey - { - get { return m_pwUserKey; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - - m_pwUserKey = value; - } - } - - public DateTime SettingsChanged - { - get { return m_dtSettingsChanged; } - set { m_dtSettingsChanged = value; } - } - - /// - /// Name of the database. - /// - public string Name - { - get { return m_strName; } - set - { - Debug.Assert(value != null); - if(value != null) m_strName = value; - } - } - - public DateTime NameChanged - { - get { return m_dtNameChanged; } - set { m_dtNameChanged = value; } - } - - /// - /// Database description. - /// - public string Description - { - get { return m_strDesc; } - set - { - Debug.Assert(value != null); - if(value != null) m_strDesc = value; - } - } - - public DateTime DescriptionChanged - { - get { return m_dtDescChanged; } - set { m_dtDescChanged = value; } - } - - /// - /// Default user name used for new entries. - /// - public string DefaultUserName - { - get { return m_strDefaultUserName; } - set - { - Debug.Assert(value != null); - if(value != null) m_strDefaultUserName = value; - } - } - - public DateTime DefaultUserNameChanged - { - get { return m_dtDefaultUserChanged; } - set { m_dtDefaultUserChanged = value; } - } - - /// - /// Number of days until history entries are being deleted - /// in a database maintenance operation. - /// - public uint MaintenanceHistoryDays - { - get { return m_uMntncHistoryDays; } - set { m_uMntncHistoryDays = value; } - } - - public Color Color - { - get { return m_clr; } - set { m_clr = value; } - } - - public DateTime MasterKeyChanged - { - get { return m_dtKeyLastChanged; } - set { m_dtKeyLastChanged = value; } - } - - public long MasterKeyChangeRec - { - get { return m_lKeyChangeRecDays; } - set { m_lKeyChangeRecDays = value; } - } - - public long MasterKeyChangeForce - { - get { return m_lKeyChangeForceDays; } - set { m_lKeyChangeForceDays = value; } - } - - public bool MasterKeyChangeForceOnce - { - get { return m_bKeyChangeForceOnce; } - set { m_bKeyChangeForceOnce = value; } - } - - /// - /// The encryption algorithm used to encrypt the data part of the database. - /// - public PwUuid DataCipherUuid - { - get { return m_uuidDataCipher; } - set - { - Debug.Assert(value != null); - if(value != null) m_uuidDataCipher = value; - } - } - - /// - /// Compression algorithm used to encrypt the data part of the database. - /// - public PwCompressionAlgorithm Compression - { - get { return m_caCompression; } - set { m_caCompression = value; } - } - - // /// - // /// Number of key transformation rounds (KDF parameter). - // /// - // public ulong KeyEncryptionRounds - // { - // get { return m_uKeyEncryptionRounds; } - // set { m_uKeyEncryptionRounds = value; } - // } - - public KdfParameters KdfParameters - { - get { return m_kdfParams; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_kdfParams = value; - } - } - - /// - /// Memory protection configuration (for default fields). - /// - public MemoryProtectionConfig MemoryProtection - { - get { return m_memProtConfig; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - - m_memProtConfig = value; - } - } - - /// - /// Get a list of all deleted objects. - /// - public PwObjectList DeletedObjects - { - get { return m_vDeletedObjects; } - } - - /// - /// Get all custom icons stored in this database. - /// - public List CustomIcons - { - get { return m_vCustomIcons; } - } - - /// - /// This is a dirty-flag for the UI. It is used to indicate when an - /// icon list update is required. - /// - public bool UINeedsIconUpdate - { - get { return m_bUINeedsIconUpdate; } - set { m_bUINeedsIconUpdate = value; } - } - - public PwUuid LastSelectedGroup - { - get { return m_pwLastSelectedGroup; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_pwLastSelectedGroup = value; - } - } - - public PwUuid LastTopVisibleGroup - { - get { return m_pwLastTopVisibleGroup; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_pwLastTopVisibleGroup = value; - } - } - - public bool RecycleBinEnabled - { - get { return m_bUseRecycleBin; } - set { m_bUseRecycleBin = value; } - } - - public PwUuid RecycleBinUuid - { - get { return m_pwRecycleBin; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_pwRecycleBin = value; - } - } - - public DateTime RecycleBinChanged - { - get { return m_dtRecycleBinChanged; } - set { m_dtRecycleBinChanged = value; } - } - - /// - /// UUID of the group containing template entries. May be - /// PwUuid.Zero, if no entry templates group has been specified. - /// - public PwUuid EntryTemplatesGroup - { - get { return m_pwEntryTemplatesGroup; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_pwEntryTemplatesGroup = value; - } - } - - public DateTime EntryTemplatesGroupChanged - { - get { return m_dtEntryTemplatesChanged; } - set { m_dtEntryTemplatesChanged = value; } - } - - public int HistoryMaxItems - { - get { return m_nHistoryMaxItems; } - set { m_nHistoryMaxItems = value; } - } - - public long HistoryMaxSize - { - get { return m_lHistoryMaxSize; } - set { m_lHistoryMaxSize = value; } - } - - /// - /// Custom data container that can be used by plugins to store - /// own data in KeePass databases. - /// The data is stored in the encrypted part of encrypted - /// database files. - /// Use unique names for your items, e.g. "PluginName_ItemName". - /// - public StringDictionaryEx CustomData - { - get { return m_dCustomData; } - internal set - { - if(value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); } - m_dCustomData = value; - } - } - - /// - /// Custom data container that can be used by plugins to store - /// own data in KeePass databases. - /// The data is stored in the *unencrypted* part of database files, - /// and it is not supported by all file formats (e.g. supported by KDBX, - /// unsupported by XML). - /// It is highly recommended to use CustomData instead, - /// if possible. - /// Use unique names for your items, e.g. "PluginName_ItemName". - /// - public VariantDictionary PublicCustomData - { - get { return m_dPublicCustomData; } - internal set - { - if(value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); } - m_dPublicCustomData = value; - } - } - - /// - /// Hash value of the primary file on disk (last read or last write). - /// A call to SaveAs without making the saved file primary will - /// not change this hash. May be null. - /// - public byte[] HashOfFileOnDisk - { - get { return m_pbHashOfFileOnDisk; } - } - - public byte[] HashOfLastIO - { - get { return m_pbHashOfLastIO; } - } - - public bool UseFileTransactions - { - get { return m_bUseFileTransactions; } - set { m_bUseFileTransactions = value; } - } - - public bool UseFileLocks - { - get { return m_bUseFileLocks; } - set { m_bUseFileLocks = value; } - } - - private string m_strDetachBins = null; - /// - /// Detach binaries when opening a file. If this isn't null, - /// all binaries are saved to the specified path and are removed - /// from the database. - /// - public string DetachBinaries - { - get { return m_strDetachBins; } - set { m_strDetachBins = value; } - } - - /// - /// Localized application name. - /// - public static string LocalizedAppName - { - get { return m_strLocalizedAppName; } - set { Debug.Assert(value != null); m_strLocalizedAppName = value; } - } - - /// - /// Constructs an empty password manager object. - /// - public PwDatabase() - { - if(m_bPrimaryCreated == false) m_bPrimaryCreated = true; - - Clear(); - } - - private void Clear() - { - m_pgRootGroup = null; - m_vDeletedObjects = new PwObjectList(); - - m_uuidDataCipher = StandardAesEngine.AesUuid; - m_caCompression = PwCompressionAlgorithm.GZip; - // m_uKeyEncryptionRounds = PwDefs.DefaultKeyEncryptionRounds; - m_kdfParams = KdfPool.GetDefaultParameters(); - - m_pwUserKey = null; - m_memProtConfig = new MemoryProtectionConfig(); - - m_vCustomIcons = new List(); - m_bUINeedsIconUpdate = true; - - DateTime dtNow = DateTime.UtcNow; - - m_dtSettingsChanged = dtNow; - m_strName = string.Empty; - m_dtNameChanged = dtNow; - m_strDesc = string.Empty; - m_dtDescChanged = dtNow; - m_strDefaultUserName = string.Empty; - m_dtDefaultUserChanged = dtNow; - m_uMntncHistoryDays = 365; - m_clr = Color.Empty; - - m_dtKeyLastChanged = dtNow; - m_lKeyChangeRecDays = -1; - m_lKeyChangeForceDays = -1; - m_bKeyChangeForceOnce = false; - - m_ioSource = new IOConnectionInfo(); - m_bDatabaseOpened = false; - m_bModified = false; - - m_pwLastSelectedGroup = PwUuid.Zero; - m_pwLastTopVisibleGroup = PwUuid.Zero; - - m_bUseRecycleBin = true; - m_pwRecycleBin = PwUuid.Zero; - m_dtRecycleBinChanged = dtNow; - m_pwEntryTemplatesGroup = PwUuid.Zero; - m_dtEntryTemplatesChanged = dtNow; - - m_nHistoryMaxItems = DefaultHistoryMaxItems; - m_lHistoryMaxSize = DefaultHistoryMaxSize; - - m_dCustomData = new StringDictionaryEx(); - m_dPublicCustomData = new VariantDictionary(); - - m_pbHashOfFileOnDisk = null; - m_pbHashOfLastIO = null; - - m_bUseFileTransactions = false; - m_bUseFileLocks = false; - } - - /// - /// Initialize the class for managing a new database. Previously loaded - /// data is deleted. - /// - /// IO connection of the new database. - /// Key to open the database. - public void New(IOConnectionInfo ioConnection, CompositeKey pwKey) - { - Debug.Assert(ioConnection != null); - if(ioConnection == null) throw new ArgumentNullException("ioConnection"); - Debug.Assert(pwKey != null); - if(pwKey == null) throw new ArgumentNullException("pwKey"); - - Close(); - - m_ioSource = ioConnection; - m_pwUserKey = pwKey; - - m_bDatabaseOpened = true; - m_bModified = true; - - m_pgRootGroup = new PwGroup(true, true, UrlUtil.StripExtension( - UrlUtil.GetFileName(ioConnection.Path)), PwIcon.FolderOpen); - m_pgRootGroup.IsExpanded = true; - } - - /// - /// Open a database. The URL may point to any supported data source. - /// - /// IO connection to load the database from. - /// Key used to open the specified database. - /// Logger, which gets all status messages. - public void Open(IOConnectionInfo ioSource, CompositeKey pwKey, - IStatusLogger slLogger) - { - Debug.Assert(ioSource != null); - if(ioSource == null) throw new ArgumentNullException("ioSource"); - Debug.Assert(pwKey != null); - if(pwKey == null) throw new ArgumentNullException("pwKey"); - - Close(); - - try - { - m_pgRootGroup = new PwGroup(true, true, UrlUtil.StripExtension( - UrlUtil.GetFileName(ioSource.Path)), PwIcon.FolderOpen); - m_pgRootGroup.IsExpanded = true; - - m_pwUserKey = pwKey; - m_bModified = false; - - KdbxFile kdbx = new KdbxFile(this); - kdbx.DetachBinaries = m_strDetachBins; - - using(Stream s = IOConnection.OpenRead(ioSource)) - { - kdbx.Load(s, KdbxFormat.Default, slLogger); - } - - m_pbHashOfLastIO = kdbx.HashOfFileOnDisk; - m_pbHashOfFileOnDisk = kdbx.HashOfFileOnDisk; - Debug.Assert(m_pbHashOfFileOnDisk != null); - - m_bDatabaseOpened = true; - m_ioSource = ioSource; - } - catch(Exception) - { - Clear(); - throw; - } - } - - /// - /// Save the currently opened database. The file is written to the location - /// it has been opened from. - /// - /// Logger that recieves status information. - public void Save(IStatusLogger slLogger) - { - Debug.Assert(!HasDuplicateUuids()); - - FileLock fl = null; - if(m_bUseFileLocks) fl = new FileLock(m_ioSource); - try - { - KdbxFile kdbx = new KdbxFile(this); - - using(FileTransactionEx ft = new FileTransactionEx(m_ioSource, - m_bUseFileTransactions)) - { - using(Stream s = ft.OpenWrite()) - { - kdbx.Save(s, null, KdbxFormat.Default, slLogger); - } - - ft.CommitWrite(); - } - - m_pbHashOfLastIO = kdbx.HashOfFileOnDisk; - m_pbHashOfFileOnDisk = kdbx.HashOfFileOnDisk; - Debug.Assert(m_pbHashOfFileOnDisk != null); - } - finally { if(fl != null) fl.Dispose(); } - - m_bModified = false; - } - - /// - /// Save the currently opened database to a different location. If - /// is true, the specified - /// location is made the default location for future saves - /// using SaveDatabase. - /// - /// New location to serialize the database to. - /// If true, the new location is made the - /// standard location for the database. If false, a copy of the currently - /// opened database is saved to the specified location, but it isn't - /// made the default location (i.e. no lock files will be moved for - /// example). - /// Logger that recieves status information. - public void SaveAs(IOConnectionInfo ioConnection, bool bIsPrimaryNow, - IStatusLogger slLogger) - { - Debug.Assert(ioConnection != null); - if(ioConnection == null) throw new ArgumentNullException("ioConnection"); - - IOConnectionInfo ioCurrent = m_ioSource; // Remember current - m_ioSource = ioConnection; - - byte[] pbHashCopy = m_pbHashOfFileOnDisk; - - try { this.Save(slLogger); } - catch(Exception) - { - m_ioSource = ioCurrent; // Restore - m_pbHashOfFileOnDisk = pbHashCopy; - - m_pbHashOfLastIO = null; - throw; - } - - if(!bIsPrimaryNow) - { - m_ioSource = ioCurrent; // Restore - m_pbHashOfFileOnDisk = pbHashCopy; - } - } - - /// - /// Closes the currently opened database. No confirmation message is shown - /// before closing. Unsaved changes will be lost. - /// - public void Close() - { - Clear(); - } - - public void MergeIn(PwDatabase pdSource, PwMergeMethod mm) - { - MergeIn(pdSource, mm, null); - } - - public void MergeIn(PwDatabase pdSource, PwMergeMethod mm, - IStatusLogger slStatus) - { - if(pdSource == null) throw new ArgumentNullException("pdSource"); - - if(mm == PwMergeMethod.CreateNewUuids) - { - pdSource.RootGroup.Uuid = new PwUuid(true); - pdSource.RootGroup.CreateNewItemUuids(true, true, true); - } - - // PwGroup pgOrgStructure = m_pgRootGroup.CloneStructure(); - // PwGroup pgSrcStructure = pdSource.RootGroup.CloneStructure(); - // Later in case 'if(mm == PwMergeMethod.Synchronize)': - // PwObjectPoolEx ppOrg = PwObjectPoolEx.FromGroup(pgOrgStructure); - // PwObjectPoolEx ppSrc = PwObjectPoolEx.FromGroup(pgSrcStructure); - - PwObjectPoolEx ppOrg = PwObjectPoolEx.FromGroup(m_pgRootGroup); - PwObjectPoolEx ppSrc = PwObjectPoolEx.FromGroup(pdSource.RootGroup); - - GroupHandler ghSrc = delegate(PwGroup pg) - { - // if(pg == pdSource.m_pgRootGroup) return true; - - // Do not use ppOrg for finding the group, because new groups - // might have been added (which are not in the pool, and the - // pool should not be modified) - PwGroup pgLocal = m_pgRootGroup.FindGroup(pg.Uuid, true); - - if(pgLocal == null) - { - PwGroup pgSourceParent = pg.ParentGroup; - PwGroup pgLocalContainer; - if(pgSourceParent == null) - { - // pg is the root group of pdSource, and no corresponding - // local group was found; create the group within the - // local root group - Debug.Assert(pg == pdSource.m_pgRootGroup); - pgLocalContainer = m_pgRootGroup; - } - else if(pgSourceParent == pdSource.m_pgRootGroup) - pgLocalContainer = m_pgRootGroup; - else - pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true); - Debug.Assert(pgLocalContainer != null); - if(pgLocalContainer == null) pgLocalContainer = m_pgRootGroup; - - PwGroup pgNew = new PwGroup(false, false); - pgNew.Uuid = pg.Uuid; - pgNew.AssignProperties(pg, false, true); - - // pgLocalContainer.AddGroup(pgNew, true); - InsertObjectAtBestPos(pgLocalContainer.Groups, pgNew, ppSrc); - pgNew.ParentGroup = pgLocalContainer; - } - else // pgLocal != null - { - Debug.Assert(mm != PwMergeMethod.CreateNewUuids); - - if(mm == PwMergeMethod.OverwriteExisting) - pgLocal.AssignProperties(pg, false, false); - else if((mm == PwMergeMethod.OverwriteIfNewer) || - (mm == PwMergeMethod.Synchronize)) - { - pgLocal.AssignProperties(pg, true, false); - } - // else if(mm == PwMergeMethod.KeepExisting) ... - } - - return ((slStatus != null) ? slStatus.ContinueWork() : true); - }; - - EntryHandler ehSrc = delegate(PwEntry pe) - { - // PwEntry peLocal = m_pgRootGroup.FindEntry(pe.Uuid, true); - PwEntry peLocal = (ppOrg.GetItemByUuid(pe.Uuid) as PwEntry); - Debug.Assert(object.ReferenceEquals(peLocal, - m_pgRootGroup.FindEntry(pe.Uuid, true))); - - if(peLocal == null) - { - PwGroup pgSourceParent = pe.ParentGroup; - PwGroup pgLocalContainer; - if(pgSourceParent == pdSource.m_pgRootGroup) - pgLocalContainer = m_pgRootGroup; - else - pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true); - Debug.Assert(pgLocalContainer != null); - if(pgLocalContainer == null) pgLocalContainer = m_pgRootGroup; - - PwEntry peNew = new PwEntry(false, false); - peNew.Uuid = pe.Uuid; - peNew.AssignProperties(pe, false, true, true); - - // pgLocalContainer.AddEntry(peNew, true); - InsertObjectAtBestPos(pgLocalContainer.Entries, peNew, ppSrc); - peNew.ParentGroup = pgLocalContainer; - } - else // peLocal != null - { - Debug.Assert(mm != PwMergeMethod.CreateNewUuids); - - const PwCompareOptions cmpOpt = (PwCompareOptions.IgnoreParentGroup | - PwCompareOptions.IgnoreLastAccess | PwCompareOptions.IgnoreHistory | - PwCompareOptions.NullEmptyEquivStd); - bool bEquals = peLocal.EqualsEntry(pe, cmpOpt, MemProtCmpMode.None); - - bool bOrgBackup = !bEquals; - if(mm != PwMergeMethod.OverwriteExisting) - bOrgBackup &= (TimeUtil.CompareLastMod(pe, peLocal, true) > 0); - bOrgBackup &= !pe.HasBackupOfData(peLocal, false, true); - if(bOrgBackup) peLocal.CreateBackup(null); // Maintain at end - - bool bSrcBackup = !bEquals && (mm != PwMergeMethod.OverwriteExisting); - bSrcBackup &= (TimeUtil.CompareLastMod(peLocal, pe, true) > 0); - bSrcBackup &= !peLocal.HasBackupOfData(pe, false, true); - if(bSrcBackup) pe.CreateBackup(null); // Maintain at end - - if(mm == PwMergeMethod.OverwriteExisting) - peLocal.AssignProperties(pe, false, false, false); - else if((mm == PwMergeMethod.OverwriteIfNewer) || - (mm == PwMergeMethod.Synchronize)) - { - peLocal.AssignProperties(pe, true, false, false); - } - // else if(mm == PwMergeMethod.KeepExisting) ... - - MergeEntryHistory(peLocal, pe, mm); - } - - return ((slStatus != null) ? slStatus.ContinueWork() : true); - }; - - ghSrc(pdSource.RootGroup); - if(!pdSource.RootGroup.TraverseTree(TraversalMethod.PreOrder, ghSrc, ehSrc)) - throw new InvalidOperationException(); - - IStatusLogger slPrevStatus = m_slStatus; - m_slStatus = slStatus; - - if(mm == PwMergeMethod.Synchronize) - { - RelocateGroups(ppOrg, ppSrc); - RelocateEntries(ppOrg, ppSrc); - ReorderObjects(m_pgRootGroup, ppOrg, ppSrc); - - // After all relocations and reorderings - MergeInLocationChanged(m_pgRootGroup, ppOrg, ppSrc); - ppOrg = null; // Pools are now invalid, because the location - ppSrc = null; // changed times have been merged in - - // Delete *after* relocating, because relocating might - // empty some groups that are marked for deletion (and - // objects that weren't relocated yet might prevent the - // deletion) - Dictionary dOrgDel = CreateDeletedObjectsPool(); - MergeInDeletionInfo(pdSource.m_vDeletedObjects, dOrgDel); - ApplyDeletions(m_pgRootGroup, dOrgDel); - - // The list and the dictionary should be kept in sync - Debug.Assert(m_vDeletedObjects.UCount == (uint)dOrgDel.Count); - } - - // Must be called *after* merging groups, because group UUIDs - // are required for recycle bin and entry template UUIDs - MergeInDbProperties(pdSource, mm); - - MergeInCustomIcons(pdSource); - - MaintainBackups(); - - Debug.Assert(!HasDuplicateUuids()); - m_slStatus = slPrevStatus; - } - - private void MergeInCustomIcons(PwDatabase pdSource) - { - foreach(PwCustomIcon pwci in pdSource.CustomIcons) - { - if(GetCustomIconIndex(pwci.Uuid) >= 0) continue; - - m_vCustomIcons.Add(pwci); // PwCustomIcon is immutable - m_bUINeedsIconUpdate = true; - } - } - - private Dictionary CreateDeletedObjectsPool() - { - Dictionary d = - new Dictionary(); - - int n = (int)m_vDeletedObjects.UCount; - for(int i = n - 1; i >= 0; --i) - { - PwDeletedObject pdo = m_vDeletedObjects.GetAt((uint)i); - - PwDeletedObject pdoEx; - if(d.TryGetValue(pdo.Uuid, out pdoEx)) - { - Debug.Assert(false); // Found duplicate, which should not happen - - if(pdo.DeletionTime > pdoEx.DeletionTime) - pdoEx.DeletionTime = pdo.DeletionTime; - - m_vDeletedObjects.RemoveAt((uint)i); - } - else d[pdo.Uuid] = pdo; - } - - return d; - } - - private void MergeInDeletionInfo(PwObjectList lSrc, - Dictionary dOrgDel) - { - foreach(PwDeletedObject pdoSrc in lSrc) - { - PwDeletedObject pdoOrg; - if(dOrgDel.TryGetValue(pdoSrc.Uuid, out pdoOrg)) // Update - { - Debug.Assert(pdoOrg.Uuid.Equals(pdoSrc.Uuid)); - - if(pdoSrc.DeletionTime > pdoOrg.DeletionTime) - pdoOrg.DeletionTime = pdoSrc.DeletionTime; - } - else // Add - { - m_vDeletedObjects.Add(pdoSrc); - dOrgDel[pdoSrc.Uuid] = pdoSrc; - } - } - } - - private void ApplyDeletions(PwObjectList l, Predicate fCanDelete, - Dictionary dOrgDel) - where T : class, ITimeLogger, IStructureItem, IDeepCloneable - { - int n = (int)l.UCount; - for(int i = n - 1; i >= 0; --i) - { - if((m_slStatus != null) && !m_slStatus.ContinueWork()) break; - - T t = l.GetAt((uint)i); - - PwDeletedObject pdo; - if(dOrgDel.TryGetValue(t.Uuid, out pdo)) - { - Debug.Assert(t.Uuid.Equals(pdo.Uuid)); - - bool bDel = (TimeUtil.Compare(t.LastModificationTime, - pdo.DeletionTime, true) < 0); - bDel &= fCanDelete(t); - - if(bDel) l.RemoveAt((uint)i); - else - { - // Prevent future deletion attempts; this also prevents - // delayed deletions (emptying a group could cause a - // group to be deleted, if the deletion was prevented - // before due to the group not being empty) - if(!m_vDeletedObjects.Remove(pdo)) { Debug.Assert(false); } - if(!dOrgDel.Remove(pdo.Uuid)) { Debug.Assert(false); } - } - } - } - } - - private static bool SafeCanDeleteGroup(PwGroup pg) - { - if(pg == null) { Debug.Assert(false); return false; } - - if(pg.Groups.UCount > 0) return false; - if(pg.Entries.UCount > 0) return false; - return true; - } - - private static bool SafeCanDeleteEntry(PwEntry pe) - { - if(pe == null) { Debug.Assert(false); return false; } - - return true; - } - - // Apply deletions on all objects in the specified container - // (but not the container itself), using post-order traversal - // to avoid implicit deletions; - // https://sourceforge.net/p/keepass/bugs/1499/ - private void ApplyDeletions(PwGroup pgContainer, - Dictionary dOrgDel) - { - foreach(PwGroup pg in pgContainer.Groups) // Post-order traversal - { - ApplyDeletions(pg, dOrgDel); - } - - ApplyDeletions(pgContainer.Groups, PwDatabase.SafeCanDeleteGroup, dOrgDel); - ApplyDeletions(pgContainer.Entries, PwDatabase.SafeCanDeleteEntry, dOrgDel); - } - - private void RelocateGroups(PwObjectPoolEx ppOrg, PwObjectPoolEx ppSrc) - { - PwObjectList vGroups = m_pgRootGroup.GetGroups(true); - - foreach(PwGroup pg in vGroups) - { - if((m_slStatus != null) && !m_slStatus.ContinueWork()) break; - - // PwGroup pgOrg = pgOrgStructure.FindGroup(pg.Uuid, true); - IStructureItem ptOrg = ppOrg.GetItemByUuid(pg.Uuid); - if(ptOrg == null) continue; - // PwGroup pgSrc = pgSrcStructure.FindGroup(pg.Uuid, true); - IStructureItem ptSrc = ppSrc.GetItemByUuid(pg.Uuid); - if(ptSrc == null) continue; - - PwGroup pgOrgParent = ptOrg.ParentGroup; - // vGroups does not contain the root group, thus pgOrgParent - // should not be null - if(pgOrgParent == null) { Debug.Assert(false); continue; } - - PwGroup pgSrcParent = ptSrc.ParentGroup; - // pgSrcParent may be null (for the source root group) - if(pgSrcParent == null) continue; - - if(pgOrgParent.Uuid.Equals(pgSrcParent.Uuid)) - { - // pg.LocationChanged = ((ptSrc.LocationChanged > ptOrg.LocationChanged) ? - // ptSrc.LocationChanged : ptOrg.LocationChanged); - continue; - } - - if(ptSrc.LocationChanged > ptOrg.LocationChanged) - { - PwGroup pgLocal = m_pgRootGroup.FindGroup(pgSrcParent.Uuid, true); - if(pgLocal == null) { Debug.Assert(false); continue; } - - if(pgLocal.IsContainedIn(pg)) continue; - - pg.ParentGroup.Groups.Remove(pg); - - // pgLocal.AddGroup(pg, true); - InsertObjectAtBestPos(pgLocal.Groups, pg, ppSrc); - pg.ParentGroup = pgLocal; - - // pg.LocationChanged = ptSrc.LocationChanged; - } - else - { - Debug.Assert(pg.ParentGroup.Uuid.Equals(pgOrgParent.Uuid)); - Debug.Assert(pg.LocationChanged == ptOrg.LocationChanged); - } - } - - Debug.Assert(m_pgRootGroup.GetGroups(true).UCount == vGroups.UCount); - } - - private void RelocateEntries(PwObjectPoolEx ppOrg, PwObjectPoolEx ppSrc) - { - PwObjectList vEntries = m_pgRootGroup.GetEntries(true); - - foreach(PwEntry pe in vEntries) - { - if((m_slStatus != null) && !m_slStatus.ContinueWork()) break; - - // PwEntry peOrg = pgOrgStructure.FindEntry(pe.Uuid, true); - IStructureItem ptOrg = ppOrg.GetItemByUuid(pe.Uuid); - if(ptOrg == null) continue; - // PwEntry peSrc = pgSrcStructure.FindEntry(pe.Uuid, true); - IStructureItem ptSrc = ppSrc.GetItemByUuid(pe.Uuid); - if(ptSrc == null) continue; - - PwGroup pgOrg = ptOrg.ParentGroup; - PwGroup pgSrc = ptSrc.ParentGroup; - if(pgOrg.Uuid.Equals(pgSrc.Uuid)) - { - // pe.LocationChanged = ((ptSrc.LocationChanged > ptOrg.LocationChanged) ? - // ptSrc.LocationChanged : ptOrg.LocationChanged); - continue; - } - - if(ptSrc.LocationChanged > ptOrg.LocationChanged) - { - PwGroup pgLocal = m_pgRootGroup.FindGroup(pgSrc.Uuid, true); - if(pgLocal == null) { Debug.Assert(false); continue; } - - pe.ParentGroup.Entries.Remove(pe); - - // pgLocal.AddEntry(pe, true); - InsertObjectAtBestPos(pgLocal.Entries, pe, ppSrc); - pe.ParentGroup = pgLocal; - - // pe.LocationChanged = ptSrc.LocationChanged; - } - else - { - Debug.Assert(pe.ParentGroup.Uuid.Equals(pgOrg.Uuid)); - Debug.Assert(pe.LocationChanged == ptOrg.LocationChanged); - } - } - - Debug.Assert(m_pgRootGroup.GetEntries(true).UCount == vEntries.UCount); - } - - private void ReorderObjects(PwGroup pg, PwObjectPoolEx ppOrg, - PwObjectPoolEx ppSrc) - { - ReorderObjectList(pg.Groups, ppOrg, ppSrc); - ReorderObjectList(pg.Entries, ppOrg, ppSrc); - - foreach(PwGroup pgSub in pg.Groups) - { - ReorderObjects(pgSub, ppOrg, ppSrc); - } - } - - private void ReorderObjectList(PwObjectList lItems, - PwObjectPoolEx ppOrg, PwObjectPoolEx ppSrc) - where T : class, ITimeLogger, IStructureItem, IDeepCloneable - { - List> lBlocks = PartitionConsec(lItems, ppOrg, ppSrc); - if(lBlocks.Count <= 1) return; - -#if DEBUG - PwObjectList lOrgItems = lItems.CloneShallow(); -#endif - - Queue> qToDo = new Queue>(); - qToDo.Enqueue(new KeyValuePair(0, lBlocks.Count - 1)); - - while(qToDo.Count > 0) - { - if((m_slStatus != null) && !m_slStatus.ContinueWork()) break; - - KeyValuePair kvp = qToDo.Dequeue(); - if(kvp.Key >= kvp.Value) { Debug.Assert(false); continue; } - - PwObjectPoolEx pPool; - int iPivot = FindLocationChangedPivot(lBlocks, kvp, out pPool); - PwObjectBlock bPivot = lBlocks[iPivot]; - - T tPivotPrimary = bPivot.PrimaryItem; - if(tPivotPrimary == null) { Debug.Assert(false); continue; } - ulong idPivot = pPool.GetIdByUuid(tPivotPrimary.Uuid); - if(idPivot == 0) { Debug.Assert(false); continue; } - - Queue> qBefore = new Queue>(); - Queue> qAfter = new Queue>(); - bool bBefore = true; - - for(int i = kvp.Key; i <= kvp.Value; ++i) - { - if(i == iPivot) { bBefore = false; continue; } - - PwObjectBlock b = lBlocks[i]; - Debug.Assert(b.LocationChanged <= bPivot.LocationChanged); - - T t = b.PrimaryItem; - if(t != null) - { - ulong idBPri = pPool.GetIdByUuid(t.Uuid); - if(idBPri > 0) - { - if(idBPri < idPivot) qBefore.Enqueue(b); - else qAfter.Enqueue(b); - - continue; - } - } - else { Debug.Assert(false); } - - if(bBefore) qBefore.Enqueue(b); - else qAfter.Enqueue(b); - } - - int j = kvp.Key; - while(qBefore.Count > 0) { lBlocks[j] = qBefore.Dequeue(); ++j; } - int iNewPivot = j; - lBlocks[j] = bPivot; - ++j; - while(qAfter.Count > 0) { lBlocks[j] = qAfter.Dequeue(); ++j; } - Debug.Assert(j == (kvp.Value + 1)); - - if((iNewPivot - 1) > kvp.Key) - qToDo.Enqueue(new KeyValuePair(kvp.Key, iNewPivot - 1)); - if((iNewPivot + 1) < kvp.Value) - qToDo.Enqueue(new KeyValuePair(iNewPivot + 1, kvp.Value)); - } - - uint u = 0; - foreach(PwObjectBlock b in lBlocks) - { - foreach(T t in b) - { - lItems.SetAt(u, t); - ++u; - } - } - Debug.Assert(u == lItems.UCount); - -#if DEBUG - Debug.Assert(u == lOrgItems.UCount); - foreach(T ptItem in lOrgItems) - { - Debug.Assert(lItems.IndexOf(ptItem) >= 0); - } -#endif - } - - private static List> PartitionConsec(PwObjectList lItems, - PwObjectPoolEx ppOrg, PwObjectPoolEx ppSrc) - where T : class, ITimeLogger, IStructureItem, IDeepCloneable - { - List> lBlocks = new List>(); - - Dictionary dItemUuids = new Dictionary(); - foreach(T t in lItems) { dItemUuids[t.Uuid] = true; } - - uint n = lItems.UCount; - for(uint u = 0; u < n; ++u) - { - T t = lItems.GetAt(u); - - PwObjectBlock b = new PwObjectBlock(); - - DateTime dtLoc; - PwObjectPoolEx pPool = GetBestPool(t, ppOrg, ppSrc, out dtLoc); - b.Add(t, dtLoc, pPool); - - lBlocks.Add(b); - - ulong idOrg = ppOrg.GetIdByUuid(t.Uuid); - ulong idSrc = ppSrc.GetIdByUuid(t.Uuid); - if((idOrg == 0) || (idSrc == 0)) continue; - - for(uint x = u + 1; x < n; ++x) - { - T tNext = lItems.GetAt(x); - - ulong idOrgNext = idOrg + 1; - while(true) - { - IStructureItem ptOrg = ppOrg.GetItemById(idOrgNext); - if(ptOrg == null) { idOrgNext = 0; break; } - if(ptOrg.Uuid.Equals(tNext.Uuid)) break; // Found it - if(dItemUuids.ContainsKey(ptOrg.Uuid)) { idOrgNext = 0; break; } - ++idOrgNext; - } - if(idOrgNext == 0) break; - - ulong idSrcNext = idSrc + 1; - while(true) - { - IStructureItem ptSrc = ppSrc.GetItemById(idSrcNext); - if(ptSrc == null) { idSrcNext = 0; break; } - if(ptSrc.Uuid.Equals(tNext.Uuid)) break; // Found it - if(dItemUuids.ContainsKey(ptSrc.Uuid)) { idSrcNext = 0; break; } - ++idSrcNext; - } - if(idSrcNext == 0) break; - - pPool = GetBestPool(tNext, ppOrg, ppSrc, out dtLoc); - b.Add(tNext, dtLoc, pPool); - - ++u; - idOrg = idOrgNext; - idSrc = idSrcNext; - } - } - - return lBlocks; - } - - private static PwObjectPoolEx GetBestPool(T t, PwObjectPoolEx ppOrg, - PwObjectPoolEx ppSrc, out DateTime dtLoc) - where T : class, ITimeLogger, IStructureItem, IDeepCloneable - { - PwObjectPoolEx p = null; - dtLoc = TimeUtil.SafeMinValueUtc; - - IStructureItem ptOrg = ppOrg.GetItemByUuid(t.Uuid); - if(ptOrg != null) - { - dtLoc = ptOrg.LocationChanged; - p = ppOrg; - } - - IStructureItem ptSrc = ppSrc.GetItemByUuid(t.Uuid); - if((ptSrc != null) && (ptSrc.LocationChanged > dtLoc)) - { - dtLoc = ptSrc.LocationChanged; - p = ppSrc; - } - - Debug.Assert(p != null); - return p; - } - - private static int FindLocationChangedPivot(List> lBlocks, - KeyValuePair kvpRange, out PwObjectPoolEx pPool) - where T : class, ITimeLogger, IStructureItem, IDeepCloneable - { - pPool = null; - - int iPosMax = kvpRange.Key; - DateTime dtMax = TimeUtil.SafeMinValueUtc; - - for(int i = kvpRange.Key; i <= kvpRange.Value; ++i) - { - PwObjectBlock b = lBlocks[i]; - if(b.LocationChanged > dtMax) - { - iPosMax = i; - dtMax = b.LocationChanged; - pPool = b.PoolAssoc; - } - } - - return iPosMax; - } - - private static void MergeInLocationChanged(PwGroup pg, - PwObjectPoolEx ppOrg, PwObjectPoolEx ppSrc) - { - GroupHandler gh = delegate(PwGroup pgSub) - { - DateTime dt; - if(GetBestPool(pgSub, ppOrg, ppSrc, out dt) != null) - pgSub.LocationChanged = dt; - else { Debug.Assert(false); } - return true; - }; - - EntryHandler eh = delegate(PwEntry pe) - { - DateTime dt; - if(GetBestPool(pe, ppOrg, ppSrc, out dt) != null) - pe.LocationChanged = dt; - else { Debug.Assert(false); } - return true; - }; - - gh(pg); - pg.TraverseTree(TraversalMethod.PreOrder, gh, eh); - } - - private static void InsertObjectAtBestPos(PwObjectList lItems, - T tNew, PwObjectPoolEx ppSrc) - where T : class, ITimeLogger, IStructureItem, IDeepCloneable - { - if(tNew == null) { Debug.Assert(false); return; } - - ulong idSrc = ppSrc.GetIdByUuid(tNew.Uuid); - if(idSrc == 0) { Debug.Assert(false); lItems.Add(tNew); return; } - - const uint uIdOffset = 2; - Dictionary dOrg = new Dictionary(); - for(uint u = 0; u < lItems.UCount; ++u) - dOrg[lItems.GetAt(u).Uuid] = uIdOffset + u; - - ulong idSrcNext = idSrc + 1; - uint idOrgNext = 0; - while(true) - { - IStructureItem pNext = ppSrc.GetItemById(idSrcNext); - if(pNext == null) break; - if(dOrg.TryGetValue(pNext.Uuid, out idOrgNext)) break; - ++idSrcNext; - } - - if(idOrgNext != 0) - { - lItems.Insert(idOrgNext - uIdOffset, tNew); - return; - } - - ulong idSrcPrev = idSrc - 1; - uint idOrgPrev = 0; - while(true) - { - IStructureItem pPrev = ppSrc.GetItemById(idSrcPrev); - if(pPrev == null) break; - if(dOrg.TryGetValue(pPrev.Uuid, out idOrgPrev)) break; - --idSrcPrev; - } - - if(idOrgPrev != 0) - { - lItems.Insert(idOrgPrev + 1 - uIdOffset, tNew); - return; - } - - lItems.Add(tNew); - } - - private void MergeInDbProperties(PwDatabase pdSource, PwMergeMethod mm) - { - if(pdSource == null) { Debug.Assert(false); return; } - if((mm == PwMergeMethod.KeepExisting) || (mm == PwMergeMethod.None)) - return; - - bool bForce = (mm == PwMergeMethod.OverwriteExisting); - bool bSourceNewer = (pdSource.m_dtSettingsChanged > m_dtSettingsChanged); - - if(bForce || bSourceNewer) - { - m_dtSettingsChanged = pdSource.m_dtSettingsChanged; - - m_clr = pdSource.m_clr; - } - - if(bForce || (pdSource.m_dtNameChanged > m_dtNameChanged)) - { - m_strName = pdSource.m_strName; - m_dtNameChanged = pdSource.m_dtNameChanged; - } - - if(bForce || (pdSource.m_dtDescChanged > m_dtDescChanged)) - { - m_strDesc = pdSource.m_strDesc; - m_dtDescChanged = pdSource.m_dtDescChanged; - } - - if(bForce || (pdSource.m_dtDefaultUserChanged > m_dtDefaultUserChanged)) - { - m_strDefaultUserName = pdSource.m_strDefaultUserName; - m_dtDefaultUserChanged = pdSource.m_dtDefaultUserChanged; - } - - PwUuid pwPrefBin = m_pwRecycleBin, pwAltBin = pdSource.m_pwRecycleBin; - if(bForce || (pdSource.m_dtRecycleBinChanged > m_dtRecycleBinChanged)) - { - pwPrefBin = pdSource.m_pwRecycleBin; - pwAltBin = m_pwRecycleBin; - m_bUseRecycleBin = pdSource.m_bUseRecycleBin; - m_dtRecycleBinChanged = pdSource.m_dtRecycleBinChanged; - } - if(m_pgRootGroup.FindGroup(pwPrefBin, true) != null) - m_pwRecycleBin = pwPrefBin; - else if(m_pgRootGroup.FindGroup(pwAltBin, true) != null) - m_pwRecycleBin = pwAltBin; - else m_pwRecycleBin = PwUuid.Zero; // Debug.Assert(false); - - PwUuid pwPrefTmp = m_pwEntryTemplatesGroup, pwAltTmp = pdSource.m_pwEntryTemplatesGroup; - if(bForce || (pdSource.m_dtEntryTemplatesChanged > m_dtEntryTemplatesChanged)) - { - pwPrefTmp = pdSource.m_pwEntryTemplatesGroup; - pwAltTmp = m_pwEntryTemplatesGroup; - m_dtEntryTemplatesChanged = pdSource.m_dtEntryTemplatesChanged; - } - if(m_pgRootGroup.FindGroup(pwPrefTmp, true) != null) - m_pwEntryTemplatesGroup = pwPrefTmp; - else if(m_pgRootGroup.FindGroup(pwAltTmp, true) != null) - m_pwEntryTemplatesGroup = pwAltTmp; - else m_pwEntryTemplatesGroup = PwUuid.Zero; // Debug.Assert(false); - - foreach(KeyValuePair kvp in pdSource.m_dCustomData) - { - if(bSourceNewer || !m_dCustomData.Exists(kvp.Key)) - m_dCustomData.Set(kvp.Key, kvp.Value); - } - - VariantDictionary vdLocal = m_dPublicCustomData; // Backup - m_dPublicCustomData = (VariantDictionary)pdSource.m_dPublicCustomData.Clone(); - if(!bSourceNewer) vdLocal.CopyTo(m_dPublicCustomData); // Merge - } - - private void MergeEntryHistory(PwEntry pe, PwEntry peSource, - PwMergeMethod mm) - { - if(!pe.Uuid.Equals(peSource.Uuid)) { Debug.Assert(false); return; } - - if(pe.History.UCount == peSource.History.UCount) - { - bool bEqual = true; - for(uint uEnum = 0; uEnum < pe.History.UCount; ++uEnum) - { - if(pe.History.GetAt(uEnum).LastModificationTime != - peSource.History.GetAt(uEnum).LastModificationTime) - { - bEqual = false; - break; - } - } - - if(bEqual) return; - } - - if((m_slStatus != null) && !m_slStatus.ContinueWork()) return; - - IDictionary dict = -#if KeePassLibSD - new SortedList(); -#else - new SortedDictionary(); -#endif - foreach(PwEntry peOrg in pe.History) - { - dict[peOrg.LastModificationTime] = peOrg; - } - - foreach(PwEntry peSrc in peSource.History) - { - DateTime dt = peSrc.LastModificationTime; - if(dict.ContainsKey(dt)) - { - if(mm == PwMergeMethod.OverwriteExisting) - dict[dt] = peSrc.CloneDeep(); - } - else dict[dt] = peSrc.CloneDeep(); - } - - pe.History.Clear(); - foreach(KeyValuePair kvpCur in dict) - { - Debug.Assert(kvpCur.Value.Uuid.Equals(pe.Uuid)); - Debug.Assert(kvpCur.Value.History.UCount == 0); - pe.History.Add(kvpCur.Value); - } - } - - public bool MaintainBackups() - { - if(m_pgRootGroup == null) { Debug.Assert(false); return false; } - - bool bDeleted = false; - EntryHandler eh = delegate(PwEntry pe) - { - if(pe.MaintainBackups(this)) bDeleted = true; - return true; - }; - - m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, null, eh); - return bDeleted; - } - - /* /// - /// Synchronize current database with another one. - /// - /// Source file. - public void Synchronize(string strFile) - { - PwDatabase pdSource = new PwDatabase(); - - IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile); - pdSource.Open(ioc, m_pwUserKey, null); - - MergeIn(pdSource, PwMergeMethod.Synchronize); - } */ - - /// - /// Get the index of a custom icon. - /// - /// ID of the icon. - /// Index of the icon. - public int GetCustomIconIndex(PwUuid pwIconId) - { - for(int i = 0; i < m_vCustomIcons.Count; ++i) - { - PwCustomIcon pwci = m_vCustomIcons[i]; - if(pwci.Uuid.Equals(pwIconId)) - return i; - } - - // Debug.Assert(false); // Do not assert - return -1; - } - - public int GetCustomIconIndex(byte[] pbPngData) - { - if(pbPngData == null) { Debug.Assert(false); return -1; } - - for(int i = 0; i < m_vCustomIcons.Count; ++i) - { - PwCustomIcon pwci = m_vCustomIcons[i]; - byte[] pbEx = pwci.ImageDataPng; - if(pbEx == null) { Debug.Assert(false); continue; } - - if(MemUtil.ArraysEqual(pbEx, pbPngData)) - return i; - } - - return -1; - } - -#if KeePassUAP - public Image GetCustomIcon(PwUuid pwIconId) - { - int nIndex = GetCustomIconIndex(pwIconId); - if(nIndex >= 0) - return m_vCustomIcons[nIndex].GetImage(); - else { Debug.Assert(false); } - - return null; - } -#elif !KeePassLibSD - [Obsolete("Additionally specify the size.")] - public Image GetCustomIcon(PwUuid pwIconId) - { - return GetCustomIcon(pwIconId, 16, 16); // Backward compatibility - } - - /// - /// Get a custom icon. This method can return null, - /// e.g. if no cached image of the icon is available. - /// - /// ID of the icon. - /// Width of the returned image. If this is - /// negative, the image is returned in its original size. - /// Height of the returned image. If this is - /// negative, the image is returned in its original size. - public Image GetCustomIcon(PwUuid pwIconId, int w, int h) - { - int nIndex = GetCustomIconIndex(pwIconId); - if(nIndex >= 0) - { - if((w >= 0) && (h >= 0)) - return m_vCustomIcons[nIndex].GetImage(w, h); - else return m_vCustomIcons[nIndex].GetImage(); // No assert - } - else { Debug.Assert(false); } - - return null; - } -#endif - - public bool DeleteCustomIcons(List vUuidsToDelete) - { - Debug.Assert(vUuidsToDelete != null); - if(vUuidsToDelete == null) throw new ArgumentNullException("vUuidsToDelete"); - if(vUuidsToDelete.Count <= 0) return true; - - GroupHandler gh = delegate(PwGroup pg) - { - PwUuid uuidThis = pg.CustomIconUuid; - if(uuidThis.Equals(PwUuid.Zero)) return true; - - foreach(PwUuid uuidDelete in vUuidsToDelete) - { - if(uuidThis.Equals(uuidDelete)) - { - pg.CustomIconUuid = PwUuid.Zero; - break; - } - } - - return true; - }; - - EntryHandler eh = delegate(PwEntry pe) - { - RemoveCustomIconUuid(pe, vUuidsToDelete); - return true; - }; - - gh(m_pgRootGroup); - if(!m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh)) - { - Debug.Assert(false); - return false; - } - - foreach(PwUuid pwUuid in vUuidsToDelete) - { - int nIndex = GetCustomIconIndex(pwUuid); - if(nIndex >= 0) m_vCustomIcons.RemoveAt(nIndex); - } - - return true; - } - - private static void RemoveCustomIconUuid(PwEntry pe, List vToDelete) - { - PwUuid uuidThis = pe.CustomIconUuid; - if(uuidThis.Equals(PwUuid.Zero)) return; - - foreach(PwUuid uuidDelete in vToDelete) - { - if(uuidThis.Equals(uuidDelete)) - { - pe.CustomIconUuid = PwUuid.Zero; - break; - } - } - - foreach(PwEntry peHistory in pe.History) - RemoveCustomIconUuid(peHistory, vToDelete); - } - - private int GetTotalObjectUuidCount() - { - uint uGroups, uEntries; - m_pgRootGroup.GetCounts(true, out uGroups, out uEntries); - - uint uTotal = uGroups + uEntries + 1; // 1 for root group - if(uTotal > 0x7FFFFFFFU) { Debug.Assert(false); return 0x7FFFFFFF; } - return (int)uTotal; - } - - internal bool HasDuplicateUuids() - { - int nTotal = GetTotalObjectUuidCount(); - Dictionary d = new Dictionary(nTotal); - bool bDupFound = false; - - GroupHandler gh = delegate(PwGroup pg) - { - PwUuid pu = pg.Uuid; - if(d.ContainsKey(pu)) - { - bDupFound = true; - return false; - } - - d.Add(pu, null); - Debug.Assert(d.ContainsKey(pu)); - return true; - }; - - EntryHandler eh = delegate(PwEntry pe) - { - PwUuid pu = pe.Uuid; - if(d.ContainsKey(pu)) - { - bDupFound = true; - return false; - } - - d.Add(pu, null); - Debug.Assert(d.ContainsKey(pu)); - return true; - }; - - gh(m_pgRootGroup); - m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh); - - Debug.Assert(bDupFound || (d.Count == nTotal)); - return bDupFound; - } - - internal void FixDuplicateUuids() - { - int nTotal = GetTotalObjectUuidCount(); - Dictionary d = new Dictionary(nTotal); - - GroupHandler gh = delegate(PwGroup pg) - { - PwUuid pu = pg.Uuid; - if(d.ContainsKey(pu)) - { - pu = new PwUuid(true); - while(d.ContainsKey(pu)) { Debug.Assert(false); pu = new PwUuid(true); } - - pg.Uuid = pu; - } - - d.Add(pu, null); - return true; - }; - - EntryHandler eh = delegate(PwEntry pe) - { - PwUuid pu = pe.Uuid; - if(d.ContainsKey(pu)) - { - pu = new PwUuid(true); - while(d.ContainsKey(pu)) { Debug.Assert(false); pu = new PwUuid(true); } - - pe.SetUuid(pu, true); - } - - d.Add(pu, null); - return true; - }; - - gh(m_pgRootGroup); - m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh); - - Debug.Assert(d.Count == nTotal); - Debug.Assert(!HasDuplicateUuids()); - } - - /* public void CreateBackupFile(IStatusLogger sl) - { - if(sl != null) sl.SetText(KLRes.CreatingBackupFile, LogStatusType.Info); - - IOConnectionInfo iocBk = m_ioSource.CloneDeep(); - iocBk.Path += StrBackupExtension; - - bool bMadeUnhidden = UrlUtil.UnhideFile(iocBk.Path); - - bool bFastCopySuccess = false; - if(m_ioSource.IsLocalFile() && (m_ioSource.UserName.Length == 0) && - (m_ioSource.Password.Length == 0)) - { - try - { - string strFile = m_ioSource.Path + StrBackupExtension; - File.Copy(m_ioSource.Path, strFile, true); - bFastCopySuccess = true; - } - catch(Exception) { Debug.Assert(false); } - } - - if(bFastCopySuccess == false) - { - using(Stream sIn = IOConnection.OpenRead(m_ioSource)) - { - using(Stream sOut = IOConnection.OpenWrite(iocBk)) - { - MemUtil.CopyStream(sIn, sOut); - } - } - } - - if(bMadeUnhidden) UrlUtil.HideFile(iocBk.Path, true); // Hide again - } */ - - /* private static void RemoveData(PwGroup pg) - { - EntryHandler eh = delegate(PwEntry pe) - { - pe.AutoType.Clear(); - pe.Binaries.Clear(); - pe.History.Clear(); - pe.Strings.Clear(); - return true; - }; - - pg.TraverseTree(TraversalMethod.PreOrder, null, eh); - } */ - - public uint DeleteDuplicateEntries(IStatusLogger sl) - { - uint uDeleted = 0; - - PwGroup pgRecycleBin = null; - if(m_bUseRecycleBin) - pgRecycleBin = m_pgRootGroup.FindGroup(m_pwRecycleBin, true); - - DateTime dtNow = DateTime.UtcNow; - PwObjectList l = m_pgRootGroup.GetEntries(true); - int i = 0; - while(true) - { - if(i >= ((int)l.UCount - 1)) break; - - if(sl != null) - { - long lCnt = (long)l.UCount, li = (long)i; - long nArTotal = (lCnt * lCnt) / 2L; - long nArCur = li * lCnt - ((li * li) / 2L); - long nArPct = (nArCur * 100L) / nArTotal; - if(nArPct < 0) nArPct = 0; - if(nArPct > 100) nArPct = 100; - if(!sl.SetProgress((uint)nArPct)) break; - } - - PwEntry peA = l.GetAt((uint)i); - - for(uint j = (uint)i + 1; j < l.UCount; ++j) - { - PwEntry peB = l.GetAt(j); - if(!DupEntriesEqual(peA, peB)) continue; - - bool bDeleteA = (TimeUtil.CompareLastMod(peA, peB, true) <= 0); - if(pgRecycleBin != null) - { - bool bAInBin = peA.IsContainedIn(pgRecycleBin); - bool bBInBin = peB.IsContainedIn(pgRecycleBin); - - if(bAInBin && !bBInBin) bDeleteA = true; - else if(bBInBin && !bAInBin) bDeleteA = false; - } - - if(bDeleteA) - { - peA.ParentGroup.Entries.Remove(peA); - m_vDeletedObjects.Add(new PwDeletedObject(peA.Uuid, dtNow)); - - l.RemoveAt((uint)i); - --i; - } - else - { - peB.ParentGroup.Entries.Remove(peB); - m_vDeletedObjects.Add(new PwDeletedObject(peB.Uuid, dtNow)); - - l.RemoveAt(j); - } - - ++uDeleted; - break; - } - - ++i; - } - - return uDeleted; - } - - private static List m_lStdFields = null; - private static bool DupEntriesEqual(PwEntry a, PwEntry b) - { - if(m_lStdFields == null) m_lStdFields = PwDefs.GetStandardFields(); - - foreach(string strStdKey in m_lStdFields) - { - string strA = a.Strings.ReadSafe(strStdKey); - string strB = b.Strings.ReadSafe(strStdKey); - if(!strA.Equals(strB)) return false; - } - - foreach(KeyValuePair kvpA in a.Strings) - { - if(PwDefs.IsStandardField(kvpA.Key)) continue; - - ProtectedString psB = b.Strings.Get(kvpA.Key); - if(psB == null) return false; - - // Ignore protection setting, compare values only - if(!psB.Equals(kvpA.Value, false)) return false; - } - - foreach(KeyValuePair kvpB in b.Strings) - { - if(PwDefs.IsStandardField(kvpB.Key)) continue; - - ProtectedString psA = a.Strings.Get(kvpB.Key); - if(psA == null) return false; - - // Must be equal by logic - Debug.Assert(psA.Equals(kvpB.Value, false)); - } - - if(a.Binaries.UCount != b.Binaries.UCount) return false; - foreach(KeyValuePair kvpBin in a.Binaries) - { - ProtectedBinary pbA = kvpBin.Value; - ProtectedBinary pbB = b.Binaries.Get(kvpBin.Key); - if(pbB == null) return false; - - // Ignore protection setting, compare values only - if(!pbB.Equals(pbA, false)) return false; - } - - return true; - } - - public uint DeleteEmptyGroups() - { - uint uDeleted = 0; - - PwObjectList l = m_pgRootGroup.GetGroups(true); - int iStart = (int)l.UCount - 1; - for(int i = iStart; i >= 0; --i) - { - PwGroup pg = l.GetAt((uint)i); - if((pg.Groups.UCount > 0) || (pg.Entries.UCount > 0)) continue; - - pg.ParentGroup.Groups.Remove(pg); - m_vDeletedObjects.Add(new PwDeletedObject(pg.Uuid, DateTime.UtcNow)); - - ++uDeleted; - } - - return uDeleted; - } - - public uint DeleteUnusedCustomIcons() - { - List lToDelete = new List(); - foreach(PwCustomIcon pwci in m_vCustomIcons) - lToDelete.Add(pwci.Uuid); - - GroupHandler gh = delegate(PwGroup pg) - { - PwUuid pwUuid = pg.CustomIconUuid; - if((pwUuid == null) || pwUuid.Equals(PwUuid.Zero)) return true; - - for(int i = 0; i < lToDelete.Count; ++i) - { - if(lToDelete[i].Equals(pwUuid)) - { - lToDelete.RemoveAt(i); - break; - } - } - - return true; - }; - - EntryHandler eh = delegate(PwEntry pe) - { - PwUuid pwUuid = pe.CustomIconUuid; - if((pwUuid == null) || pwUuid.Equals(PwUuid.Zero)) return true; - - for(int i = 0; i < lToDelete.Count; ++i) - { - if(lToDelete[i].Equals(pwUuid)) - { - lToDelete.RemoveAt(i); - break; - } - } - - return true; - }; - - gh(m_pgRootGroup); - m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh); - - uint uDeleted = 0; - foreach(PwUuid pwDel in lToDelete) - { - int nIndex = GetCustomIconIndex(pwDel); - if(nIndex < 0) { Debug.Assert(false); continue; } - - m_vCustomIcons.RemoveAt(nIndex); - ++uDeleted; - } - - if(uDeleted > 0) m_bUINeedsIconUpdate = true; - return uDeleted; - } - } -} diff --git a/ModernKeePassLib/PwDefs.cs b/ModernKeePassLib/PwDefs.cs deleted file mode 100644 index f3aade6..0000000 --- a/ModernKeePassLib/PwDefs.cs +++ /dev/null @@ -1,505 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Xml.Serialization; - -using ModernKeePassLib.Delegates; -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Serialization; - -namespace ModernKeePassLib -{ - /// - /// Contains KeePassLib-global definitions and enums. - /// - public static class PwDefs - { - /// - /// The product name. - /// - public const string ProductName = "KeePass Password Safe"; - - /// - /// A short, simple string representing the product name. The string - /// should contain no spaces, directory separator characters, etc. - /// - public const string ShortProductName = "KeePass"; - - internal const string UnixName = "keepass2"; - internal const string ResClass = "KeePass2"; // With initial capital - - /// - /// Version, encoded as 32-bit unsigned integer. - /// 2.00 = 0x02000000, 2.01 = 0x02000100, ..., 2.18 = 0x02010800. - /// As of 2.19, the version is encoded component-wise per byte, - /// e.g. 2.19 = 0x02130000. - /// It is highly recommended to use FileVersion64 instead. - /// - public const uint Version32 = 0x02270100; - - /// - /// Version, encoded as 64-bit unsigned integer - /// (component-wise, 16 bits per component). - /// - public const ulong FileVersion64 = 0x0002002700010000UL; - - /// - /// Version, encoded as string. - /// - public const string VersionString = "2.39.1"; - - public const string Copyright = @"Copyright © 2003-2018 Dominik Reichl"; - - /// - /// Product website URL. Terminated by a forward slash. - /// - public const string HomepageUrl = "https://keepass.info/"; - - /// - /// URL to the online translations page. - /// - public const string TranslationsUrl = "https://keepass.info/translations.html"; - - /// - /// URL to the online plugins page. - /// - public const string PluginsUrl = "https://keepass.info/plugins.html"; - - /// - /// Product donations URL. - /// - public const string DonationsUrl = "https://keepass.info/donate.html"; - - /// - /// URL to the root path of the online KeePass help. Terminated by - /// a forward slash. - /// - public const string HelpUrl = "https://keepass.info/help/"; - - /// - /// URL to a TXT file (eventually compressed) that contains information - /// about the latest KeePass version available on the website. - /// - public const string VersionUrl = "https://www.dominik-reichl.de/update/version2x.txt.gz"; - - /// - /// A DateTime object that represents the time when the assembly - /// was loaded. - /// - public static readonly DateTime DtDefaultNow = DateTime.UtcNow; - - /// - /// Default number of master key encryption/transformation rounds - /// (making dictionary attacks harder). - /// - public const ulong DefaultKeyEncryptionRounds = 60000; - - /// - /// Default identifier string for the title field. Should not contain - /// spaces, tabs or other whitespace. - /// - public const string TitleField = "Title"; - - /// - /// Default identifier string for the user name field. Should not contain - /// spaces, tabs or other whitespace. - /// - public const string UserNameField = "UserName"; - - /// - /// Default identifier string for the password field. Should not contain - /// spaces, tabs or other whitespace. - /// - public const string PasswordField = "Password"; - - /// - /// Default identifier string for the URL field. Should not contain - /// spaces, tabs or other whitespace. - /// - public const string UrlField = "URL"; - - /// - /// Default identifier string for the notes field. Should not contain - /// spaces, tabs or other whitespace. - /// - public const string NotesField = "Notes"; - - /// - /// Default identifier string for the field which will contain TAN indices. - /// - public const string TanIndexField = UserNameField; - - /// - /// Default title of an entry that is really a TAN entry. - /// - public const string TanTitle = @""; - - /// - /// Prefix of a custom auto-type string field. - /// - public const string AutoTypeStringPrefix = "S:"; - - /// - /// Default string representing a hidden password. - /// - public const string HiddenPassword = "********"; - - /// - /// Default auto-type keystroke sequence. If no custom sequence is - /// specified, this sequence is used. - /// - public const string DefaultAutoTypeSequence = @"{USERNAME}{TAB}{PASSWORD}{ENTER}"; - - /// - /// Default auto-type keystroke sequence for TAN entries. If no custom - /// sequence is specified, this sequence is used. - /// - public const string DefaultAutoTypeSequenceTan = @"{PASSWORD}"; - - /// - /// Check if a name is a standard field name. - /// - /// Input field name. - /// Returns true, if the field name is a standard - /// field name (title, user name, password, ...), otherwise false. - public static bool IsStandardField(string strFieldName) - { - Debug.Assert(strFieldName != null); if(strFieldName == null) return false; - - if(strFieldName.Equals(TitleField)) return true; - if(strFieldName.Equals(UserNameField)) return true; - if(strFieldName.Equals(PasswordField)) return true; - if(strFieldName.Equals(UrlField)) return true; - if(strFieldName.Equals(NotesField)) return true; - - return false; - } - - public static List GetStandardFields() - { - List l = new List(); - - l.Add(TitleField); - l.Add(UserNameField); - l.Add(PasswordField); - l.Add(UrlField); - l.Add(NotesField); - - return l; - } - - /// - /// Check if an entry is a TAN. - /// - /// Password entry. - /// Returns true if the entry is a TAN. - public static bool IsTanEntry(PwEntry pe) - { - Debug.Assert(pe != null); if(pe == null) return false; - - return (pe.Strings.ReadSafe(PwDefs.TitleField) == TanTitle); - } - - internal static string GetTranslationDisplayVersion(string strFileVersion) - { - if(strFileVersion == null) { Debug.Assert(false); return string.Empty; } - - if(strFileVersion == "2.39") return "2.39 / 2.39.1"; - - return strFileVersion; - } - } - - // #pragma warning disable 1591 // Missing XML comments warning - /// - /// Search parameters for group and entry searches. - /// - public sealed class SearchParameters - { - private string m_strText = string.Empty; - [DefaultValue("")] - public string SearchString - { - get { return m_strText; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strText = value; - } - } - - private bool m_bRegex = false; - [DefaultValue(false)] - public bool RegularExpression - { - get { return m_bRegex; } - set { m_bRegex = value; } - } - - private bool m_bSearchInTitles = true; - [DefaultValue(true)] - public bool SearchInTitles - { - get { return m_bSearchInTitles; } - set { m_bSearchInTitles = value; } - } - - private bool m_bSearchInUserNames = true; - [DefaultValue(true)] - public bool SearchInUserNames - { - get { return m_bSearchInUserNames; } - set { m_bSearchInUserNames = value; } - } - - private bool m_bSearchInPasswords = false; - [DefaultValue(false)] - public bool SearchInPasswords - { - get { return m_bSearchInPasswords; } - set { m_bSearchInPasswords = value; } - } - - private bool m_bSearchInUrls = true; - [DefaultValue(true)] - public bool SearchInUrls - { - get { return m_bSearchInUrls; } - set { m_bSearchInUrls = value; } - } - - private bool m_bSearchInNotes = true; - [DefaultValue(true)] - public bool SearchInNotes - { - get { return m_bSearchInNotes; } - set { m_bSearchInNotes = value; } - } - - private bool m_bSearchInOther = true; - [DefaultValue(true)] - public bool SearchInOther - { - get { return m_bSearchInOther; } - set { m_bSearchInOther = value; } - } - - private bool m_bSearchInStringNames = false; - [DefaultValue(false)] - public bool SearchInStringNames - { - get { return m_bSearchInStringNames; } - set { m_bSearchInStringNames = value; } - } - - private bool m_bSearchInTags = true; - [DefaultValue(true)] - public bool SearchInTags - { - get { return m_bSearchInTags; } - set { m_bSearchInTags = value; } - } - - private bool m_bSearchInUuids = false; - [DefaultValue(false)] - public bool SearchInUuids - { - get { return m_bSearchInUuids; } - set { m_bSearchInUuids = value; } - } - - private bool m_bSearchInGroupNames = false; - [DefaultValue(false)] - public bool SearchInGroupNames - { - get { return m_bSearchInGroupNames; } - set { m_bSearchInGroupNames = value; } - } - -#if ModernKeePassLib || KeePassUAP - private StringComparison m_scType = StringComparison.OrdinalIgnoreCase; -#else - private StringComparison m_scType = StringComparison.InvariantCultureIgnoreCase; -#endif - /// - /// String comparison type. Specifies the condition when the specified - /// text matches a group/entry string. - /// - public StringComparison ComparisonMode - { - get { return m_scType; } - set { m_scType = value; } - } - - private bool m_bExcludeExpired = false; - [DefaultValue(false)] - public bool ExcludeExpired - { - get { return m_bExcludeExpired; } - set { m_bExcludeExpired = value; } - } - - private bool m_bRespectEntrySearchingDisabled = true; - [DefaultValue(true)] - public bool RespectEntrySearchingDisabled - { - get { return m_bRespectEntrySearchingDisabled; } - set { m_bRespectEntrySearchingDisabled = value; } - } - - private StrPwEntryDelegate m_fnDataTrf = null; - [XmlIgnore] - public StrPwEntryDelegate DataTransformationFn - { - get { return m_fnDataTrf; } - set { m_fnDataTrf = value; } - } - - private string m_strDataTrf = string.Empty; - /// - /// Only for serialization. - /// - [DefaultValue("")] - public string DataTransformation - { - get { return m_strDataTrf; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strDataTrf = value; - } - } - - [XmlIgnore] - public static SearchParameters None - { - get - { - SearchParameters sp = new SearchParameters(); - - Debug.Assert(sp.m_strText.Length == 0); - Debug.Assert(!sp.m_bRegex); - sp.m_bSearchInTitles = false; - sp.m_bSearchInUserNames = false; - Debug.Assert(!sp.m_bSearchInPasswords); - sp.m_bSearchInUrls = false; - sp.m_bSearchInNotes = false; - sp.m_bSearchInOther = false; - Debug.Assert(!sp.m_bSearchInStringNames); - sp.m_bSearchInTags = false; - Debug.Assert(!sp.m_bSearchInUuids); - Debug.Assert(!sp.m_bSearchInGroupNames); - // Debug.Assert(sp.m_scType == StringComparison.InvariantCultureIgnoreCase); - Debug.Assert(!sp.m_bExcludeExpired); - Debug.Assert(sp.m_bRespectEntrySearchingDisabled); - - return sp; - } - } - - /// - /// Construct a new search parameters object. - /// - public SearchParameters() - { - } - - public SearchParameters Clone() - { - return (SearchParameters)this.MemberwiseClone(); - } - } - // #pragma warning restore 1591 // Missing XML comments warning - - // #pragma warning disable 1591 // Missing XML comments warning - /// - /// Memory protection configuration structure (for default fields). - /// - public sealed class MemoryProtectionConfig : IDeepCloneable - { - public bool ProtectTitle = false; - public bool ProtectUserName = false; - public bool ProtectPassword = true; - public bool ProtectUrl = false; - public bool ProtectNotes = false; - - // public bool AutoEnableVisualHiding = false; - - public MemoryProtectionConfig CloneDeep() - { - return (MemoryProtectionConfig)this.MemberwiseClone(); - } - - public bool GetProtection(string strField) - { - if(strField == PwDefs.TitleField) return this.ProtectTitle; - if(strField == PwDefs.UserNameField) return this.ProtectUserName; - if(strField == PwDefs.PasswordField) return this.ProtectPassword; - if(strField == PwDefs.UrlField) return this.ProtectUrl; - if(strField == PwDefs.NotesField) return this.ProtectNotes; - - return false; - } - } - // #pragma warning restore 1591 // Missing XML comments warning - - public sealed class ObjectTouchedEventArgs : EventArgs - { - private object m_o; - public object Object { get { return m_o; } } - - private bool m_bModified; - public bool Modified { get { return m_bModified; } } - - private bool m_bParentsTouched; - public bool ParentsTouched { get { return m_bParentsTouched; } } - - public ObjectTouchedEventArgs(object o, bool bModified, - bool bParentsTouched) - { - m_o = o; - m_bModified = bModified; - m_bParentsTouched = bParentsTouched; - } - } - - public sealed class IOAccessEventArgs : EventArgs - { - private IOConnectionInfo m_ioc; - public IOConnectionInfo IOConnectionInfo { get { return m_ioc; } } - - private IOConnectionInfo m_ioc2; - public IOConnectionInfo IOConnectionInfo2 { get { return m_ioc2; } } - - private IOAccessType m_t; - public IOAccessType Type { get { return m_t; } } - - public IOAccessEventArgs(IOConnectionInfo ioc, IOConnectionInfo ioc2, - IOAccessType t) - { - m_ioc = ioc; - m_ioc2 = ioc2; - m_t = t; - } - } -} diff --git a/ModernKeePassLib/PwDeletedObject.cs b/ModernKeePassLib/PwDeletedObject.cs deleted file mode 100644 index 3f10a09..0000000 --- a/ModernKeePassLib/PwDeletedObject.cs +++ /dev/null @@ -1,86 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -using ModernKeePassLib.Interfaces; - -namespace ModernKeePassLib -{ - /// - /// Represents an object that has been deleted. - /// - public sealed class PwDeletedObject : IDeepCloneable - { - private PwUuid m_uuid = PwUuid.Zero; - /// - /// UUID of the entry that has been deleted. - /// - public PwUuid Uuid - { - get { return m_uuid; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_uuid = value; - } - } - - private DateTime m_dtDeletionTime = PwDefs.DtDefaultNow; - /// - /// The date/time when the entry has been deleted. - /// - public DateTime DeletionTime - { - get { return m_dtDeletionTime; } - set { m_dtDeletionTime = value; } - } - - /// - /// Construct a new PwDeletedObject object. - /// - public PwDeletedObject() - { - } - - public PwDeletedObject(PwUuid uuid, DateTime dtDeletionTime) - { - if(uuid == null) throw new ArgumentNullException("uuid"); - - m_uuid = uuid; - m_dtDeletionTime = dtDeletionTime; - } - - /// - /// Clone the object. - /// - /// Value copy of the current object. - public PwDeletedObject CloneDeep() - { - PwDeletedObject pdo = new PwDeletedObject(); - - pdo.m_uuid = m_uuid; // PwUuid objects are immutable - pdo.m_dtDeletionTime = m_dtDeletionTime; - - return pdo; - } - } -} diff --git a/ModernKeePassLib/PwEntry.cs b/ModernKeePassLib/PwEntry.cs deleted file mode 100644 index 2f91d92..0000000 --- a/ModernKeePassLib/PwEntry.cs +++ /dev/null @@ -1,947 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -using System.Drawing; - -using ModernKeePassLib.Collections; -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib -{ - /// - /// A class representing a password entry. A password entry consists of several - /// fields like title, user name, password, etc. Each password entry has a - /// unique ID (UUID). - /// - public sealed class PwEntry : ITimeLogger, IStructureItem, IDeepCloneable - { - private PwUuid m_uuid = PwUuid.Zero; - private PwGroup m_pParentGroup = null; - private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow; - - private ProtectedStringDictionary m_listStrings = new ProtectedStringDictionary(); - private ProtectedBinaryDictionary m_listBinaries = new ProtectedBinaryDictionary(); - private AutoTypeConfig m_listAutoType = new AutoTypeConfig(); - private PwObjectList m_listHistory = new PwObjectList(); - - private PwIcon m_pwIcon = PwIcon.Key; - private PwUuid m_pwCustomIconID = PwUuid.Zero; - - private Color m_clrForeground = Color.Empty; - private Color m_clrBackground = Color.Empty; - - private DateTime m_tCreation = PwDefs.DtDefaultNow; - private DateTime m_tLastMod = PwDefs.DtDefaultNow; - private DateTime m_tLastAccess = PwDefs.DtDefaultNow; - private DateTime m_tExpire = PwDefs.DtDefaultNow; - private bool m_bExpires = false; - private ulong m_uUsageCount = 0; - - private string m_strOverrideUrl = string.Empty; - - private List m_vTags = new List(); - - private StringDictionaryEx m_dCustomData = new StringDictionaryEx(); - - /// - /// UUID of this entry. - /// - public PwUuid Uuid - { - get { return m_uuid; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_uuid = value; - } - } - - /// - /// Reference to a group which contains the current entry. - /// - public PwGroup ParentGroup - { - get { return m_pParentGroup; } - - // Plugins: use PwGroup.AddEntry instead. - internal set { m_pParentGroup = value; } - } - - /// - /// The date/time when the location of the object was last changed. - /// - public DateTime LocationChanged - { - get { return m_tParentGroupLastMod; } - set { m_tParentGroupLastMod = value; } - } - - /// - /// Get or set all entry strings. - /// - public ProtectedStringDictionary Strings - { - get { return m_listStrings; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_listStrings = value; - } - } - - /// - /// Get or set all entry binaries. - /// - public ProtectedBinaryDictionary Binaries - { - get { return m_listBinaries; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_listBinaries = value; - } - } - - /// - /// Get or set all auto-type window/keystroke sequence associations. - /// - public AutoTypeConfig AutoType - { - get { return m_listAutoType; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_listAutoType = value; - } - } - - /// - /// Get all previous versions of this entry (backups). - /// - public PwObjectList History - { - get { return m_listHistory; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_listHistory = value; - } - } - - /// - /// Image ID specifying the icon that will be used for this entry. - /// - public PwIcon IconId - { - get { return m_pwIcon; } - set { m_pwIcon = value; } - } - - /// - /// Get the custom icon ID. This value is 0, if no custom icon is - /// being used (i.e. the icon specified by the IconID property - /// should be displayed). - /// - public PwUuid CustomIconUuid - { - get { return m_pwCustomIconID; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_pwCustomIconID = value; - } - } - - /// - /// Get or set the foreground color of this entry. - /// - public Color ForegroundColor - { - get { return m_clrForeground; } - set { m_clrForeground = value; } - } - - /// - /// Get or set the background color of this entry. - /// - public Color BackgroundColor - { - get { return m_clrBackground; } - set { m_clrBackground = value; } - } - - /// - /// The date/time when this entry was created. - /// - public DateTime CreationTime - { - get { return m_tCreation; } - set { m_tCreation = value; } - } - - /// - /// The date/time when this entry was last modified. - /// - public DateTime LastModificationTime - { - get { return m_tLastMod; } - set { m_tLastMod = value; } - } - - /// - /// The date/time when this entry was last accessed (read). - /// - public DateTime LastAccessTime - { - get { return m_tLastAccess; } - set { m_tLastAccess = value; } - } - - /// - /// The date/time when this entry expires. Use the Expires property - /// to specify if the entry does actually expire or not. - /// - public DateTime ExpiryTime - { - get { return m_tExpire; } - set { m_tExpire = value; } - } - - /// - /// Specifies whether the entry expires or not. - /// - public bool Expires - { - get { return m_bExpires; } - set { m_bExpires = value; } - } - - /// - /// Get or set the usage count of the entry. To increase the usage - /// count by one, use the Touch function. - /// - public ulong UsageCount - { - get { return m_uUsageCount; } - set { m_uUsageCount = value; } - } - - /// - /// Entry-specific override URL. If this string is non-empty, - /// - public string OverrideUrl - { - get { return m_strOverrideUrl; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strOverrideUrl = value; - } - } - - /// - /// List of tags associated with this entry. - /// - public List Tags - { - get { return m_vTags; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_vTags = value; - } - } - - /// - /// Custom data container that can be used by plugins to store - /// own data in KeePass entries. - /// The data is stored in the encrypted part of encrypted - /// database files. - /// Use unique names for your items, e.g. "PluginName_ItemName". - /// - public StringDictionaryEx CustomData - { - get { return m_dCustomData; } - internal set - { - if(value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); } - m_dCustomData = value; - } - } - - public static EventHandler EntryTouched; - public EventHandler Touched; - - /// - /// Construct a new, empty password entry. Member variables will be initialized - /// to their default values. - /// - /// If true, a new UUID will be created - /// for this entry. If false, the UUID is zero and you must set it - /// manually later. - /// If true, the creation, last modification - /// and last access times will be set to the current system time. - public PwEntry(bool bCreateNewUuid, bool bSetTimes) - { - if(bCreateNewUuid) m_uuid = new PwUuid(true); - - if(bSetTimes) - { - DateTime dtNow = DateTime.UtcNow; - m_tCreation = dtNow; - m_tLastMod = dtNow; - m_tLastAccess = dtNow; - m_tParentGroupLastMod = dtNow; - } - } - - /// - /// Construct a new, empty password entry. Member variables will be initialized - /// to their default values. - /// - /// Reference to the containing group, this - /// parameter may be null and set later manually. - /// If true, a new UUID will be created - /// for this entry. If false, the UUID is zero and you must set it - /// manually later. - /// If true, the creation, last modification - /// and last access times will be set to the current system time. - [Obsolete("Use a different constructor. To add an entry to a group, use AddEntry of PwGroup.")] - public PwEntry(PwGroup pwParentGroup, bool bCreateNewUuid, bool bSetTimes) - { - m_pParentGroup = pwParentGroup; - - if(bCreateNewUuid) m_uuid = new PwUuid(true); - - if(bSetTimes) - { - DateTime dtNow = DateTime.UtcNow; - m_tCreation = dtNow; - m_tLastMod = dtNow; - m_tLastAccess = dtNow; - m_tParentGroupLastMod = dtNow; - } - } - -#if DEBUG - // For display in debugger - public override string ToString() - { - return (@"PwEntry '" + m_listStrings.ReadSafe(PwDefs.TitleField) + @"'"); - } -#endif - - /// - /// Clone the current entry. The returned entry is an exact value copy - /// of the current entry (including UUID and parent group reference). - /// All mutable members are cloned. - /// - /// Exact value clone. All references to mutable values changed. - public PwEntry CloneDeep() - { - PwEntry peNew = new PwEntry(false, false); - - peNew.m_uuid = m_uuid; // PwUuid is immutable - peNew.m_pParentGroup = m_pParentGroup; - peNew.m_tParentGroupLastMod = m_tParentGroupLastMod; - - peNew.m_listStrings = m_listStrings.CloneDeep(); - peNew.m_listBinaries = m_listBinaries.CloneDeep(); - peNew.m_listAutoType = m_listAutoType.CloneDeep(); - peNew.m_listHistory = m_listHistory.CloneDeep(); - - peNew.m_pwIcon = m_pwIcon; - peNew.m_pwCustomIconID = m_pwCustomIconID; - - peNew.m_clrForeground = m_clrForeground; - peNew.m_clrBackground = m_clrBackground; - - peNew.m_tCreation = m_tCreation; - peNew.m_tLastMod = m_tLastMod; - peNew.m_tLastAccess = m_tLastAccess; - peNew.m_tExpire = m_tExpire; - peNew.m_bExpires = m_bExpires; - peNew.m_uUsageCount = m_uUsageCount; - - peNew.m_strOverrideUrl = m_strOverrideUrl; - - peNew.m_vTags = new List(m_vTags); - - peNew.m_dCustomData = m_dCustomData.CloneDeep(); - - return peNew; - } - - public PwEntry CloneStructure() - { - PwEntry peNew = new PwEntry(false, false); - - peNew.m_uuid = m_uuid; // PwUuid is immutable - peNew.m_tParentGroupLastMod = m_tParentGroupLastMod; - // Do not assign m_pParentGroup - - return peNew; - } - - private static PwCompareOptions BuildCmpOpt(bool bIgnoreParentGroup, - bool bIgnoreLastMod, bool bIgnoreLastAccess, bool bIgnoreHistory, - bool bIgnoreThisLastBackup) - { - PwCompareOptions pwOpt = PwCompareOptions.None; - if(bIgnoreParentGroup) pwOpt |= PwCompareOptions.IgnoreParentGroup; - if(bIgnoreLastMod) pwOpt |= PwCompareOptions.IgnoreLastMod; - if(bIgnoreLastAccess) pwOpt |= PwCompareOptions.IgnoreLastAccess; - if(bIgnoreHistory) pwOpt |= PwCompareOptions.IgnoreHistory; - if(bIgnoreThisLastBackup) pwOpt |= PwCompareOptions.IgnoreLastBackup; - return pwOpt; - } - - [Obsolete] - public bool EqualsEntry(PwEntry pe, bool bIgnoreParentGroup, bool bIgnoreLastMod, - bool bIgnoreLastAccess, bool bIgnoreHistory, bool bIgnoreThisLastBackup) - { - return EqualsEntry(pe, BuildCmpOpt(bIgnoreParentGroup, bIgnoreLastMod, - bIgnoreLastAccess, bIgnoreHistory, bIgnoreThisLastBackup), - MemProtCmpMode.None); - } - - [Obsolete] - public bool EqualsEntry(PwEntry pe, bool bIgnoreParentGroup, bool bIgnoreLastMod, - bool bIgnoreLastAccess, bool bIgnoreHistory, bool bIgnoreThisLastBackup, - MemProtCmpMode mpCmpStr) - { - return EqualsEntry(pe, BuildCmpOpt(bIgnoreParentGroup, bIgnoreLastMod, - bIgnoreLastAccess, bIgnoreHistory, bIgnoreThisLastBackup), mpCmpStr); - } - - public bool EqualsEntry(PwEntry pe, PwCompareOptions pwOpt, - MemProtCmpMode mpCmpStr) - { - if(pe == null) { Debug.Assert(false); return false; } - - bool bNeEqStd = ((pwOpt & PwCompareOptions.NullEmptyEquivStd) != - PwCompareOptions.None); - bool bIgnoreLastAccess = ((pwOpt & PwCompareOptions.IgnoreLastAccess) != - PwCompareOptions.None); - bool bIgnoreLastMod = ((pwOpt & PwCompareOptions.IgnoreLastMod) != - PwCompareOptions.None); - - if(!m_uuid.Equals(pe.m_uuid)) return false; - if((pwOpt & PwCompareOptions.IgnoreParentGroup) == PwCompareOptions.None) - { - if(m_pParentGroup != pe.m_pParentGroup) return false; - if(!bIgnoreLastMod && (m_tParentGroupLastMod != pe.m_tParentGroupLastMod)) - return false; - } - - if(!m_listStrings.EqualsDictionary(pe.m_listStrings, pwOpt, mpCmpStr)) - return false; - if(!m_listBinaries.EqualsDictionary(pe.m_listBinaries)) return false; - - if(!m_listAutoType.Equals(pe.m_listAutoType)) return false; - - if((pwOpt & PwCompareOptions.IgnoreHistory) == PwCompareOptions.None) - { - bool bIgnoreLastBackup = ((pwOpt & PwCompareOptions.IgnoreLastBackup) != - PwCompareOptions.None); - - if(!bIgnoreLastBackup && (m_listHistory.UCount != pe.m_listHistory.UCount)) - return false; - if(bIgnoreLastBackup && (m_listHistory.UCount == 0)) - { - Debug.Assert(false); - return false; - } - if(bIgnoreLastBackup && ((m_listHistory.UCount - 1) != pe.m_listHistory.UCount)) - return false; - - PwCompareOptions cmpSub = PwCompareOptions.IgnoreParentGroup; - if(bNeEqStd) cmpSub |= PwCompareOptions.NullEmptyEquivStd; - if(bIgnoreLastMod) cmpSub |= PwCompareOptions.IgnoreLastMod; - if(bIgnoreLastAccess) cmpSub |= PwCompareOptions.IgnoreLastAccess; - - for(uint uHist = 0; uHist < pe.m_listHistory.UCount; ++uHist) - { - if(!m_listHistory.GetAt(uHist).EqualsEntry(pe.m_listHistory.GetAt( - uHist), cmpSub, MemProtCmpMode.None)) - return false; - } - } - - if(m_pwIcon != pe.m_pwIcon) return false; - if(!m_pwCustomIconID.Equals(pe.m_pwCustomIconID)) return false; - - if(m_clrForeground != pe.m_clrForeground) return false; - if(m_clrBackground != pe.m_clrBackground) return false; - - if(m_tCreation != pe.m_tCreation) return false; - if(!bIgnoreLastMod && (m_tLastMod != pe.m_tLastMod)) return false; - if(!bIgnoreLastAccess && (m_tLastAccess != pe.m_tLastAccess)) return false; - if(m_tExpire != pe.m_tExpire) return false; - if(m_bExpires != pe.m_bExpires) return false; - if(!bIgnoreLastAccess && (m_uUsageCount != pe.m_uUsageCount)) return false; - - if(m_strOverrideUrl != pe.m_strOverrideUrl) return false; - - if(m_vTags.Count != pe.m_vTags.Count) return false; - for(int iTag = 0; iTag < m_vTags.Count; ++iTag) - { - if(m_vTags[iTag] != pe.m_vTags[iTag]) return false; - } - - if(!m_dCustomData.Equals(pe.m_dCustomData)) return false; - - return true; - } - - /// - /// Assign properties to the current entry based on a template entry. - /// - /// Template entry. Must not be null. - /// Only set the properties of the template entry - /// if it is newer than the current one. - /// If true, the history will be - /// copied, too. - /// If true, the - /// LocationChanged property is copied, otherwise not. - public void AssignProperties(PwEntry peTemplate, bool bOnlyIfNewer, - bool bIncludeHistory, bool bAssignLocationChanged) - { - if(peTemplate == null) { Debug.Assert(false); throw new ArgumentNullException("peTemplate"); } - - if(bOnlyIfNewer && (TimeUtil.Compare(peTemplate.m_tLastMod, - m_tLastMod, true) < 0)) - return; - - // Template UUID should be the same as the current one - Debug.Assert(m_uuid.Equals(peTemplate.m_uuid)); - m_uuid = peTemplate.m_uuid; - - if(bAssignLocationChanged) - m_tParentGroupLastMod = peTemplate.m_tParentGroupLastMod; - - m_listStrings = peTemplate.m_listStrings.CloneDeep(); - m_listBinaries = peTemplate.m_listBinaries.CloneDeep(); - m_listAutoType = peTemplate.m_listAutoType.CloneDeep(); - if(bIncludeHistory) - m_listHistory = peTemplate.m_listHistory.CloneDeep(); - - m_pwIcon = peTemplate.m_pwIcon; - m_pwCustomIconID = peTemplate.m_pwCustomIconID; // Immutable - - m_clrForeground = peTemplate.m_clrForeground; - m_clrBackground = peTemplate.m_clrBackground; - - m_tCreation = peTemplate.m_tCreation; - m_tLastMod = peTemplate.m_tLastMod; - m_tLastAccess = peTemplate.m_tLastAccess; - m_tExpire = peTemplate.m_tExpire; - m_bExpires = peTemplate.m_bExpires; - m_uUsageCount = peTemplate.m_uUsageCount; - - m_strOverrideUrl = peTemplate.m_strOverrideUrl; - - m_vTags = new List(peTemplate.m_vTags); - - m_dCustomData = peTemplate.m_dCustomData.CloneDeep(); - } - - /// - /// Touch the entry. This function updates the internal last access - /// time. If the parameter is true, - /// the last modification time gets updated, too. - /// - /// Modify last modification time. - public void Touch(bool bModified) - { - Touch(bModified, true); - } - - /// - /// Touch the entry. This function updates the internal last access - /// time. If the parameter is true, - /// the last modification time gets updated, too. - /// - /// Modify last modification time. - /// If true, all parent objects - /// get touched, too. - public void Touch(bool bModified, bool bTouchParents) - { - m_tLastAccess = DateTime.UtcNow; - ++m_uUsageCount; - - if(bModified) m_tLastMod = m_tLastAccess; - - if(this.Touched != null) - this.Touched(this, new ObjectTouchedEventArgs(this, - bModified, bTouchParents)); - if(PwEntry.EntryTouched != null) - PwEntry.EntryTouched(this, new ObjectTouchedEventArgs(this, - bModified, bTouchParents)); - - if(bTouchParents && (m_pParentGroup != null)) - m_pParentGroup.Touch(bModified, true); - } - - /// - /// Create a backup of this entry. The backup item doesn't contain any - /// history items. - /// - [Obsolete] - public void CreateBackup() - { - CreateBackup(null); - } - - /// - /// Create a backup of this entry. The backup item doesn't contain any - /// history items. - /// If this parameter isn't null, - /// the history list is maintained automatically (i.e. old backups are - /// deleted if there are too many or the history size is too large). - /// This parameter may be null (no maintenance then). - /// - public void CreateBackup(PwDatabase pwHistMntcSettings) - { - PwEntry peCopy = CloneDeep(); - peCopy.History = new PwObjectList(); // Remove history - - m_listHistory.Add(peCopy); // Must be added at end, see EqualsEntry - - if(pwHistMntcSettings != null) MaintainBackups(pwHistMntcSettings); - } - - /// - /// Restore an entry snapshot from backups. - /// - /// Index of the backup item, to which - /// should be reverted. - [Obsolete] - public void RestoreFromBackup(uint uBackupIndex) - { - RestoreFromBackup(uBackupIndex, null); - } - - /// - /// Restore an entry snapshot from backups. - /// - /// Index of the backup item, to which - /// should be reverted. - /// If this parameter isn't null, - /// the history list is maintained automatically (i.e. old backups are - /// deleted if there are too many or the history size is too large). - /// This parameter may be null (no maintenance then). - public void RestoreFromBackup(uint uBackupIndex, PwDatabase pwHistMntcSettings) - { - Debug.Assert(uBackupIndex < m_listHistory.UCount); - if(uBackupIndex >= m_listHistory.UCount) - throw new ArgumentOutOfRangeException("uBackupIndex"); - - PwEntry pe = m_listHistory.GetAt(uBackupIndex); - Debug.Assert(pe != null); if(pe == null) throw new InvalidOperationException(); - - CreateBackup(pwHistMntcSettings); // Backup current data before restoring - AssignProperties(pe, false, false, false); - } - - public bool HasBackupOfData(PwEntry peData, bool bIgnoreLastMod, - bool bIgnoreLastAccess) - { - if(peData == null) { Debug.Assert(false); return false; } - - PwCompareOptions cmpOpt = (PwCompareOptions.IgnoreParentGroup | - PwCompareOptions.IgnoreHistory | PwCompareOptions.NullEmptyEquivStd); - if(bIgnoreLastMod) cmpOpt |= PwCompareOptions.IgnoreLastMod; - if(bIgnoreLastAccess) cmpOpt |= PwCompareOptions.IgnoreLastAccess; - - foreach(PwEntry pe in m_listHistory) - { - if(pe.EqualsEntry(peData, cmpOpt, MemProtCmpMode.None)) return true; - } - - return false; - } - - /// - /// Delete old history items if there are too many or the history - /// size is too large. - /// If one or more history items have been deleted, true - /// is returned. Otherwise false. - /// - public bool MaintainBackups(PwDatabase pwSettings) - { - if(pwSettings == null) { Debug.Assert(false); return false; } - - bool bDeleted = false; - - int nMaxItems = pwSettings.HistoryMaxItems; - if(nMaxItems >= 0) - { - while(m_listHistory.UCount > (uint)nMaxItems) - { - RemoveOldestBackup(); - bDeleted = true; - } - } - - long lMaxSize = pwSettings.HistoryMaxSize; - if(lMaxSize >= 0) - { - while(true) - { - ulong uHistSize = 0; - foreach(PwEntry pe in m_listHistory) { uHistSize += pe.GetSize(); } - - if(uHistSize > (ulong)lMaxSize) - { - RemoveOldestBackup(); - bDeleted = true; - } - else break; - } - } - - return bDeleted; - } - - private void RemoveOldestBackup() - { - DateTime dtMin = TimeUtil.SafeMaxValueUtc; - uint idxRemove = uint.MaxValue; - - for(uint u = 0; u < m_listHistory.UCount; ++u) - { - PwEntry pe = m_listHistory.GetAt(u); - if(TimeUtil.Compare(pe.LastModificationTime, dtMin, true) < 0) - { - idxRemove = u; - dtMin = pe.LastModificationTime; - } - } - - if(idxRemove != uint.MaxValue) m_listHistory.RemoveAt(idxRemove); - } - - public bool GetAutoTypeEnabled() - { - if(!m_listAutoType.Enabled) return false; - - if(m_pParentGroup != null) - return m_pParentGroup.GetAutoTypeEnabledInherited(); - - return PwGroup.DefaultAutoTypeEnabled; - } - - public string GetAutoTypeSequence() - { - string strSeq = m_listAutoType.DefaultSequence; - - PwGroup pg = m_pParentGroup; - while(pg != null) - { - if(strSeq.Length != 0) break; - - strSeq = pg.DefaultAutoTypeSequence; - pg = pg.ParentGroup; - } - - if(strSeq.Length != 0) return strSeq; - - if(PwDefs.IsTanEntry(this)) return PwDefs.DefaultAutoTypeSequenceTan; - return PwDefs.DefaultAutoTypeSequence; - } - - public bool GetSearchingEnabled() - { - if(m_pParentGroup != null) - return m_pParentGroup.GetSearchingEnabledInherited(); - - return PwGroup.DefaultSearchingEnabled; - } - - /// - /// Approximate the total size (in process memory) of this entry - /// in bytes (including strings, binaries and history entries). - /// - /// Size in bytes. - public ulong GetSize() - { - // This method assumes 64-bit pointers/references and Unicode - // strings (i.e. 2 bytes per character) - - ulong cb = 248; // Number of bytes; approx. fixed length data - ulong cc = 0; // Number of characters - - cb += (ulong)m_listStrings.UCount * 40; - foreach(KeyValuePair kvpStr in m_listStrings) - cc += (ulong)kvpStr.Key.Length + (ulong)kvpStr.Value.Length; - - cb += (ulong)m_listBinaries.UCount * 65; - foreach(KeyValuePair kvpBin in m_listBinaries) - { - cc += (ulong)kvpBin.Key.Length; - cb += (ulong)kvpBin.Value.Length; - } - - cc += (ulong)m_listAutoType.DefaultSequence.Length; - cb += (ulong)m_listAutoType.AssociationsCount * 24; - foreach(AutoTypeAssociation a in m_listAutoType.Associations) - cc += (ulong)a.WindowName.Length + (ulong)a.Sequence.Length; - - cb += (ulong)m_listHistory.UCount * 8; - foreach(PwEntry peHistory in m_listHistory) - cb += peHistory.GetSize(); - - cc += (ulong)m_strOverrideUrl.Length; - - cb += (ulong)m_vTags.Count * 8; - foreach(string strTag in m_vTags) - cc += (ulong)strTag.Length; - - cb += (ulong)m_dCustomData.Count * 16; - foreach(KeyValuePair kvp in m_dCustomData) - cc += (ulong)kvp.Key.Length + (ulong)kvp.Value.Length; - - return (cb + (cc << 1)); - } - - public bool HasTag(string strTag) - { - if(string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; } - - for(int i = 0; i < m_vTags.Count; ++i) - { - if(m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) return true; - } - - return false; - } - - public bool AddTag(string strTag) - { - if(string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; } - - for(int i = 0; i < m_vTags.Count; ++i) - { - if(m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) return false; - } - - m_vTags.Add(strTag); - return true; - } - - public bool RemoveTag(string strTag) - { - if(string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; } - - for(int i = 0; i < m_vTags.Count; ++i) - { - if(m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) - { - m_vTags.RemoveAt(i); - return true; - } - } - - return false; - } - - public bool IsContainedIn(PwGroup pgContainer) - { - PwGroup pgCur = m_pParentGroup; - while(pgCur != null) - { - if(pgCur == pgContainer) return true; - - pgCur = pgCur.ParentGroup; - } - - return false; - } - - public void SetUuid(PwUuid pwNewUuid, bool bAlsoChangeHistoryUuids) - { - this.Uuid = pwNewUuid; - - if(bAlsoChangeHistoryUuids) - { - foreach(PwEntry peHist in m_listHistory) - { - peHist.Uuid = pwNewUuid; - } - } - } - - public void SetCreatedNow() - { - DateTime dt = DateTime.UtcNow; - - m_tCreation = dt; - m_tLastAccess = dt; - } - - public PwEntry Duplicate() - { - PwEntry pe = CloneDeep(); - - pe.SetUuid(new PwUuid(true), true); - pe.SetCreatedNow(); - - return pe; - } - } - - public sealed class PwEntryComparer : IComparer - { - private string m_strFieldName; - private bool m_bCaseInsensitive; - private bool m_bCompareNaturally; - - public PwEntryComparer(string strFieldName, bool bCaseInsensitive, - bool bCompareNaturally) - { - if(strFieldName == null) throw new ArgumentNullException("strFieldName"); - - m_strFieldName = strFieldName; - m_bCaseInsensitive = bCaseInsensitive; - m_bCompareNaturally = bCompareNaturally; - } - - public int Compare(PwEntry a, PwEntry b) - { - string strA = a.Strings.ReadSafe(m_strFieldName); - string strB = b.Strings.ReadSafe(m_strFieldName); - - if(m_bCompareNaturally) return StrUtil.CompareNaturally(strA, strB); - -#if ModernKeePassLib || KeePassRT - return string.Compare(strA, strB, m_bCaseInsensitive ? - StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture); -#else - return string.Compare(strA, strB, m_bCaseInsensitive); -#endif - } - } -} diff --git a/ModernKeePassLib/PwEnums.cs b/ModernKeePassLib/PwEnums.cs deleted file mode 100644 index 9befce9..0000000 --- a/ModernKeePassLib/PwEnums.cs +++ /dev/null @@ -1,319 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; - -namespace ModernKeePassLib -{ - /// - /// Compression algorithm specifiers. - /// - public enum PwCompressionAlgorithm - { - /// - /// No compression. - /// - None = 0, - - /// - /// GZip compression. - /// - GZip = 1, - - /// - /// Virtual field: currently known number of algorithms. Should not be used - /// by plugins or libraries -- it's used internally only. - /// - Count = 2 - } - - /// - /// Tree traversal methods. - /// - public enum TraversalMethod - { - /// - /// Don't traverse the tree. - /// - None = 0, - - /// - /// Traverse the tree in pre-order mode, i.e. first visit all items - /// in the current node, then visit all subnodes. - /// - PreOrder = 1 - } - - /// - /// Methods for merging password databases/entries. - /// - public enum PwMergeMethod - { - // Do not change the explicitly assigned values, otherwise - // serialization (e.g. of Ecas triggers) breaks - None = 0, - OverwriteExisting = 1, - KeepExisting = 2, - OverwriteIfNewer = 3, - CreateNewUuids = 4, - Synchronize = 5 - } - - /// - /// Icon identifiers for groups and password entries. - /// - public enum PwIcon - { - Key = 0, - World, - Warning, - NetworkServer, - MarkedDirectory, - UserCommunication, - Parts, - Notepad, - WorldSocket, - Identity, - PaperReady, - Digicam, - IRCommunication, - MultiKeys, - Energy, - Scanner, - WorldStar, - CDRom, - Monitor, - EMail, - Configuration, - ClipboardReady, - PaperNew, - Screen, - EnergyCareful, - EMailBox, - Disk, - Drive, - PaperQ, - TerminalEncrypted, - Console, - Printer, - ProgramIcons, - Run, - Settings, - WorldComputer, - Archive, - Homebanking, - DriveWindows, - Clock, - EMailSearch, - PaperFlag, - Memory, - TrashBin, - Note, - Expired, - Info, - Package, - Folder, - FolderOpen, - FolderPackage, - LockOpen, - PaperLocked, - Checked, - Pen, - Thumbnail, - Book, - List, - UserKey, - Tool, - Home, - Star, - Tux, - Feather, - Apple, - Wiki, - Money, - Certificate, - BlackBerry, - - /// - /// Virtual identifier -- represents the number of icons. - /// - Count - } - - public enum ProxyServerType - { - None = 0, - System = 1, - Manual = 2 - } - - public enum ProxyAuthType - { - None = 0, - - /// - /// Use default user credentials (provided by the system). - /// - Default = 1, - - Manual = 2, - - /// - /// Default or Manual, depending on whether - /// manual credentials are available. - /// This type exists for supporting upgrading from KeePass - /// 2.28 to 2.29; the user cannot select this type. - /// - Auto = 3 - } - - /// - /// Comparison modes for in-memory protected objects. - /// - public enum MemProtCmpMode - { - /// - /// Ignore the in-memory protection states. - /// - None = 0, - - /// - /// Ignore the in-memory protection states of standard - /// objects; do compare in-memory protection states of - /// custom objects. - /// - CustomOnly, - - /// - /// Compare in-memory protection states. - /// - Full - } - - [Flags] - public enum PwCompareOptions - { - None = 0x0, - - /// - /// Empty standard string fields are considered to be the - /// same as non-existing standard string fields. - /// This doesn't affect custom string comparisons. - /// - NullEmptyEquivStd = 0x1, - - IgnoreParentGroup = 0x2, - IgnoreLastAccess = 0x4, - IgnoreLastMod = 0x8, - IgnoreHistory = 0x10, - IgnoreLastBackup = 0x20, - - // For groups: - PropertiesOnly = 0x40, - - IgnoreTimes = (IgnoreLastAccess | IgnoreLastMod) - } - - public enum IOAccessType - { - None = 0, - - /// - /// The IO connection is being opened for reading. - /// - Read = 1, - - /// - /// The IO connection is being opened for writing. - /// - Write = 2, - - /// - /// The IO connection is being opened for testing - /// whether a file/object exists. - /// - Exists = 3, - - /// - /// The IO connection is being opened for deleting a file/object. - /// - Delete = 4, - - /// - /// The IO connection is being opened for renaming/moving a file/object. - /// - Move = 5 - } - - // public enum PwLogicalOp - // { - // None = 0, - // Or = 1, - // And = 2, - // NOr = 3, - // NAnd = 4 - // } - - [Flags] - public enum AppRunFlags - { - None = 0, - GetStdOutput = 1, - WaitForExit = 2, - - // https://sourceforge.net/p/keepass/patches/84/ - /// - /// This flag prevents any handles being garbage-collected - /// before the started process has terminated, without - /// blocking the current thread. - /// - GCKeepAlive = 4, - - // https://sourceforge.net/p/keepass/patches/85/ - DoEvents = 8, - DisableForms = 16 - } - - [Flags] - public enum ScaleTransformFlags - { - None = 0, - - /// - /// UIIcon indicates that the returned image is going - /// to be displayed as icon in the UI and that it is not - /// subject to future changes in size. - /// - UIIcon = 1 - } - - public enum DesktopType - { - None = 0, - Windows, - Gnome, - Kde, - Unity, - Lxde, - Xfce, - Mate, - Cinnamon, - Pantheon - } -} diff --git a/ModernKeePassLib/PwGroup.cs b/ModernKeePassLib/PwGroup.cs deleted file mode 100644 index 0649a6e..0000000 --- a/ModernKeePassLib/PwGroup.cs +++ /dev/null @@ -1,1664 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text.RegularExpressions; - -using ModernKeePassLib.Collections; -using ModernKeePassLib.Delegates; -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib -{ - /// - /// A group containing several password entries. - /// - public sealed class PwGroup : ITimeLogger, IStructureItem, IDeepCloneable - { - public const bool DefaultAutoTypeEnabled = true; - public const bool DefaultSearchingEnabled = true; - - private PwObjectList m_listGroups = new PwObjectList(); - private PwObjectList m_listEntries = new PwObjectList(); - private PwGroup m_pParentGroup = null; - private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow; - - private PwUuid m_uuid = PwUuid.Zero; - private string m_strName = string.Empty; - private string m_strNotes = string.Empty; - - private PwIcon m_pwIcon = PwIcon.Folder; - private PwUuid m_pwCustomIconID = PwUuid.Zero; - - private DateTime m_tCreation = PwDefs.DtDefaultNow; - private DateTime m_tLastMod = PwDefs.DtDefaultNow; - private DateTime m_tLastAccess = PwDefs.DtDefaultNow; - private DateTime m_tExpire = PwDefs.DtDefaultNow; - private bool m_bExpires = false; - private ulong m_uUsageCount = 0; - - private bool m_bIsExpanded = true; - private bool m_bVirtual = false; - - private string m_strDefaultAutoTypeSequence = string.Empty; - - private bool? m_bEnableAutoType = null; - private bool? m_bEnableSearching = null; - - private PwUuid m_pwLastTopVisibleEntry = PwUuid.Zero; - - private StringDictionaryEx m_dCustomData = new StringDictionaryEx(); - - /// - /// UUID of this group. - /// - public PwUuid Uuid - { - get { return m_uuid; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_uuid = value; - } - } - - /// - /// The name of this group. Cannot be null. - /// - public string Name - { - get { return m_strName; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_strName = value; - } - } - - /// - /// Comments about this group. Cannot be null. - /// - public string Notes - { - get { return m_strNotes; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_strNotes = value; - } - } - - /// - /// Icon of the group. - /// - public PwIcon IconId - { - get { return m_pwIcon; } - set { m_pwIcon = value; } - } - - /// - /// Get the custom icon ID. This value is 0, if no custom icon is - /// being used (i.e. the icon specified by the IconID property - /// should be displayed). - /// - public PwUuid CustomIconUuid - { - get { return m_pwCustomIconID; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_pwCustomIconID = value; - } - } - - /// - /// Reference to the group to which this group belongs. May be null. - /// - public PwGroup ParentGroup - { - get { return m_pParentGroup; } - - // Plugins: use PwGroup.AddGroup instead. - internal set { Debug.Assert(value != this); m_pParentGroup = value; } - } - - /// - /// The date/time when the location of the object was last changed. - /// - public DateTime LocationChanged - { - get { return m_tParentGroupLastMod; } - set { m_tParentGroupLastMod = value; } - } - - /// - /// A flag that specifies if the group is shown as expanded or - /// collapsed in the user interface. - /// - public bool IsExpanded - { - get { return m_bIsExpanded; } - set { m_bIsExpanded = value; } - } - - /// - /// The date/time when this group was created. - /// - public DateTime CreationTime - { - get { return m_tCreation; } - set { m_tCreation = value; } - } - - /// - /// The date/time when this group was last modified. - /// - public DateTime LastModificationTime - { - get { return m_tLastMod; } - set { m_tLastMod = value; } - } - - /// - /// The date/time when this group was last accessed (read). - /// - public DateTime LastAccessTime - { - get { return m_tLastAccess; } - set { m_tLastAccess = value; } - } - - /// - /// The date/time when this group expires. - /// - public DateTime ExpiryTime - { - get { return m_tExpire; } - set { m_tExpire = value; } - } - - /// - /// Flag that determines if the group expires. - /// - public bool Expires - { - get { return m_bExpires; } - set { m_bExpires = value; } - } - - /// - /// Get or set the usage count of the group. To increase the usage - /// count by one, use the Touch function. - /// - public ulong UsageCount - { - get { return m_uUsageCount; } - set { m_uUsageCount = value; } - } - - /// - /// Get a list of subgroups in this group. - /// - public PwObjectList Groups - { - get { return m_listGroups; } - } - - /// - /// Get a list of entries in this group. - /// - public PwObjectList Entries - { - get { return m_listEntries; } - } - - /// - /// A flag specifying whether this group is virtual or not. Virtual - /// groups can contain links to entries stored in other groups. - /// Note that this flag has to be interpreted and set by the calling - /// code; it won't prevent you from accessing and modifying the list - /// of entries in this group in any way. - /// - public bool IsVirtual - { - get { return m_bVirtual; } - set { m_bVirtual = value; } - } - - /// - /// Default auto-type keystroke sequence for all entries in - /// this group. This property can be an empty string, which - /// means that the value should be inherited from the parent. - /// - public string DefaultAutoTypeSequence - { - get { return m_strDefaultAutoTypeSequence; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_strDefaultAutoTypeSequence = value; - } - } - - public bool? EnableAutoType - { - get { return m_bEnableAutoType; } - set { m_bEnableAutoType = value; } - } - - public bool? EnableSearching - { - get { return m_bEnableSearching; } - set { m_bEnableSearching = value; } - } - - public PwUuid LastTopVisibleEntry - { - get { return m_pwLastTopVisibleEntry; } - set - { - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - m_pwLastTopVisibleEntry = value; - } - } - - /// - /// Custom data container that can be used by plugins to store - /// own data in KeePass groups. - /// The data is stored in the encrypted part of encrypted - /// database files. - /// Use unique names for your items, e.g. "PluginName_ItemName". - /// - public StringDictionaryEx CustomData - { - get { return m_dCustomData; } - internal set - { - if(value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); } - m_dCustomData = value; - } - } - - public static EventHandler GroupTouched; - public EventHandler Touched; - - /// - /// Construct a new, empty group. - /// - public PwGroup() - { - } - - /// - /// Construct a new, empty group. - /// - /// Create a new UUID for this group. - /// Set creation, last access and last modification times to the current time. - public PwGroup(bool bCreateNewUuid, bool bSetTimes) - { - if(bCreateNewUuid) m_uuid = new PwUuid(true); - - if(bSetTimes) - { - DateTime dtNow = DateTime.UtcNow; - m_tCreation = dtNow; - m_tLastMod = dtNow; - m_tLastAccess = dtNow; - m_tParentGroupLastMod = dtNow; - } - } - - /// - /// Construct a new group. - /// - /// Create a new UUID for this group. - /// Set creation, last access and last modification times to the current time. - /// Name of the new group. - /// Icon of the new group. - public PwGroup(bool bCreateNewUuid, bool bSetTimes, string strName, PwIcon pwIcon) - { - if(bCreateNewUuid) m_uuid = new PwUuid(true); - - if(bSetTimes) - { - DateTime dtNow = DateTime.UtcNow; - m_tCreation = dtNow; - m_tLastMod = dtNow; - m_tLastAccess = dtNow; - m_tParentGroupLastMod = dtNow; - } - - if(strName != null) m_strName = strName; - - m_pwIcon = pwIcon; - } - -#if DEBUG - // For display in debugger - public override string ToString() - { - return (@"PwGroup '" + m_strName + @"'"); - } -#endif - - /// - /// Deeply clone the current group. The returned group will be an exact - /// value copy of the current object (including UUID, etc.). - /// - /// Exact value copy of the current PwGroup object. - public PwGroup CloneDeep() - { - PwGroup pg = new PwGroup(false, false); - - pg.m_uuid = m_uuid; // PwUuid is immutable - - pg.m_listGroups = m_listGroups.CloneDeep(); - pg.m_listEntries = m_listEntries.CloneDeep(); - pg.m_pParentGroup = m_pParentGroup; - pg.m_tParentGroupLastMod = m_tParentGroupLastMod; - - pg.m_strName = m_strName; - pg.m_strNotes = m_strNotes; - - pg.m_pwIcon = m_pwIcon; - pg.m_pwCustomIconID = m_pwCustomIconID; - - pg.m_tCreation = m_tCreation; - pg.m_tLastMod = m_tLastMod; - pg.m_tLastAccess = m_tLastAccess; - pg.m_tExpire = m_tExpire; - pg.m_bExpires = m_bExpires; - pg.m_uUsageCount = m_uUsageCount; - - pg.m_bIsExpanded = m_bIsExpanded; - pg.m_bVirtual = m_bVirtual; - - pg.m_strDefaultAutoTypeSequence = m_strDefaultAutoTypeSequence; - - pg.m_bEnableAutoType = m_bEnableAutoType; - pg.m_bEnableSearching = m_bEnableSearching; - - pg.m_pwLastTopVisibleEntry = m_pwLastTopVisibleEntry; - - pg.m_dCustomData = m_dCustomData.CloneDeep(); - - return pg; - } - - public PwGroup CloneStructure() - { - PwGroup pg = new PwGroup(false, false); - - pg.m_uuid = m_uuid; // PwUuid is immutable - pg.m_tParentGroupLastMod = m_tParentGroupLastMod; - // Do not assign m_pParentGroup - - foreach(PwGroup pgSub in m_listGroups) - pg.AddGroup(pgSub.CloneStructure(), true); - - foreach(PwEntry peSub in m_listEntries) - pg.AddEntry(peSub.CloneStructure(), true); - - return pg; - } - - public bool EqualsGroup(PwGroup pg, PwCompareOptions pwOpt, - MemProtCmpMode mpCmpStr) - { - if(pg == null) { Debug.Assert(false); return false; } - - bool bIgnoreLastAccess = ((pwOpt & PwCompareOptions.IgnoreLastAccess) != - PwCompareOptions.None); - bool bIgnoreLastMod = ((pwOpt & PwCompareOptions.IgnoreLastMod) != - PwCompareOptions.None); - - if(!m_uuid.Equals(pg.m_uuid)) return false; - if((pwOpt & PwCompareOptions.IgnoreParentGroup) == PwCompareOptions.None) - { - if(m_pParentGroup != pg.m_pParentGroup) return false; - if(!bIgnoreLastMod && (m_tParentGroupLastMod != pg.m_tParentGroupLastMod)) - return false; - } - - if(m_strName != pg.m_strName) return false; - if(m_strNotes != pg.m_strNotes) return false; - - if(m_pwIcon != pg.m_pwIcon) return false; - if(!m_pwCustomIconID.Equals(pg.m_pwCustomIconID)) return false; - - if(m_tCreation != pg.m_tCreation) return false; - if(!bIgnoreLastMod && (m_tLastMod != pg.m_tLastMod)) return false; - if(!bIgnoreLastAccess && (m_tLastAccess != pg.m_tLastAccess)) return false; - if(m_tExpire != pg.m_tExpire) return false; - if(m_bExpires != pg.m_bExpires) return false; - if(!bIgnoreLastAccess && (m_uUsageCount != pg.m_uUsageCount)) return false; - - // if(m_bIsExpanded != pg.m_bIsExpanded) return false; - - if(m_strDefaultAutoTypeSequence != pg.m_strDefaultAutoTypeSequence) return false; - - if(m_bEnableAutoType.HasValue != pg.m_bEnableAutoType.HasValue) return false; - if(m_bEnableAutoType.HasValue) - { - if(m_bEnableAutoType.Value != pg.m_bEnableAutoType.Value) return false; - } - if(m_bEnableSearching.HasValue != pg.m_bEnableSearching.HasValue) return false; - if(m_bEnableSearching.HasValue) - { - if(m_bEnableSearching.Value != pg.m_bEnableSearching.Value) return false; - } - - if(!m_pwLastTopVisibleEntry.Equals(pg.m_pwLastTopVisibleEntry)) return false; - - if(!m_dCustomData.Equals(pg.m_dCustomData)) return false; - - if((pwOpt & PwCompareOptions.PropertiesOnly) == PwCompareOptions.None) - { - if(m_listEntries.UCount != pg.m_listEntries.UCount) return false; - for(uint u = 0; u < m_listEntries.UCount; ++u) - { - PwEntry peA = m_listEntries.GetAt(u); - PwEntry peB = pg.m_listEntries.GetAt(u); - if(!peA.EqualsEntry(peB, pwOpt, mpCmpStr)) return false; - } - - if(m_listGroups.UCount != pg.m_listGroups.UCount) return false; - for(uint u = 0; u < m_listGroups.UCount; ++u) - { - PwGroup pgA = m_listGroups.GetAt(u); - PwGroup pgB = pg.m_listGroups.GetAt(u); - if(!pgA.EqualsGroup(pgB, pwOpt, mpCmpStr)) return false; - } - } - - return true; - } - - /// - /// Assign properties to the current group based on a template group. - /// - /// Template group. Must not be null. - /// Only set the properties of the template group - /// if it is newer than the current one. - /// If true, the - /// LocationChanged property is copied, otherwise not. - public void AssignProperties(PwGroup pgTemplate, bool bOnlyIfNewer, - bool bAssignLocationChanged) - { - Debug.Assert(pgTemplate != null); if(pgTemplate == null) throw new ArgumentNullException("pgTemplate"); - - if(bOnlyIfNewer && (TimeUtil.Compare(pgTemplate.m_tLastMod, m_tLastMod, - true) < 0)) - return; - - // Template UUID should be the same as the current one - Debug.Assert(m_uuid.Equals(pgTemplate.m_uuid)); - m_uuid = pgTemplate.m_uuid; - - if(bAssignLocationChanged) - m_tParentGroupLastMod = pgTemplate.m_tParentGroupLastMod; - - m_strName = pgTemplate.m_strName; - m_strNotes = pgTemplate.m_strNotes; - - m_pwIcon = pgTemplate.m_pwIcon; - m_pwCustomIconID = pgTemplate.m_pwCustomIconID; - - m_tCreation = pgTemplate.m_tCreation; - m_tLastMod = pgTemplate.m_tLastMod; - m_tLastAccess = pgTemplate.m_tLastAccess; - m_tExpire = pgTemplate.m_tExpire; - m_bExpires = pgTemplate.m_bExpires; - m_uUsageCount = pgTemplate.m_uUsageCount; - - m_strDefaultAutoTypeSequence = pgTemplate.m_strDefaultAutoTypeSequence; - - m_bEnableAutoType = pgTemplate.m_bEnableAutoType; - m_bEnableSearching = pgTemplate.m_bEnableSearching; - - m_pwLastTopVisibleEntry = pgTemplate.m_pwLastTopVisibleEntry; - - m_dCustomData = pgTemplate.m_dCustomData.CloneDeep(); - } - - /// - /// Touch the group. This function updates the internal last access - /// time. If the parameter is true, - /// the last modification time gets updated, too. - /// - /// Modify last modification time. - public void Touch(bool bModified) - { - Touch(bModified, true); - } - - /// - /// Touch the group. This function updates the internal last access - /// time. If the parameter is true, - /// the last modification time gets updated, too. - /// - /// Modify last modification time. - /// If true, all parent objects - /// get touched, too. - public void Touch(bool bModified, bool bTouchParents) - { - m_tLastAccess = DateTime.UtcNow; - ++m_uUsageCount; - - if(bModified) m_tLastMod = m_tLastAccess; - - if(this.Touched != null) - this.Touched(this, new ObjectTouchedEventArgs(this, - bModified, bTouchParents)); - if(PwGroup.GroupTouched != null) - PwGroup.GroupTouched(this, new ObjectTouchedEventArgs(this, - bModified, bTouchParents)); - - if(bTouchParents && (m_pParentGroup != null)) - m_pParentGroup.Touch(bModified, true); - } - - /// - /// Get number of groups and entries in the current group. This function - /// can also traverse through all subgroups and accumulate their counts - /// (recursive mode). - /// - /// If this parameter is true, all - /// subgroups and entries in subgroups will be counted and added to - /// the returned value. If it is false, only the number of - /// subgroups and entries of the current group is returned. - /// Number of subgroups. - /// Number of entries. - public void GetCounts(bool bRecursive, out uint uNumGroups, out uint uNumEntries) - { - if(bRecursive) - { - uint uTotalGroups = m_listGroups.UCount; - uint uTotalEntries = m_listEntries.UCount; - uint uSubGroupCount, uSubEntryCount; - - foreach(PwGroup pg in m_listGroups) - { - pg.GetCounts(true, out uSubGroupCount, out uSubEntryCount); - - uTotalGroups += uSubGroupCount; - uTotalEntries += uSubEntryCount; - } - - uNumGroups = uTotalGroups; - uNumEntries = uTotalEntries; - } - else // !bRecursive - { - uNumGroups = m_listGroups.UCount; - uNumEntries = m_listEntries.UCount; - } - } - - public uint GetEntriesCount(bool bRecursive) - { - uint uGroups, uEntries; - GetCounts(bRecursive, out uGroups, out uEntries); - return uEntries; - } - - /// - /// Traverse the group/entry tree in the current group. Various traversal - /// methods are available. - /// - /// Specifies the traversal method. - /// Function that performs an action on - /// the currently visited group (see GroupHandler for more). - /// This parameter may be null, in this case the tree is traversed but - /// you don't get notifications for each visited group. - /// Function that performs an action on - /// the currently visited entry (see EntryHandler for more). - /// This parameter may be null. - /// Returns true if all entries and groups have been - /// traversed. If the traversal has been canceled by one of the two - /// handlers, the return value is false. - public bool TraverseTree(TraversalMethod tm, GroupHandler groupHandler, EntryHandler entryHandler) - { - bool bRet = false; - - switch(tm) - { - case TraversalMethod.None: - bRet = true; - break; - case TraversalMethod.PreOrder: - bRet = PreOrderTraverseTree(groupHandler, entryHandler); - break; - default: - Debug.Assert(false); - break; - } - - return bRet; - } - - private bool PreOrderTraverseTree(GroupHandler groupHandler, EntryHandler entryHandler) - { - if(entryHandler != null) - { - foreach(PwEntry pe in m_listEntries) - { - if(!entryHandler(pe)) return false; - } - } - - foreach(PwGroup pg in m_listGroups) - { - if(groupHandler != null) - { - if(!groupHandler(pg)) return false; - } - - if(!pg.PreOrderTraverseTree(groupHandler, entryHandler)) - return false; - } - - return true; - } - - /// - /// Pack all groups into one flat linked list of references (recursively). - /// - /// Flat list of all groups. - public LinkedList GetFlatGroupList() - { - LinkedList list = new LinkedList(); - - foreach(PwGroup pg in m_listGroups) - { - list.AddLast(pg); - - if(pg.Groups.UCount != 0) - LinearizeGroupRecursive(list, pg, 1); - } - - return list; - } - - private void LinearizeGroupRecursive(LinkedList list, PwGroup pg, ushort uLevel) - { - Debug.Assert(pg != null); if(pg == null) return; - - foreach(PwGroup pwg in pg.Groups) - { - list.AddLast(pwg); - - if(pwg.Groups.UCount != 0) - LinearizeGroupRecursive(list, pwg, (ushort)(uLevel + 1)); - } - } - - /// - /// Pack all entries into one flat linked list of references. Temporary - /// group IDs are assigned automatically. - /// - /// A flat group list created by - /// GetFlatGroupList. - /// Flat list of all entries. - public static LinkedList GetFlatEntryList(LinkedList flatGroupList) - { - Debug.Assert(flatGroupList != null); if(flatGroupList == null) return null; - - LinkedList list = new LinkedList(); - foreach(PwGroup pg in flatGroupList) - { - foreach(PwEntry pe in pg.Entries) - list.AddLast(pe); - } - - return list; - } - - /// - /// Enable protection of a specific string field type. - /// - /// Name of the string field to protect or unprotect. - /// Enable protection or not. - /// Returns true, if the operation completed successfully, - /// otherwise false. - public bool EnableStringFieldProtection(string strFieldName, bool bEnable) - { - Debug.Assert(strFieldName != null); - - EntryHandler eh = delegate(PwEntry pe) - { - // Enable protection of current string - pe.Strings.EnableProtection(strFieldName, bEnable); - - // Do the same for all history items - foreach(PwEntry peHistory in pe.History) - { - peHistory.Strings.EnableProtection(strFieldName, bEnable); - } - - return true; - }; - - return PreOrderTraverseTree(null, eh); - } - - /// - /// Search this group and all subgroups for entries. - /// - /// Specifies the search parameters. - /// Entry list in which the search results - /// will be stored. - public void SearchEntries(SearchParameters sp, PwObjectList lResults) - { - SearchEntries(sp, lResults, null); - } - - /// - /// Search this group and all subgroups for entries. - /// - /// Specifies the search parameters. - /// Entry list in which the search results - /// will be stored. - /// Optional status reporting object. - public void SearchEntries(SearchParameters sp, PwObjectList lResults, - IStatusLogger slStatus) - { - if(sp == null) { Debug.Assert(false); return; } - if(lResults == null) { Debug.Assert(false); return; } - - PwObjectList lCand = GetEntries(true); - DateTime dtNow = DateTime.UtcNow; - - PwObjectList l = new PwObjectList(); - foreach(PwEntry pe in lCand) - { - if(sp.RespectEntrySearchingDisabled && !pe.GetSearchingEnabled()) - continue; - if(sp.ExcludeExpired && pe.Expires && (pe.ExpiryTime <= dtNow)) - continue; - - l.Add(pe); - } - lCand = l; - - List lTerms; - if(sp.RegularExpression) - { - lTerms = new List(); - lTerms.Add((sp.SearchString ?? string.Empty).Trim()); - } - else lTerms = StrUtil.SplitSearchTerms(sp.SearchString); - - // Search longer strings first (for improved performance) - lTerms.Sort(StrUtil.CompareLengthGt); - - ulong uPrcEntries = 0, uTotalEntries = lCand.UCount; - SearchParameters spSub = sp.Clone(); - - for(int iTerm = 0; iTerm < lTerms.Count; ++iTerm) - { - // Update counters for a better state guess - if(slStatus != null) - { - ulong uRemRounds = (ulong)(lTerms.Count - iTerm); - uTotalEntries = uPrcEntries + (uRemRounds * - lCand.UCount); - } - - spSub.SearchString = lTerms[iTerm]; // No trim - // spSub.RespectEntrySearchingDisabled = false; // Ignored by sub - // spSub.ExcludeExpired = false; // Ignored by sub - - bool bNegate = false; - if(spSub.SearchString.StartsWith(@"-") && - (spSub.SearchString.Length >= 2)) - { - spSub.SearchString = spSub.SearchString.Substring(1); - bNegate = true; - } - - l = new PwObjectList(); - if(!SearchEntriesSingle(lCand, spSub, l, slStatus, - ref uPrcEntries, uTotalEntries)) - { - lCand.Clear(); - break; - } - - if(bNegate) - { - PwObjectList lRem = new PwObjectList(); - foreach(PwEntry pe in lCand) - { - if(l.IndexOf(pe) < 0) lRem.Add(pe); - } - - lCand = lRem; - } - else lCand = l; - } - - Debug.Assert(lResults.UCount == 0); - lResults.Clear(); - lResults.Add(lCand); - } - - private static bool SearchEntriesSingle(PwObjectList lSource, - SearchParameters sp, PwObjectList lResults, - IStatusLogger slStatus, ref ulong uPrcEntries, ulong uTotalEntries) - { - if(lSource == null) { Debug.Assert(false); return true; } - if(sp == null) { Debug.Assert(false); return true; } - if(lResults == null) { Debug.Assert(false); return true; } - Debug.Assert(lResults.UCount == 0); - - bool bTitle = sp.SearchInTitles; - bool bUserName = sp.SearchInUserNames; - bool bPassword = sp.SearchInPasswords; - bool bUrl = sp.SearchInUrls; - bool bNotes = sp.SearchInNotes; - bool bOther = sp.SearchInOther; - bool bStringName = sp.SearchInStringNames; - bool bTags = sp.SearchInTags; - bool bUuids = sp.SearchInUuids; - bool bGroupName = sp.SearchInGroupNames; - // bool bExcludeExpired = sp.ExcludeExpired; - // bool bRespectEntrySearchingDisabled = sp.RespectEntrySearchingDisabled; - - Regex rx = null; - if(sp.RegularExpression) - { - RegexOptions ro = RegexOptions.None; // RegexOptions.Compiled - if((sp.ComparisonMode == StringComparison.CurrentCultureIgnoreCase) || -#if !ModernKeePassLib && !KeePassRT - (sp.ComparisonMode == StringComparison.InvariantCultureIgnoreCase) || -#endif - (sp.ComparisonMode == StringComparison.OrdinalIgnoreCase)) - { - ro |= RegexOptions.IgnoreCase; - } - - rx = new Regex(sp.SearchString, ro); - } - - ulong uLocalPrcEntries = uPrcEntries; - - if(sp.SearchString.Length == 0) lResults.Add(lSource); - else - { - foreach(PwEntry pe in lSource) - { - if(slStatus != null) - { - if(!slStatus.SetProgress((uint)((uLocalPrcEntries * - 100UL) / uTotalEntries))) return false; - ++uLocalPrcEntries; - } - - // if(bRespectEntrySearchingDisabled && !pe.GetSearchingEnabled()) - // continue; - // if(bExcludeExpired && pe.Expires && (pe.ExpiryTime <= dtNow)) - // continue; - - uint uInitialResults = lResults.UCount; - - foreach(KeyValuePair kvp in pe.Strings) - { - string strKey = kvp.Key; - - if(strKey == PwDefs.TitleField) - { - if(bTitle) SearchEvalAdd(sp, kvp.Value.ReadString(), - rx, pe, lResults); - } - else if(strKey == PwDefs.UserNameField) - { - if(bUserName) SearchEvalAdd(sp, kvp.Value.ReadString(), - rx, pe, lResults); - } - else if(strKey == PwDefs.PasswordField) - { - if(bPassword) SearchEvalAdd(sp, kvp.Value.ReadString(), - rx, pe, lResults); - } - else if(strKey == PwDefs.UrlField) - { - if(bUrl) SearchEvalAdd(sp, kvp.Value.ReadString(), - rx, pe, lResults); - } - else if(strKey == PwDefs.NotesField) - { - if(bNotes) SearchEvalAdd(sp, kvp.Value.ReadString(), - rx, pe, lResults); - } - else if(bOther) - SearchEvalAdd(sp, kvp.Value.ReadString(), - rx, pe, lResults); - - // An entry can match only once => break if we have added it - if(lResults.UCount != uInitialResults) break; - } - - if(bStringName) - { - foreach(KeyValuePair kvp in pe.Strings) - { - if(lResults.UCount != uInitialResults) break; - - SearchEvalAdd(sp, kvp.Key, rx, pe, lResults); - } - } - - if(bTags) - { - foreach(string strTag in pe.Tags) - { - if(lResults.UCount != uInitialResults) break; - - SearchEvalAdd(sp, strTag, rx, pe, lResults); - } - } - - if(bUuids && (lResults.UCount == uInitialResults)) - SearchEvalAdd(sp, pe.Uuid.ToHexString(), rx, pe, lResults); - - if(bGroupName && (lResults.UCount == uInitialResults) && - (pe.ParentGroup != null)) - SearchEvalAdd(sp, pe.ParentGroup.Name, rx, pe, lResults); - } - } - - uPrcEntries = uLocalPrcEntries; - return true; - } - - private static void SearchEvalAdd(SearchParameters sp, string strData, - Regex rx, PwEntry pe, PwObjectList lResults) - { - if(sp == null) { Debug.Assert(false); return; } - if(strData == null) { Debug.Assert(false); return; } - if(pe == null) { Debug.Assert(false); return; } - if(lResults == null) { Debug.Assert(false); return; } - - bool bMatch; - if(rx == null) - bMatch = (strData.IndexOf(sp.SearchString, - sp.ComparisonMode) >= 0); - else bMatch = rx.IsMatch(strData); - - if(!bMatch && (sp.DataTransformationFn != null)) - { - string strCmp = sp.DataTransformationFn(strData, pe); - if(!object.ReferenceEquals(strCmp, strData)) - { - if(rx == null) - bMatch = (strCmp.IndexOf(sp.SearchString, - sp.ComparisonMode) >= 0); - else bMatch = rx.IsMatch(strCmp); - } - } - - if(bMatch) lResults.Add(pe); - } - - public List BuildEntryTagsList() - { - return BuildEntryTagsList(false); - } - - public List BuildEntryTagsList(bool bSort) - { - List vTags = new List(); - - EntryHandler eh = delegate(PwEntry pe) - { - foreach(string strTag in pe.Tags) - { - bool bFound = false; - for(int i = 0; i < vTags.Count; ++i) - { - if(vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) - { - bFound = true; - break; - } - } - - if(!bFound) vTags.Add(strTag); - } - - return true; - }; - - TraverseTree(TraversalMethod.PreOrder, null, eh); - if(bSort) vTags.Sort(StrUtil.CaseIgnoreComparer); - return vTags; - } - -#if !KeePassLibSD - public IDictionary BuildEntryTagsDict(bool bSort) - { - IDictionary d; - if(!bSort) d = new Dictionary(StrUtil.CaseIgnoreComparer); - else d = new SortedDictionary(StrUtil.CaseIgnoreComparer); - - EntryHandler eh = delegate(PwEntry pe) - { - foreach(string strTag in pe.Tags) - { - uint u; - if(d.TryGetValue(strTag, out u)) d[strTag] = u + 1; - else d[strTag] = 1; - } - - return true; - }; - - TraverseTree(TraversalMethod.PreOrder, null, eh); - return d; - } -#endif - - public void FindEntriesByTag(string strTag, PwObjectList listStorage, - bool bSearchRecursive) - { - if(strTag == null) throw new ArgumentNullException("strTag"); - if(strTag.Length == 0) return; - - foreach(PwEntry pe in m_listEntries) - { - foreach(string strEntryTag in pe.Tags) - { - if(strEntryTag.Equals(strTag, StrUtil.CaseIgnoreCmp)) - { - listStorage.Add(pe); - break; - } - } - } - - if(bSearchRecursive) - { - foreach(PwGroup pg in m_listGroups) - pg.FindEntriesByTag(strTag, listStorage, true); - } - } - - /// - /// Find a group. - /// - /// UUID identifying the group the caller is looking for. - /// If true, the search is recursive. - /// Returns reference to found group, otherwise null. - public PwGroup FindGroup(PwUuid uuid, bool bSearchRecursive) - { - // Do not assert on PwUuid.Zero - if(m_uuid.Equals(uuid)) return this; - - if(bSearchRecursive) - { - PwGroup pgRec; - foreach(PwGroup pg in m_listGroups) - { - pgRec = pg.FindGroup(uuid, true); - if(pgRec != null) return pgRec; - } - } - else // Not recursive - { - foreach(PwGroup pg in m_listGroups) - { - if(pg.m_uuid.Equals(uuid)) - return pg; - } - } - - return null; - } - - /// - /// Find an object. - /// - /// UUID of the object to find. - /// Specifies whether to search recursively. - /// If null, groups and entries are - /// searched. If true, only entries are searched. If false, - /// only groups are searched. - /// Reference to the object, if found. Otherwise null. - public IStructureItem FindObject(PwUuid uuid, bool bRecursive, - bool? bEntries) - { - if(bEntries.HasValue) - { - if(bEntries.Value) return FindEntry(uuid, bRecursive); - else return FindGroup(uuid, bRecursive); - } - - PwGroup pg = FindGroup(uuid, bRecursive); - if(pg != null) return pg; - return FindEntry(uuid, bRecursive); - } - - /// - /// Try to find a subgroup and create it, if it doesn't exist yet. - /// - /// Name of the subgroup. - /// If the group isn't found: create it. - /// Returns a reference to the requested group or null if - /// it doesn't exist and shouldn't be created. - public PwGroup FindCreateGroup(string strName, bool bCreateIfNotFound) - { - Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); - - foreach(PwGroup pg in m_listGroups) - { - if(pg.Name == strName) return pg; - } - - if(!bCreateIfNotFound) return null; - - PwGroup pgNew = new PwGroup(true, true, strName, PwIcon.Folder); - AddGroup(pgNew, true); - return pgNew; - } - - /// - /// Find an entry. - /// - /// UUID identifying the entry the caller is looking for. - /// If true, the search is recursive. - /// Returns reference to found entry, otherwise null. - public PwEntry FindEntry(PwUuid uuid, bool bSearchRecursive) - { - foreach(PwEntry pe in m_listEntries) - { - if(pe.Uuid.Equals(uuid)) return pe; - } - - if(bSearchRecursive) - { - PwEntry peSub; - foreach(PwGroup pg in m_listGroups) - { - peSub = pg.FindEntry(uuid, true); - if(peSub != null) return peSub; - } - } - - return null; - } - - /// - /// Get the full path of a group. - /// - /// Full path of the group. - public string GetFullPath() - { - return GetFullPath(".", false); - } - - /// - /// Get the full path of a group. - /// - /// String that separates the group - /// names. - /// Specifies whether the returned - /// path starts with the topmost group. - /// Full path of the group. - public string GetFullPath(string strSeparator, bool bIncludeTopMostGroup) - { - Debug.Assert(strSeparator != null); - if(strSeparator == null) throw new ArgumentNullException("strSeparator"); - - string strPath = m_strName; - - PwGroup pg = m_pParentGroup; - while(pg != null) - { - if((!bIncludeTopMostGroup) && (pg.m_pParentGroup == null)) - break; - - strPath = pg.Name + strSeparator + strPath; - - pg = pg.m_pParentGroup; - } - - return strPath; - } - - /// - /// Assign new UUIDs to groups and entries. - /// - /// Create new UUIDs for subgroups. - /// Create new UUIDs for entries. - /// Recursive tree traversal. - public void CreateNewItemUuids(bool bNewGroups, bool bNewEntries, bool bRecursive) - { - if(bNewGroups) - { - foreach(PwGroup pg in m_listGroups) - pg.Uuid = new PwUuid(true); - } - - if(bNewEntries) - { - foreach(PwEntry pe in m_listEntries) - pe.SetUuid(new PwUuid(true), true); - } - - if(bRecursive) - { - foreach(PwGroup pg in m_listGroups) - pg.CreateNewItemUuids(bNewGroups, bNewEntries, true); - } - } - - public void TakeOwnership(bool bTakeSubGroups, bool bTakeEntries, bool bRecursive) - { - if(bTakeSubGroups) - { - foreach(PwGroup pg in m_listGroups) - pg.ParentGroup = this; - } - - if(bTakeEntries) - { - foreach(PwEntry pe in m_listEntries) - pe.ParentGroup = this; - } - - if(bRecursive) - { - foreach(PwGroup pg in m_listGroups) - pg.TakeOwnership(bTakeSubGroups, bTakeEntries, true); - } - } - -#if !KeePassLibSD - /// - /// Find/create a subtree of groups. - /// - /// Tree string. - /// Separators that delimit groups in the - /// strTree parameter. - public PwGroup FindCreateSubTree(string strTree, char[] vSeparators) - { - return FindCreateSubTree(strTree, vSeparators, true); - } - - public PwGroup FindCreateSubTree(string strTree, char[] vSeparators, - bool bAllowCreate) - { - if(vSeparators == null) { Debug.Assert(false); vSeparators = new char[0]; } - - string[] v = new string[vSeparators.Length]; - for(int i = 0; i < vSeparators.Length; ++i) - v[i] = new string(vSeparators[i], 1); - - return FindCreateSubTree(strTree, v, bAllowCreate); - } - - public PwGroup FindCreateSubTree(string strTree, string[] vSeparators, - bool bAllowCreate) - { - Debug.Assert(strTree != null); if(strTree == null) return this; - if(strTree.Length == 0) return this; - - string[] vGroups = strTree.Split(vSeparators, StringSplitOptions.None); - if((vGroups == null) || (vGroups.Length == 0)) return this; - - PwGroup pgContainer = this; - for(int nGroup = 0; nGroup < vGroups.Length; ++nGroup) - { - if(string.IsNullOrEmpty(vGroups[nGroup])) continue; - - bool bFound = false; - foreach(PwGroup pg in pgContainer.Groups) - { - if(pg.Name == vGroups[nGroup]) - { - pgContainer = pg; - bFound = true; - break; - } - } - - if(!bFound) - { - if(!bAllowCreate) return null; - - PwGroup pg = new PwGroup(true, true, vGroups[nGroup], PwIcon.Folder); - pgContainer.AddGroup(pg, true); - pgContainer = pg; - } - } - - return pgContainer; - } -#endif - - /// - /// Get the level of the group (i.e. the number of parent groups). - /// - /// Number of parent groups. - public uint GetLevel() - { - PwGroup pg = m_pParentGroup; - uint uLevel = 0; - - while(pg != null) - { - pg = pg.ParentGroup; - ++uLevel; - } - - return uLevel; - } - - public string GetAutoTypeSequenceInherited() - { - if(m_strDefaultAutoTypeSequence.Length > 0) - return m_strDefaultAutoTypeSequence; - - if(m_pParentGroup != null) - return m_pParentGroup.GetAutoTypeSequenceInherited(); - - return string.Empty; - } - - public bool GetAutoTypeEnabledInherited() - { - if(m_bEnableAutoType.HasValue) return m_bEnableAutoType.Value; - - if(m_pParentGroup != null) - return m_pParentGroup.GetAutoTypeEnabledInherited(); - - return DefaultAutoTypeEnabled; - } - - public bool GetSearchingEnabledInherited() - { - if(m_bEnableSearching.HasValue) return m_bEnableSearching.Value; - - if(m_pParentGroup != null) - return m_pParentGroup.GetSearchingEnabledInherited(); - - return DefaultSearchingEnabled; - } - - /// - /// Get a list of subgroups (not including this one). - /// - /// If true, subgroups are added - /// recursively, i.e. all child groups are returned, too. - /// List of subgroups. If is - /// true, it is guaranteed that subsubgroups appear after - /// subgroups. - public PwObjectList GetGroups(bool bRecursive) - { - if(bRecursive == false) return m_listGroups; - - PwObjectList list = m_listGroups.CloneShallow(); - foreach(PwGroup pgSub in m_listGroups) - { - list.Add(pgSub.GetGroups(true)); - } - - return list; - } - - public PwObjectList GetEntries(bool bIncludeSubGroupEntries) - { - PwObjectList l = new PwObjectList(); - - GroupHandler gh = delegate(PwGroup pg) - { - l.Add(pg.Entries); - return true; - }; - - gh(this); - if(bIncludeSubGroupEntries) - PreOrderTraverseTree(gh, null); - - Debug.Assert(l.UCount == GetEntriesCount(bIncludeSubGroupEntries)); - return l; - } - - /// - /// Get objects contained in this group. - /// - /// Specifies whether to search recursively. - /// If null, the returned list contains - /// groups and entries. If true, the returned list contains only - /// entries. If false, the returned list contains only groups. - /// List of objects. - public List GetObjects(bool bRecursive, bool? bEntries) - { - List list = new List(); - - if(!bEntries.HasValue || !bEntries.Value) - { - PwObjectList lGroups = GetGroups(bRecursive); - foreach(PwGroup pg in lGroups) list.Add(pg); - } - - if(!bEntries.HasValue || bEntries.Value) - { - PwObjectList lEntries = GetEntries(bRecursive); - foreach(PwEntry pe in lEntries) list.Add(pe); - } - - return list; - } - - public bool IsContainedIn(PwGroup pgContainer) - { - PwGroup pgCur = m_pParentGroup; - while(pgCur != null) - { - if(pgCur == pgContainer) return true; - - pgCur = pgCur.m_pParentGroup; - } - - return false; - } - - /// - /// Add a subgroup to this group. - /// - /// Group to be added. Must not be null. - /// If this parameter is true, the - /// parent group reference of the subgroup will be set to the current - /// group (i.e. the current group takes ownership of the subgroup). - public void AddGroup(PwGroup subGroup, bool bTakeOwnership) - { - AddGroup(subGroup, bTakeOwnership, false); - } - - /// - /// Add a subgroup to this group. - /// - /// Group to be added. Must not be null. - /// If this parameter is true, the - /// parent group reference of the subgroup will be set to the current - /// group (i.e. the current group takes ownership of the subgroup). - /// If true, the - /// LocationChanged property of the subgroup is updated. - public void AddGroup(PwGroup subGroup, bool bTakeOwnership, - bool bUpdateLocationChangedOfSub) - { - if(subGroup == null) throw new ArgumentNullException("subGroup"); - - m_listGroups.Add(subGroup); - - if(bTakeOwnership) subGroup.m_pParentGroup = this; - - if(bUpdateLocationChangedOfSub) subGroup.LocationChanged = DateTime.UtcNow; - } - - /// - /// Add an entry to this group. - /// - /// Entry to be added. Must not be null. - /// If this parameter is true, the - /// parent group reference of the entry will be set to the current - /// group (i.e. the current group takes ownership of the entry). - public void AddEntry(PwEntry pe, bool bTakeOwnership) - { - AddEntry(pe, bTakeOwnership, false); - } - - /// - /// Add an entry to this group. - /// - /// Entry to be added. Must not be null. - /// If this parameter is true, the - /// parent group reference of the entry will be set to the current - /// group (i.e. the current group takes ownership of the entry). - /// If true, the - /// LocationChanged property of the entry is updated. - public void AddEntry(PwEntry pe, bool bTakeOwnership, - bool bUpdateLocationChangedOfEntry) - { - if(pe == null) throw new ArgumentNullException("pe"); - - m_listEntries.Add(pe); - - // Do not remove the entry from its previous parent group, - // only assign it to the new one - if(bTakeOwnership) pe.ParentGroup = this; - - if(bUpdateLocationChangedOfEntry) pe.LocationChanged = DateTime.UtcNow; - } - - public void SortSubGroups(bool bRecursive) - { - m_listGroups.Sort(new PwGroupComparer()); - - if(bRecursive) - { - foreach(PwGroup pgSub in m_listGroups) - pgSub.SortSubGroups(true); - } - } - - public void DeleteAllObjects(PwDatabase pdContext) - { - DateTime dtNow = DateTime.UtcNow; - - foreach(PwEntry pe in m_listEntries) - { - PwDeletedObject pdo = new PwDeletedObject(pe.Uuid, dtNow); - pdContext.DeletedObjects.Add(pdo); - } - m_listEntries.Clear(); - - foreach(PwGroup pg in m_listGroups) - { - pg.DeleteAllObjects(pdContext); - - PwDeletedObject pdo = new PwDeletedObject(pg.Uuid, dtNow); - pdContext.DeletedObjects.Add(pdo); - } - m_listGroups.Clear(); - } - - internal List GetTopSearchSkippedGroups() - { - List l = new List(); - - if(!GetSearchingEnabledInherited()) l.Add(this); - else GetTopSearchSkippedGroupsRec(l); - - return l; - } - - private void GetTopSearchSkippedGroupsRec(List l) - { - if(m_bEnableSearching.HasValue && !m_bEnableSearching.Value) - { - l.Add(this); - return; - } - else { Debug.Assert(GetSearchingEnabledInherited()); } - - foreach(PwGroup pgSub in m_listGroups) - pgSub.GetTopSearchSkippedGroupsRec(l); - } - - public void SetCreatedNow(bool bRecursive) - { - DateTime dt = DateTime.UtcNow; - - m_tCreation = dt; - m_tLastAccess = dt; - - if(!bRecursive) return; - - GroupHandler gh = delegate(PwGroup pg) - { - pg.m_tCreation = dt; - pg.m_tLastAccess = dt; - return true; - }; - - EntryHandler eh = delegate(PwEntry pe) - { - pe.CreationTime = dt; - pe.LastAccessTime = dt; - return true; - }; - - TraverseTree(TraversalMethod.PreOrder, gh, eh); - } - - public PwGroup Duplicate() - { - PwGroup pg = CloneDeep(); - - pg.Uuid = new PwUuid(true); - pg.CreateNewItemUuids(true, true, true); - - pg.SetCreatedNow(true); - - pg.TakeOwnership(true, true, true); - - return pg; - } - } - - public sealed class PwGroupComparer : IComparer - { - public PwGroupComparer() - { - } - - public int Compare(PwGroup a, PwGroup b) - { - return StrUtil.CompareNaturally(a.Name, b.Name); - } - } -} diff --git a/ModernKeePassLib/PwUuid.cs b/ModernKeePassLib/PwUuid.cs deleted file mode 100644 index 05f3e05..0000000 --- a/ModernKeePassLib/PwUuid.cs +++ /dev/null @@ -1,215 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Xml; -using System.Diagnostics; - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib -{ - // [ImmutableObject(true)] - /// - /// Represents an UUID of a password entry or group. Once created, - /// PwUuid objects aren't modifyable anymore (immutable). - /// - public sealed class PwUuid : IComparable, IEquatable - { - /// - /// Standard size in bytes of a UUID. - /// - public const uint UuidSize = 16; - - /// - /// Zero UUID (all bytes are zero). - /// - public static readonly PwUuid Zero = new PwUuid(false); - - private byte[] m_pbUuid = null; // Never null after constructor - - /// - /// Get the 16 UUID bytes. - /// - public byte[] UuidBytes - { - get { return m_pbUuid; } - } - - /// - /// Construct a new UUID object. - /// - /// If this parameter is true, a new - /// UUID is generated. If it is false, the UUID is initialized - /// to zero. - public PwUuid(bool bCreateNew) - { - if(bCreateNew) CreateNew(); - else SetZero(); - } - - /// - /// Construct a new UUID object. - /// - /// Initial value of the PwUuid object. - public PwUuid(byte[] uuidBytes) - { - SetValue(uuidBytes); - } - - /// - /// Create a new, random UUID. - /// - /// Returns true if a random UUID has been generated, - /// otherwise it returns false. - private void CreateNew() - { - Debug.Assert(m_pbUuid == null); // Only call from constructor - while(true) - { - m_pbUuid = Guid.NewGuid().ToByteArray(); - - if((m_pbUuid == null) || (m_pbUuid.Length != (int)UuidSize)) - { - Debug.Assert(false); - throw new InvalidOperationException(); - } - - // Zero is a reserved value -- do not generate Zero - if(!Equals(PwUuid.Zero)) break; - Debug.Assert(false); - } - } - - private void SetValue(byte[] uuidBytes) - { - Debug.Assert((uuidBytes != null) && (uuidBytes.Length == (int)UuidSize)); - if(uuidBytes == null) throw new ArgumentNullException("uuidBytes"); - if(uuidBytes.Length != (int)UuidSize) throw new ArgumentException(); - - Debug.Assert(m_pbUuid == null); // Only call from constructor - m_pbUuid = new byte[UuidSize]; - - Array.Copy(uuidBytes, m_pbUuid, (int)UuidSize); - } - - private void SetZero() - { - Debug.Assert(m_pbUuid == null); // Only call from constructor - m_pbUuid = new byte[UuidSize]; - - // Array.Clear(m_pbUuid, 0, (int)UuidSize); -#if DEBUG - List l = new List(m_pbUuid); - Debug.Assert(l.TrueForAll(bt => (bt == 0))); -#endif - } - - [Obsolete] - public bool EqualsValue(PwUuid uuid) - { - return Equals(uuid); - } - - public override bool Equals(object obj) - { - return Equals(obj as PwUuid); - } - - public bool Equals(PwUuid other) - { - if(other == null) { Debug.Assert(false); return false; } - - for(int i = 0; i < (int)UuidSize; ++i) - { - if(m_pbUuid[i] != other.m_pbUuid[i]) return false; - } - - return true; - } - - private int m_h = 0; - public override int GetHashCode() - { - if(m_h == 0) - m_h = (int)MemUtil.Hash32(m_pbUuid, 0, m_pbUuid.Length); - return m_h; - } - - public int CompareTo(PwUuid other) - { - if(other == null) - { - Debug.Assert(false); - throw new ArgumentNullException("other"); - } - - for(int i = 0; i < (int)UuidSize; ++i) - { - if(m_pbUuid[i] < other.m_pbUuid[i]) return -1; - if(m_pbUuid[i] > other.m_pbUuid[i]) return 1; - } - - return 0; - } - - /// - /// Convert the UUID to its string representation. - /// - /// String containing the UUID value. - public string ToHexString() - { - return MemUtil.ByteArrayToHexString(m_pbUuid); - } - -#if DEBUG - public override string ToString() - { - return ToHexString(); - } -#endif - } - - [Obsolete] - public sealed class PwUuidComparable : IComparable - { - private byte[] m_pbUuid = new byte[PwUuid.UuidSize]; - - public PwUuidComparable(PwUuid pwUuid) - { - if(pwUuid == null) throw new ArgumentNullException("pwUuid"); - - Array.Copy(pwUuid.UuidBytes, m_pbUuid, (int)PwUuid.UuidSize); - } - - public int CompareTo(PwUuidComparable other) - { - if(other == null) throw new ArgumentNullException("other"); - - for(int i = 0; i < (int)PwUuid.UuidSize; ++i) - { - if(m_pbUuid[i] < other.m_pbUuid[i]) return -1; - if(m_pbUuid[i] > other.m_pbUuid[i]) return 1; - } - - return 0; - } - } -} diff --git a/ModernKeePassLib/README.md b/ModernKeePassLib/README.md deleted file mode 100644 index debe24f..0000000 --- a/ModernKeePassLib/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# ModernKeePassLib - -This is my adaptation of the KeePassLib (KeePass library) for the Universal Windows Platform and Windows Runtime (WinRT). -It aims at introducing as little change as possible to the original library: overall, except for namespace changes and some added classes (see below), there is almost no change. - -Download the Nuget package [here](https://www.nuget.org/packages/ModernKeePassLib) - -# Features -- Custom implementation of the System.Security.Cryptography.HashAlgoritm class by using WinRT equivalents -- Use of BouncyCastle PCL to implement AES key derivation features -- Lots of small changes in .NET methods (UTF8 instead of ASCII, string.) -- Disabled native functions (because not compatible with WinRT) -- Use of Splat for GfxUtil \ No newline at end of file diff --git a/ModernKeePassLib/Resources/KLRes.Generated.cs b/ModernKeePassLib/Resources/KLRes.Generated.cs deleted file mode 100644 index 007d875..0000000 --- a/ModernKeePassLib/Resources/KLRes.Generated.cs +++ /dev/null @@ -1,546 +0,0 @@ -// This is a generated file! -// Do not edit manually, changes will be overwritten. - -using System; -using System.Collections.Generic; - -namespace ModernKeePassLib.Resources -{ - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - public static class KLRes - { - private static string TryGetEx(Dictionary dictNew, - string strName, string strDefault) - { - string strTemp; - - if(dictNew.TryGetValue(strName, out strTemp)) - return strTemp; - - return strDefault; - } - - public static void SetTranslatedStrings(Dictionary dictNew) - { - if(dictNew == null) throw new ArgumentNullException("dictNew"); - - m_strCryptoStreamFailed = TryGetEx(dictNew, "CryptoStreamFailed", m_strCryptoStreamFailed); - m_strEncDataTooLarge = TryGetEx(dictNew, "EncDataTooLarge", m_strEncDataTooLarge); - m_strErrorInClipboard = TryGetEx(dictNew, "ErrorInClipboard", m_strErrorInClipboard); - m_strExpect100Continue = TryGetEx(dictNew, "Expect100Continue", m_strExpect100Continue); - m_strFatalError = TryGetEx(dictNew, "FatalError", m_strFatalError); - m_strFatalErrorText = TryGetEx(dictNew, "FatalErrorText", m_strFatalErrorText); - m_strFileCorrupted = TryGetEx(dictNew, "FileCorrupted", m_strFileCorrupted); - m_strFileHeaderCorrupted = TryGetEx(dictNew, "FileHeaderCorrupted", m_strFileHeaderCorrupted); - m_strFileIncomplete = TryGetEx(dictNew, "FileIncomplete", m_strFileIncomplete); - m_strFileIncompleteExpc = TryGetEx(dictNew, "FileIncompleteExpc", m_strFileIncompleteExpc); - m_strFileLoadFailed = TryGetEx(dictNew, "FileLoadFailed", m_strFileLoadFailed); - m_strFileLockedWrite = TryGetEx(dictNew, "FileLockedWrite", m_strFileLockedWrite); - m_strFileNewVerOrPlgReq = TryGetEx(dictNew, "FileNewVerOrPlgReq", m_strFileNewVerOrPlgReq); - m_strFileNewVerReq = TryGetEx(dictNew, "FileNewVerReq", m_strFileNewVerReq); - m_strFileSaveCorruptionWarning = TryGetEx(dictNew, "FileSaveCorruptionWarning", m_strFileSaveCorruptionWarning); - m_strFileSaveFailed = TryGetEx(dictNew, "FileSaveFailed", m_strFileSaveFailed); - m_strFileSigInvalid = TryGetEx(dictNew, "FileSigInvalid", m_strFileSigInvalid); - m_strFileUnknownCipher = TryGetEx(dictNew, "FileUnknownCipher", m_strFileUnknownCipher); - m_strFileUnknownCompression = TryGetEx(dictNew, "FileUnknownCompression", m_strFileUnknownCompression); - m_strFileVersionUnsupported = TryGetEx(dictNew, "FileVersionUnsupported", m_strFileVersionUnsupported); - m_strFinalKeyCreationFailed = TryGetEx(dictNew, "FinalKeyCreationFailed", m_strFinalKeyCreationFailed); - m_strFrameworkNotImplExcp = TryGetEx(dictNew, "FrameworkNotImplExcp", m_strFrameworkNotImplExcp); - m_strGeneral = TryGetEx(dictNew, "General", m_strGeneral); - m_strInvalidCompositeKey = TryGetEx(dictNew, "InvalidCompositeKey", m_strInvalidCompositeKey); - m_strInvalidCompositeKeyHint = TryGetEx(dictNew, "InvalidCompositeKeyHint", m_strInvalidCompositeKeyHint); - m_strInvalidDataWhileDecoding = TryGetEx(dictNew, "InvalidDataWhileDecoding", m_strInvalidDataWhileDecoding); - m_strKeePass1xHint = TryGetEx(dictNew, "KeePass1xHint", m_strKeePass1xHint); - m_strKeyBits = TryGetEx(dictNew, "KeyBits", m_strKeyBits); - m_strKeyFileDbSel = TryGetEx(dictNew, "KeyFileDbSel", m_strKeyFileDbSel); - m_strMasterSeedLengthInvalid = TryGetEx(dictNew, "MasterSeedLengthInvalid", m_strMasterSeedLengthInvalid); - m_strOldFormat = TryGetEx(dictNew, "OldFormat", m_strOldFormat); - m_strPassive = TryGetEx(dictNew, "Passive", m_strPassive); - m_strPreAuth = TryGetEx(dictNew, "PreAuth", m_strPreAuth); - m_strTimeout = TryGetEx(dictNew, "Timeout", m_strTimeout); - m_strTryAgainSecs = TryGetEx(dictNew, "TryAgainSecs", m_strTryAgainSecs); - m_strUnknownHeaderId = TryGetEx(dictNew, "UnknownHeaderId", m_strUnknownHeaderId); - m_strUnknownKdf = TryGetEx(dictNew, "UnknownKdf", m_strUnknownKdf); - m_strUserAccountKeyError = TryGetEx(dictNew, "UserAccountKeyError", m_strUserAccountKeyError); - m_strUserAgent = TryGetEx(dictNew, "UserAgent", m_strUserAgent); - } - - private static readonly string[] m_vKeyNames = { - "CryptoStreamFailed", - "EncDataTooLarge", - "ErrorInClipboard", - "Expect100Continue", - "FatalError", - "FatalErrorText", - "FileCorrupted", - "FileHeaderCorrupted", - "FileIncomplete", - "FileIncompleteExpc", - "FileLoadFailed", - "FileLockedWrite", - "FileNewVerOrPlgReq", - "FileNewVerReq", - "FileSaveCorruptionWarning", - "FileSaveFailed", - "FileSigInvalid", - "FileUnknownCipher", - "FileUnknownCompression", - "FileVersionUnsupported", - "FinalKeyCreationFailed", - "FrameworkNotImplExcp", - "General", - "InvalidCompositeKey", - "InvalidCompositeKeyHint", - "InvalidDataWhileDecoding", - "KeePass1xHint", - "KeyBits", - "KeyFileDbSel", - "MasterSeedLengthInvalid", - "OldFormat", - "Passive", - "PreAuth", - "Timeout", - "TryAgainSecs", - "UnknownHeaderId", - "UnknownKdf", - "UserAccountKeyError", - "UserAgent" - }; - - public static string[] GetKeyNames() - { - return m_vKeyNames; - } - - private static string m_strCryptoStreamFailed = - @"Failed to initialize encryption/decryption stream!"; - /// - /// Look up a localized string similar to - /// 'Failed to initialize encryption/decryption stream!'. - /// - public static string CryptoStreamFailed - { - get { return m_strCryptoStreamFailed; } - } - - private static string m_strEncDataTooLarge = - @"The data is too large to be encrypted/decrypted securely using {PARAM}."; - /// - /// Look up a localized string similar to - /// 'The data is too large to be encrypted/decrypted securely using {PARAM}.'. - /// - public static string EncDataTooLarge - { - get { return m_strEncDataTooLarge; } - } - - private static string m_strErrorInClipboard = - @"An extended error report has been copied to the clipboard."; - /// - /// Look up a localized string similar to - /// 'An extended error report has been copied to the clipboard.'. - /// - public static string ErrorInClipboard - { - get { return m_strErrorInClipboard; } - } - - private static string m_strExpect100Continue = - @"Expect 100-Continue responses"; - /// - /// Look up a localized string similar to - /// 'Expect 100-Continue responses'. - /// - public static string Expect100Continue - { - get { return m_strExpect100Continue; } - } - - private static string m_strFatalError = - @"Fatal Error"; - /// - /// Look up a localized string similar to - /// 'Fatal Error'. - /// - public static string FatalError - { - get { return m_strFatalError; } - } - - private static string m_strFatalErrorText = - @"A fatal error has occurred!"; - /// - /// Look up a localized string similar to - /// 'A fatal error has occurred!'. - /// - public static string FatalErrorText - { - get { return m_strFatalErrorText; } - } - - private static string m_strFileCorrupted = - @"The file is corrupted."; - /// - /// Look up a localized string similar to - /// 'The file is corrupted.'. - /// - public static string FileCorrupted - { - get { return m_strFileCorrupted; } - } - - private static string m_strFileHeaderCorrupted = - @"The file header is corrupted."; - /// - /// Look up a localized string similar to - /// 'The file header is corrupted.'. - /// - public static string FileHeaderCorrupted - { - get { return m_strFileHeaderCorrupted; } - } - - private static string m_strFileIncomplete = - @"Data is missing at the end of the file, i.e. the file is incomplete."; - /// - /// Look up a localized string similar to - /// 'Data is missing at the end of the file, i.e. the file is incomplete.'. - /// - public static string FileIncomplete - { - get { return m_strFileIncomplete; } - } - - private static string m_strFileIncompleteExpc = - @"Less data than expected could be read from the file."; - /// - /// Look up a localized string similar to - /// 'Less data than expected could be read from the file.'. - /// - public static string FileIncompleteExpc - { - get { return m_strFileIncompleteExpc; } - } - - private static string m_strFileLoadFailed = - @"Failed to load the specified file!"; - /// - /// Look up a localized string similar to - /// 'Failed to load the specified file!'. - /// - public static string FileLoadFailed - { - get { return m_strFileLoadFailed; } - } - - private static string m_strFileLockedWrite = - @"The file is locked, because the following user is currently writing to it:"; - /// - /// Look up a localized string similar to - /// 'The file is locked, because the following user is currently writing to it:'. - /// - public static string FileLockedWrite - { - get { return m_strFileLockedWrite; } - } - - private static string m_strFileNewVerOrPlgReq = - @"A newer KeePass version or a plugin is required to open this file."; - /// - /// Look up a localized string similar to - /// 'A newer KeePass version or a plugin is required to open this file.'. - /// - public static string FileNewVerOrPlgReq - { - get { return m_strFileNewVerOrPlgReq; } - } - - private static string m_strFileNewVerReq = - @"A newer KeePass version is required to open this file."; - /// - /// Look up a localized string similar to - /// 'A newer KeePass version is required to open this file.'. - /// - public static string FileNewVerReq - { - get { return m_strFileNewVerReq; } - } - - private static string m_strFileSaveCorruptionWarning = - @"The target file might be corrupted. Please try saving again. If that fails, save the database to a different location."; - /// - /// Look up a localized string similar to - /// 'The target file might be corrupted. Please try saving again. If that fails, save the database to a different location.'. - /// - public static string FileSaveCorruptionWarning - { - get { return m_strFileSaveCorruptionWarning; } - } - - private static string m_strFileSaveFailed = - @"Failed to save the current database to the specified location!"; - /// - /// Look up a localized string similar to - /// 'Failed to save the current database to the specified location!'. - /// - public static string FileSaveFailed - { - get { return m_strFileSaveFailed; } - } - - private static string m_strFileSigInvalid = - @"The file signature is invalid. Either the file isn't a KeePass database file at all or it is corrupted."; - /// - /// Look up a localized string similar to - /// 'The file signature is invalid. Either the file isn't a KeePass database file at all or it is corrupted.'. - /// - public static string FileSigInvalid - { - get { return m_strFileSigInvalid; } - } - - private static string m_strFileUnknownCipher = - @"The file is encrypted using an unknown encryption algorithm!"; - /// - /// Look up a localized string similar to - /// 'The file is encrypted using an unknown encryption algorithm!'. - /// - public static string FileUnknownCipher - { - get { return m_strFileUnknownCipher; } - } - - private static string m_strFileUnknownCompression = - @"The file is compressed using an unknown compression algorithm!"; - /// - /// Look up a localized string similar to - /// 'The file is compressed using an unknown compression algorithm!'. - /// - public static string FileUnknownCompression - { - get { return m_strFileUnknownCompression; } - } - - private static string m_strFileVersionUnsupported = - @"The file version is unsupported."; - /// - /// Look up a localized string similar to - /// 'The file version is unsupported.'. - /// - public static string FileVersionUnsupported - { - get { return m_strFileVersionUnsupported; } - } - - private static string m_strFinalKeyCreationFailed = - @"Failed to create the final encryption/decryption key!"; - /// - /// Look up a localized string similar to - /// 'Failed to create the final encryption/decryption key!'. - /// - public static string FinalKeyCreationFailed - { - get { return m_strFinalKeyCreationFailed; } - } - - private static string m_strFrameworkNotImplExcp = - @"The .NET framework/runtime under which KeePass is currently running does not support this operation."; - /// - /// Look up a localized string similar to - /// 'The .NET framework/runtime under which KeePass is currently running does not support this operation.'. - /// - public static string FrameworkNotImplExcp - { - get { return m_strFrameworkNotImplExcp; } - } - - private static string m_strGeneral = - @"General"; - /// - /// Look up a localized string similar to - /// 'General'. - /// - public static string General - { - get { return m_strGeneral; } - } - - private static string m_strInvalidCompositeKey = - @"The composite key is invalid!"; - /// - /// Look up a localized string similar to - /// 'The composite key is invalid!'. - /// - public static string InvalidCompositeKey - { - get { return m_strInvalidCompositeKey; } - } - - private static string m_strInvalidCompositeKeyHint = - @"Make sure the composite key is correct and try again."; - /// - /// Look up a localized string similar to - /// 'Make sure the composite key is correct and try again.'. - /// - public static string InvalidCompositeKeyHint - { - get { return m_strInvalidCompositeKeyHint; } - } - - private static string m_strInvalidDataWhileDecoding = - @"Found invalid data while decoding."; - /// - /// Look up a localized string similar to - /// 'Found invalid data while decoding.'. - /// - public static string InvalidDataWhileDecoding - { - get { return m_strInvalidDataWhileDecoding; } - } - - private static string m_strKeePass1xHint = - @"In order to import KeePass 1.x KDB files, create a new 2.x database file and click 'File' -> 'Import' in the main menu. In the import dialog, choose 'KeePass KDB (1.x)' as file format."; - /// - /// Look up a localized string similar to - /// 'In order to import KeePass 1.x KDB files, create a new 2.x database file and click 'File' -> 'Import' in the main menu. In the import dialog, choose 'KeePass KDB (1.x)' as file format.'. - /// - public static string KeePass1xHint - { - get { return m_strKeePass1xHint; } - } - - private static string m_strKeyBits = - @"{PARAM}-bit key"; - /// - /// Look up a localized string similar to - /// '{PARAM}-bit key'. - /// - public static string KeyBits - { - get { return m_strKeyBits; } - } - - private static string m_strKeyFileDbSel = - @"Database files cannot be used as key files."; - /// - /// Look up a localized string similar to - /// 'Database files cannot be used as key files.'. - /// - public static string KeyFileDbSel - { - get { return m_strKeyFileDbSel; } - } - - private static string m_strMasterSeedLengthInvalid = - @"The length of the master key seed is invalid!"; - /// - /// Look up a localized string similar to - /// 'The length of the master key seed is invalid!'. - /// - public static string MasterSeedLengthInvalid - { - get { return m_strMasterSeedLengthInvalid; } - } - - private static string m_strOldFormat = - @"The selected file appears to be an old format"; - /// - /// Look up a localized string similar to - /// 'The selected file appears to be an old format'. - /// - public static string OldFormat - { - get { return m_strOldFormat; } - } - - private static string m_strPassive = - @"Passive"; - /// - /// Look up a localized string similar to - /// 'Passive'. - /// - public static string Passive - { - get { return m_strPassive; } - } - - private static string m_strPreAuth = - @"Pre-authenticate"; - /// - /// Look up a localized string similar to - /// 'Pre-authenticate'. - /// - public static string PreAuth - { - get { return m_strPreAuth; } - } - - private static string m_strTimeout = - @"Timeout"; - /// - /// Look up a localized string similar to - /// 'Timeout'. - /// - public static string Timeout - { - get { return m_strTimeout; } - } - - private static string m_strTryAgainSecs = - @"Please try it again in a few seconds."; - /// - /// Look up a localized string similar to - /// 'Please try it again in a few seconds.'. - /// - public static string TryAgainSecs - { - get { return m_strTryAgainSecs; } - } - - private static string m_strUnknownHeaderId = - @"Unknown header ID!"; - /// - /// Look up a localized string similar to - /// 'Unknown header ID!'. - /// - public static string UnknownHeaderId - { - get { return m_strUnknownHeaderId; } - } - - private static string m_strUnknownKdf = - @"Unknown key derivation function!"; - /// - /// Look up a localized string similar to - /// 'Unknown key derivation function!'. - /// - public static string UnknownKdf - { - get { return m_strUnknownKdf; } - } - - private static string m_strUserAccountKeyError = - @"The operating system did not grant KeePass read/write access to the user profile folder, where the protected user key is stored."; - /// - /// Look up a localized string similar to - /// 'The operating system did not grant KeePass read/write access to the user profile folder, where the protected user key is stored.'. - /// - public static string UserAccountKeyError - { - get { return m_strUserAccountKeyError; } - } - - private static string m_strUserAgent = - @"User agent"; - /// - /// Look up a localized string similar to - /// 'User agent'. - /// - public static string UserAgent - { - get { return m_strUserAgent; } - } - } -} diff --git a/ModernKeePassLib/Resources/KSRes.Generated.cs b/ModernKeePassLib/Resources/KSRes.Generated.cs deleted file mode 100644 index 7b49547..0000000 --- a/ModernKeePassLib/Resources/KSRes.Generated.cs +++ /dev/null @@ -1,52 +0,0 @@ -// This is a generated file! -// Do not edit manually, changes will be overwritten. - -using System; -using System.Collections.Generic; - -namespace ModernKeePassLib.Resources -{ - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - public static class KSRes - { - private static string TryGetEx(Dictionary dictNew, - string strName, string strDefault) - { - string strTemp; - - if(dictNew.TryGetValue(strName, out strTemp)) - return strTemp; - - return strDefault; - } - - public static void SetTranslatedStrings(Dictionary dictNew) - { - if(dictNew == null) throw new ArgumentNullException("dictNew"); - - m_strTest = TryGetEx(dictNew, "Test", m_strTest); - } - - private static readonly string[] m_vKeyNames = { - "Test" - }; - - public static string[] GetKeyNames() - { - return m_vKeyNames; - } - - private static string m_strTest = - @"Test"; - /// - /// Look up a localized string similar to - /// 'Test'. - /// - public static string Test - { - get { return m_strTest; } - } - } -} diff --git a/ModernKeePassLib/Security/ProtectedBinary.cs b/ModernKeePassLib/Security/ProtectedBinary.cs deleted file mode 100644 index eff079a..0000000 --- a/ModernKeePassLib/Security/ProtectedBinary.cs +++ /dev/null @@ -1,418 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Diagnostics; -using System.Threading; - -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Cryptography.Cipher; -using ModernKeePassLib.Native; -using ModernKeePassLib.Utility; - -#if KeePassLibSD -using KeePassLibSD; -#endif - -namespace ModernKeePassLib.Security -{ - [Flags] - public enum PbCryptFlags - { - None = 0, - Encrypt = 1, - Decrypt = 2 - } - - public delegate void PbCryptDelegate(byte[] pbData, PbCryptFlags cf, - long lID); - - /// - /// A protected binary, i.e. a byte array that is encrypted in memory. - /// A ProtectedBinary object is immutable and thread-safe. - /// - public sealed class ProtectedBinary : IEquatable - { - private const int BlockSize = 16; - - private static PbCryptDelegate g_fExtCrypt = null; - /// - /// A plugin can provide a custom memory protection method - /// by assigning a non-null delegate to this property. - /// - public static PbCryptDelegate ExtCrypt - { - get { return g_fExtCrypt; } - set { g_fExtCrypt = value; } - } - - // Local copy of the delegate that was used for encryption, - // in order to allow correct decryption even when the global - // delegate changes - private PbCryptDelegate m_fExtCrypt = null; - - private enum PbMemProt - { - None = 0, - ProtectedMemory, // DPAPI on Windows - ChaCha20, - ExtCrypt - } - - // ProtectedMemory is supported only on Windows 2000 SP3 and higher -#if !KeePassLibSD - private static bool? g_obProtectedMemorySupported = null; -#endif - private static bool ProtectedMemorySupported - { - get - { -#if KeePassLibSD - return false; -#else - bool? ob = g_obProtectedMemorySupported; - if(ob.HasValue) return ob.Value; - - // Mono does not implement any encryption for ProtectedMemory - // on Linux (Mono uses DPAPI on Windows); - // https://sourceforge.net/p/keepass/feature-requests/1907/ - if(NativeLib.IsUnix()) - { - g_obProtectedMemorySupported = false; - return false; - } - - ob = false; - try // Test whether ProtectedMemory is supported - { - // BlockSize * 3 in order to test encryption for multiple - // blocks, but not introduce a power of 2 as factor - byte[] pb = new byte[ProtectedBinary.BlockSize * 3]; - for(int i = 0; i < pb.Length; ++i) pb[i] = (byte)i; - - ProtectedMemory.Protect(pb, MemoryProtectionScope.SameProcess); - - for(int i = 0; i < pb.Length; ++i) - { - if(pb[i] != (byte)i) { ob = true; break; } - } - } - catch(Exception) { } // Windows 98 / ME - - g_obProtectedMemorySupported = ob; - return ob.Value; -#endif - } - } - - private static long g_lCurID = 0; - private long m_lID; - - private byte[] m_pbData; // Never null - - // The real length of the data; this value can be different from - // m_pbData.Length, as the length of m_pbData always is a multiple - // of BlockSize (required for ProtectedMemory) - private uint m_uDataLen; - - private bool m_bProtected; // Protection requested by the caller - - private PbMemProt m_mp = PbMemProt.None; // Actual protection - - private readonly object m_objSync = new object(); - - private static byte[] g_pbKey32 = null; - - /// - /// A flag specifying whether the ProtectedBinary object has - /// turned on memory protection or not. - /// - public bool IsProtected - { - get { return m_bProtected; } - } - - /// - /// Length of the stored data. - /// - public uint Length - { - get { return m_uDataLen; } - } - - /// - /// Construct a new, empty protected binary data object. - /// Protection is disabled. - /// - public ProtectedBinary() - { - Init(false, MemUtil.EmptyByteArray, 0, 0); - } - - /// - /// Construct a new protected binary data object. - /// - /// If this paremeter is true, - /// the data will be encrypted in memory. If it is false, the - /// data is stored in plain-text in the process memory. - /// Value of the protected object. - /// The input parameter is not modified and - /// ProtectedBinary doesn't take ownership of the data, - /// i.e. the caller is responsible for clearing it. - public ProtectedBinary(bool bEnableProtection, byte[] pbData) - { - if(pbData == null) throw new ArgumentNullException("pbData"); // For .Length - - Init(bEnableProtection, pbData, 0, pbData.Length); - } - - /// - /// Construct a new protected binary data object. - /// - /// If this paremeter is true, - /// the data will be encrypted in memory. If it is false, the - /// data is stored in plain-text in the process memory. - /// Value of the protected object. - /// The input parameter is not modified and - /// ProtectedBinary doesn't take ownership of the data, - /// i.e. the caller is responsible for clearing it. - /// Offset for . - /// Size for . - public ProtectedBinary(bool bEnableProtection, byte[] pbData, - int iOffset, int cbSize) - { - Init(bEnableProtection, pbData, iOffset, cbSize); - } - - /// - /// Construct a new protected binary data object. Copy the data from - /// a XorredBuffer object. - /// - /// Enable protection or not. - /// XorredBuffer object used to - /// initialize the ProtectedBinary object. - public ProtectedBinary(bool bEnableProtection, XorredBuffer xbProtected) - { - Debug.Assert(xbProtected != null); - if(xbProtected == null) throw new ArgumentNullException("xbProtected"); - - byte[] pb = xbProtected.ReadPlainText(); - try { Init(bEnableProtection, pb, 0, pb.Length); } - finally { if(bEnableProtection) MemUtil.ZeroByteArray(pb); } - } - - private void Init(bool bEnableProtection, byte[] pbData, int iOffset, - int cbSize) - { - if(pbData == null) throw new ArgumentNullException("pbData"); - if(iOffset < 0) throw new ArgumentOutOfRangeException("iOffset"); - if(cbSize < 0) throw new ArgumentOutOfRangeException("cbSize"); - if(iOffset > (pbData.Length - cbSize)) - throw new ArgumentOutOfRangeException("cbSize"); - -#if KeePassLibSD - m_lID = ++g_lCurID; -#else - m_lID = Interlocked.Increment(ref g_lCurID); -#endif - - m_bProtected = bEnableProtection; - m_uDataLen = (uint)cbSize; - - const int bs = ProtectedBinary.BlockSize; - int nBlocks = cbSize / bs; - if((nBlocks * bs) < cbSize) ++nBlocks; - Debug.Assert((nBlocks * bs) >= cbSize); - - m_pbData = new byte[nBlocks * bs]; - Array.Copy(pbData, iOffset, m_pbData, 0, cbSize); - - Encrypt(); - } - - private void Encrypt() - { - Debug.Assert(m_mp == PbMemProt.None); - - // Nothing to do if caller didn't request protection - if(!m_bProtected) return; - - // ProtectedMemory.Protect throws for data size == 0 - if(m_pbData.Length == 0) return; - - PbCryptDelegate f = g_fExtCrypt; - if(f != null) - { - f(m_pbData, PbCryptFlags.Encrypt, m_lID); - - m_fExtCrypt = f; - m_mp = PbMemProt.ExtCrypt; - return; - } - - if(ProtectedBinary.ProtectedMemorySupported) - { - ProtectedMemory.Protect(m_pbData, MemoryProtectionScope.SameProcess); - - m_mp = PbMemProt.ProtectedMemory; - return; - } - - byte[] pbKey32 = g_pbKey32; - if(pbKey32 == null) - { - pbKey32 = CryptoRandom.Instance.GetRandomBytes(32); - - byte[] pbUpd = Interlocked.Exchange(ref g_pbKey32, pbKey32); - if(pbUpd != null) pbKey32 = pbUpd; - } - - byte[] pbIV = new byte[12]; - MemUtil.UInt64ToBytesEx((ulong)m_lID, pbIV, 4); - using(ChaCha20Cipher c = new ChaCha20Cipher(pbKey32, pbIV, true)) - { - c.Encrypt(m_pbData, 0, m_pbData.Length); - } - m_mp = PbMemProt.ChaCha20; - } - - private void Decrypt() - { - if(m_pbData.Length == 0) return; - - if(m_mp == PbMemProt.ProtectedMemory) - ProtectedMemory.Unprotect(m_pbData, MemoryProtectionScope.SameProcess); - else if(m_mp == PbMemProt.ChaCha20) - { - byte[] pbIV = new byte[12]; - MemUtil.UInt64ToBytesEx((ulong)m_lID, pbIV, 4); - using(ChaCha20Cipher c = new ChaCha20Cipher(g_pbKey32, pbIV, true)) - { - c.Decrypt(m_pbData, 0, m_pbData.Length); - } - } - else if(m_mp == PbMemProt.ExtCrypt) - m_fExtCrypt(m_pbData, PbCryptFlags.Decrypt, m_lID); - else { Debug.Assert(m_mp == PbMemProt.None); } - - m_mp = PbMemProt.None; - } - - /// - /// Get a copy of the protected data as a byte array. - /// Please note that the returned byte array is not protected and - /// can therefore been read by any other application. - /// Make sure that your clear it properly after usage. - /// - /// Unprotected byte array. This is always a copy of the internal - /// protected data and can therefore be cleared safely. - public byte[] ReadData() - { - if(m_uDataLen == 0) return MemUtil.EmptyByteArray; - - byte[] pbReturn = new byte[m_uDataLen]; - - lock(m_objSync) - { - Decrypt(); - Array.Copy(m_pbData, pbReturn, (int)m_uDataLen); - Encrypt(); - } - - return pbReturn; - } - - /// - /// Read the protected data and return it protected with a sequence - /// of bytes generated by a random stream. - /// - /// Random number source. - public byte[] ReadXorredData(CryptoRandomStream crsRandomSource) - { - Debug.Assert(crsRandomSource != null); - if(crsRandomSource == null) throw new ArgumentNullException("crsRandomSource"); - - byte[] pbData = ReadData(); - uint uLen = (uint)pbData.Length; - - byte[] randomPad = crsRandomSource.GetRandomBytes(uLen); - Debug.Assert(randomPad.Length == pbData.Length); - - for(uint i = 0; i < uLen; ++i) - pbData[i] ^= randomPad[i]; - - return pbData; - } - - private int? m_hash = null; - public override int GetHashCode() - { - if(m_hash.HasValue) return m_hash.Value; - - int h = (m_bProtected ? 0x7B11D289 : 0); - - byte[] pb = ReadData(); - unchecked - { - for(int i = 0; i < pb.Length; ++i) - h = (h << 3) + h + (int)pb[i]; - } - if(m_bProtected) MemUtil.ZeroByteArray(pb); - - m_hash = h; - return h; - } - - public override bool Equals(object obj) - { - return this.Equals(obj as ProtectedBinary, true); - } - - public bool Equals(ProtectedBinary other) - { - return this.Equals(other, true); - } - - public bool Equals(ProtectedBinary other, bool bCheckProtEqual) - { - if(other == null) return false; // No assert - if(object.ReferenceEquals(this, other)) return true; // Perf. opt. - - if(bCheckProtEqual && (m_bProtected != other.m_bProtected)) - return false; - - if(m_uDataLen != other.m_uDataLen) return false; - - byte[] pbL = ReadData(), pbR = null; - bool bEq; - try - { - pbR = other.ReadData(); - bEq = MemUtil.ArraysEqual(pbL, pbR); - } - finally - { - if(m_bProtected) MemUtil.ZeroByteArray(pbL); - if(other.m_bProtected && (pbR != null)) MemUtil.ZeroByteArray(pbR); - } - - return bEq; - } - } -} diff --git a/ModernKeePassLib/Security/ProtectedString.cs b/ModernKeePassLib/Security/ProtectedString.cs deleted file mode 100644 index eb62841..0000000 --- a/ModernKeePassLib/Security/ProtectedString.cs +++ /dev/null @@ -1,436 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Utility; - -#if KeePassLibSD -using KeePassLibSD; -#endif - -// SecureString objects are limited to 65536 characters, don't use - -namespace ModernKeePassLib.Security -{ - /// - /// A string that is protected in process memory. - /// ProtectedString objects are immutable and thread-safe. - /// -#if (DEBUG && !KeePassLibSD) - [DebuggerDisplay("{ReadString()}")] -#endif - public sealed class ProtectedString - { - // Exactly one of the following will be non-null - private ProtectedBinary m_pbUtf8 = null; - private string m_strPlainText = null; - - private bool m_bIsProtected; - - private static readonly ProtectedString m_psEmpty = new ProtectedString(); - /// - /// Get an empty ProtectedString object, without protection. - /// - public static ProtectedString Empty - { - get { return m_psEmpty; } - } - - private static readonly ProtectedString m_psEmptyEx = new ProtectedString( - true, new byte[0]); - /// - /// Get an empty ProtectedString object, with protection turned on. - /// - public static ProtectedString EmptyEx - { - get { return m_psEmptyEx; } - } - - /// - /// A flag specifying whether the ProtectedString object - /// has turned on memory protection or not. - /// - public bool IsProtected - { - get { return m_bIsProtected; } - } - - public bool IsEmpty - { - get - { - ProtectedBinary p = m_pbUtf8; // Local ref for thread-safety - if(p != null) return (p.Length == 0); - - Debug.Assert(m_strPlainText != null); - return (m_strPlainText.Length == 0); - } - } - - private int m_nCachedLength = -1; - /// - /// Length of the protected string, in characters. - /// - public int Length - { - get - { - if(m_nCachedLength >= 0) return m_nCachedLength; - - ProtectedBinary p = m_pbUtf8; // Local ref for thread-safety - if(p != null) - { - byte[] pbPlain = p.ReadData(); - try { m_nCachedLength = StrUtil.Utf8.GetCharCount(pbPlain); } - finally { MemUtil.ZeroByteArray(pbPlain); } - } - else - { - Debug.Assert(m_strPlainText != null); - m_nCachedLength = m_strPlainText.Length; - } - - return m_nCachedLength; - } - } - - /// - /// Construct a new protected string object. Protection is - /// disabled. - /// - public ProtectedString() - { - Init(false, string.Empty); - } - - /// - /// Construct a new protected string. The string is initialized - /// to the value supplied in the parameters. - /// - /// If this parameter is true, - /// the string will be protected in memory (encrypted). If it - /// is false, the string will be stored as plain-text. - /// The initial string value. - public ProtectedString(bool bEnableProtection, string strValue) - { - Init(bEnableProtection, strValue); - } - - /// - /// Construct a new protected string. The string is initialized - /// to the value supplied in the parameters (UTF-8 encoded string). - /// - /// If this parameter is true, - /// the string will be protected in memory (encrypted). If it - /// is false, the string will be stored as plain-text. - /// The initial string value, encoded as - /// UTF-8 byte array. This parameter won't be modified; the caller - /// is responsible for clearing it. - public ProtectedString(bool bEnableProtection, byte[] vUtf8Value) - { - Init(bEnableProtection, vUtf8Value); - } - - /// - /// Construct a new protected string. The string is initialized - /// to the value passed in the XorredBuffer object. - /// - /// Enable protection or not. - /// XorredBuffer object containing the - /// string in UTF-8 representation. The UTF-8 string must not - /// be null-terminated. - public ProtectedString(bool bEnableProtection, XorredBuffer xbProtected) - { - Debug.Assert(xbProtected != null); - if(xbProtected == null) throw new ArgumentNullException("xbProtected"); - - byte[] pb = xbProtected.ReadPlainText(); - try { Init(bEnableProtection, pb); } - finally { if(bEnableProtection) MemUtil.ZeroByteArray(pb); } - } - - private void Init(bool bEnableProtection, string str) - { - if(str == null) throw new ArgumentNullException("str"); - - m_bIsProtected = bEnableProtection; - - // As the string already is in memory and immutable, - // protection would be useless - m_strPlainText = str; - } - - private void Init(bool bEnableProtection, byte[] pbUtf8) - { - if(pbUtf8 == null) throw new ArgumentNullException("pbUtf8"); - - m_bIsProtected = bEnableProtection; - - if(bEnableProtection) - m_pbUtf8 = new ProtectedBinary(true, pbUtf8); - else - m_strPlainText = StrUtil.Utf8.GetString(pbUtf8, 0, pbUtf8.Length); - } - - /// - /// Convert the protected string to a standard string object. - /// Be careful with this function, as the returned string object - /// isn't protected anymore and stored in plain-text in the - /// process memory. - /// - /// Plain-text string. Is never null. - public string ReadString() - { - if(m_strPlainText != null) return m_strPlainText; - - byte[] pb = ReadUtf8(); - string str = ((pb.Length == 0) ? string.Empty : - StrUtil.Utf8.GetString(pb, 0, pb.Length)); - // No need to clear pb - - // As the text is now visible in process memory anyway, - // there's no need to protect it anymore (strings are - // immutable and thus cannot be overwritten) - m_strPlainText = str; - m_pbUtf8 = null; // Thread-safe order - - return str; - } - - /// - /// Read out the string and return it as a char array. - /// The returned array is not protected and should be cleared by - /// the caller. - /// - /// Plain-text char array. - public char[] ReadChars() - { - if(m_strPlainText != null) return m_strPlainText.ToCharArray(); - - byte[] pb = ReadUtf8(); - char[] v; - try { v = StrUtil.Utf8.GetChars(pb); } - finally { MemUtil.ZeroByteArray(pb); } - return v; - } - - /// - /// Read out the string and return a byte array that contains the - /// string encoded using UTF-8. - /// The returned array is not protected and should be cleared by - /// the caller. - /// - /// Plain-text UTF-8 byte array. - public byte[] ReadUtf8() - { - ProtectedBinary p = m_pbUtf8; // Local ref for thread-safety - if(p != null) return p.ReadData(); - - return StrUtil.Utf8.GetBytes(m_strPlainText); - } - - /// - /// Read the protected string and return it protected with a sequence - /// of bytes generated by a random stream. - /// - /// Random number source. - /// Protected string. - public byte[] ReadXorredString(CryptoRandomStream crsRandomSource) - { - if(crsRandomSource == null) { Debug.Assert(false); throw new ArgumentNullException("crsRandomSource"); } - - byte[] pbData = ReadUtf8(); - uint uLen = (uint)pbData.Length; - - byte[] randomPad = crsRandomSource.GetRandomBytes(uLen); - Debug.Assert(randomPad.Length == pbData.Length); - - for(uint i = 0; i < uLen; ++i) - pbData[i] ^= randomPad[i]; - - return pbData; - } - - public ProtectedString WithProtection(bool bProtect) - { - if(bProtect == m_bIsProtected) return this; - - byte[] pb = ReadUtf8(); - - // No need to clear pb; either the current or the new object is unprotected - return new ProtectedString(bProtect, pb); - } - - public bool Equals(ProtectedString ps, bool bCheckProtEqual) - { - if(ps == null) throw new ArgumentNullException("ps"); - if(object.ReferenceEquals(this, ps)) return true; // Perf. opt. - - bool bPA = m_bIsProtected, bPB = ps.m_bIsProtected; - if(bCheckProtEqual && (bPA != bPB)) return false; - if(!bPA && !bPB) return (ReadString() == ps.ReadString()); - - byte[] pbA = ReadUtf8(), pbB = null; - bool bEq; - try - { - pbB = ps.ReadUtf8(); - bEq = MemUtil.ArraysEqual(pbA, pbB); - } - finally - { - if(bPA) MemUtil.ZeroByteArray(pbA); - if(bPB && (pbB != null)) MemUtil.ZeroByteArray(pbB); - } - - return bEq; - } - - public ProtectedString Insert(int iStart, string strInsert) - { - if(iStart < 0) throw new ArgumentOutOfRangeException("iStart"); - if(strInsert == null) throw new ArgumentNullException("strInsert"); - if(strInsert.Length == 0) return this; - - if(!m_bIsProtected) - return new ProtectedString(false, ReadString().Insert( - iStart, strInsert)); - - UTF8Encoding utf8 = StrUtil.Utf8; - char[] v = ReadChars(), vNew = null; - byte[] pbNew = null; - ProtectedString ps; - - try - { - if(iStart > v.Length) - throw new ArgumentOutOfRangeException("iStart"); - - char[] vIns = strInsert.ToCharArray(); - - vNew = new char[v.Length + vIns.Length]; - Array.Copy(v, 0, vNew, 0, iStart); - Array.Copy(vIns, 0, vNew, iStart, vIns.Length); - Array.Copy(v, iStart, vNew, iStart + vIns.Length, - v.Length - iStart); - - pbNew = utf8.GetBytes(vNew); - ps = new ProtectedString(true, pbNew); - - Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) == - ReadString().Insert(iStart, strInsert)); - } - finally - { - MemUtil.ZeroArray(v); - if(vNew != null) MemUtil.ZeroArray(vNew); - if(pbNew != null) MemUtil.ZeroByteArray(pbNew); - } - - return ps; - } - - public ProtectedString Remove(int iStart, int nCount) - { - if(iStart < 0) throw new ArgumentOutOfRangeException("iStart"); - if(nCount < 0) throw new ArgumentOutOfRangeException("nCount"); - if(nCount == 0) return this; - - if(!m_bIsProtected) - return new ProtectedString(false, ReadString().Remove( - iStart, nCount)); - - UTF8Encoding utf8 = StrUtil.Utf8; - char[] v = ReadChars(), vNew = null; - byte[] pbNew = null; - ProtectedString ps; - - try - { - if((iStart + nCount) > v.Length) - throw new ArgumentException("(iStart + nCount) > v.Length"); - - vNew = new char[v.Length - nCount]; - Array.Copy(v, 0, vNew, 0, iStart); - Array.Copy(v, iStart + nCount, vNew, iStart, v.Length - - (iStart + nCount)); - - pbNew = utf8.GetBytes(vNew); - ps = new ProtectedString(true, pbNew); - - Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) == - ReadString().Remove(iStart, nCount)); - } - finally - { - MemUtil.ZeroArray(v); - if(vNew != null) MemUtil.ZeroArray(vNew); - if(pbNew != null) MemUtil.ZeroByteArray(pbNew); - } - - return ps; - } - - public static ProtectedString operator +(ProtectedString a, ProtectedString b) - { - if(a == null) throw new ArgumentNullException("a"); - if(b == null) throw new ArgumentNullException("b"); - - if(b.IsEmpty) return a; - if(a.IsEmpty) return b; - if(!a.IsProtected && !b.IsProtected) - return new ProtectedString(false, a.ReadString() + b.ReadString()); - - char[] vA = a.ReadChars(), vB = null, vNew = null; - byte[] pbNew = null; - ProtectedString ps; - - try - { - vB = b.ReadChars(); - - vNew = new char[vA.Length + vB.Length]; - Array.Copy(vA, vNew, vA.Length); - Array.Copy(vB, 0, vNew, vA.Length, vB.Length); - - pbNew = StrUtil.Utf8.GetBytes(vNew); - ps = new ProtectedString(true, pbNew); - } - finally - { - MemUtil.ZeroArray(vA); - if(vB != null) MemUtil.ZeroArray(vB); - if(vNew != null) MemUtil.ZeroArray(vNew); - if(pbNew != null) MemUtil.ZeroByteArray(pbNew); - } - - return ps; - } - - public static ProtectedString operator +(ProtectedString a, string b) - { - ProtectedString psB = new ProtectedString(false, b); - return (a + psB); - } - } -} diff --git a/ModernKeePassLib/Security/XorredBuffer.cs b/ModernKeePassLib/Security/XorredBuffer.cs deleted file mode 100644 index ec9cf64..0000000 --- a/ModernKeePassLib/Security/XorredBuffer.cs +++ /dev/null @@ -1,116 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Diagnostics; - -namespace ModernKeePassLib.Security -{ - /// - /// Represents an object that is encrypted using a XOR pad until - /// it is read. XorredBuffer objects are immutable and - /// thread-safe. - /// - public sealed class XorredBuffer - { - private byte[] m_pbData; // Never null - private byte[] m_pbXorPad; // Always valid for m_pbData - - /// - /// Length of the protected data in bytes. - /// - public uint Length - { - get { return (uint)m_pbData.Length; } - } - - /// - /// Construct a new XOR-protected object using a protected byte array - /// and a XOR pad that decrypts the protected data. The - /// byte array must have the same size - /// as the byte array. - /// The XorredBuffer object takes ownership of the two byte - /// arrays, i.e. the caller must not use or modify them afterwards. - /// - /// Protected data (XOR pad applied). - /// XOR pad that can be used to decrypt the - /// parameter. - /// Thrown if one of the input - /// parameters is null. - /// Thrown if the byte arrays are - /// of different size. - public XorredBuffer(byte[] pbProtectedData, byte[] pbXorPad) - { - if(pbProtectedData == null) { Debug.Assert(false); throw new ArgumentNullException("pbProtectedData"); } - if(pbXorPad == null) { Debug.Assert(false); throw new ArgumentNullException("pbXorPad"); } - - Debug.Assert(pbProtectedData.Length == pbXorPad.Length); - if(pbProtectedData.Length != pbXorPad.Length) throw new ArgumentException(); - - m_pbData = pbProtectedData; - m_pbXorPad = pbXorPad; - } - - /// - /// Get a copy of the plain-text. The caller is responsible - /// for clearing the byte array safely after using it. - /// - /// Unprotected plain-text byte array. - public byte[] ReadPlainText() - { - byte[] pbPlain = new byte[m_pbData.Length]; - - for(int i = 0; i < pbPlain.Length; ++i) - pbPlain[i] = (byte)(m_pbData[i] ^ m_pbXorPad[i]); - - return pbPlain; - } - - /* public bool EqualsValue(XorredBuffer xb) - { - if(xb == null) { Debug.Assert(false); throw new ArgumentNullException("xb"); } - - if(xb.m_pbData.Length != m_pbData.Length) return false; - - for(int i = 0; i < m_pbData.Length; ++i) - { - byte bt1 = (byte)(m_pbData[i] ^ m_pbXorPad[i]); - byte bt2 = (byte)(xb.m_pbData[i] ^ xb.m_pbXorPad[i]); - - if(bt1 != bt2) return false; - } - - return true; - } - - public bool EqualsValue(byte[] pb) - { - if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } - - if(pb.Length != m_pbData.Length) return false; - - for(int i = 0; i < m_pbData.Length; ++i) - { - if((byte)(m_pbData[i] ^ m_pbXorPad[i]) != pb[i]) return false; - } - - return true; - } */ - } -} diff --git a/ModernKeePassLib/Serialization/BinaryReaderEx.cs b/ModernKeePassLib/Serialization/BinaryReaderEx.cs deleted file mode 100644 index 4445ef4..0000000 --- a/ModernKeePassLib/Serialization/BinaryReaderEx.cs +++ /dev/null @@ -1,92 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Serialization -{ - public sealed class BinaryReaderEx - { - private Stream m_s; - // private Encoding m_enc; // See constructor - - private string m_strReadExcp; // May be null - public string ReadExceptionText - { - get { return m_strReadExcp; } - set { m_strReadExcp = value; } - } - - private Stream m_sCopyTo = null; - /// - /// If this property is set to a non-null stream, all data that - /// is read from the input stream is automatically written to - /// the copy stream (before returning the read data). - /// - public Stream CopyDataTo - { - get { return m_sCopyTo; } - set { m_sCopyTo = value; } - } - - public BinaryReaderEx(Stream input, Encoding encoding, - string strReadExceptionText) - { - if(input == null) throw new ArgumentNullException("input"); - - m_s = input; - // m_enc = encoding; // Not used yet - m_strReadExcp = strReadExceptionText; - } - - public byte[] ReadBytes(int nCount) - { - try - { - byte[] pb = MemUtil.Read(m_s, nCount); - if((pb == null) || (pb.Length != nCount)) - { - if(!string.IsNullOrEmpty(m_strReadExcp)) - throw new EndOfStreamException(m_strReadExcp); - else throw new EndOfStreamException(); - } - - if(m_sCopyTo != null) m_sCopyTo.Write(pb, 0, pb.Length); - return pb; - } - catch(Exception) - { - if(!string.IsNullOrEmpty(m_strReadExcp)) - throw new IOException(m_strReadExcp); - else throw; - } - } - - public byte ReadByte() - { - byte[] pb = ReadBytes(1); - return pb[0]; - } - } -} diff --git a/ModernKeePassLib/Serialization/FileLock.cs b/ModernKeePassLib/Serialization/FileLock.cs deleted file mode 100644 index e476acb..0000000 --- a/ModernKeePassLib/Serialization/FileLock.cs +++ /dev/null @@ -1,274 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; -using System.Threading; -#if ModernKeePassLib -using System.Runtime.InteropServices.WindowsRuntime; -using System.Threading.Tasks; -using Windows.Storage.Streams; -#endif -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Resources; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Serialization -{ - public sealed class FileLockException : Exception - { - private readonly string m_strMsg; - - public override string Message - { - get { return m_strMsg; } - } - - public FileLockException(string strBaseFile, string strUser) - { - StringBuilder sb = new StringBuilder(); - - if(!string.IsNullOrEmpty(strBaseFile)) - { - sb.Append(strBaseFile); - sb.Append(Environment.NewLine + Environment.NewLine); - } - - sb.Append(KLRes.FileLockedWrite); - sb.Append(Environment.NewLine); - - if(!string.IsNullOrEmpty(strUser)) sb.Append(strUser); - else sb.Append("?"); - - sb.Append(Environment.NewLine + Environment.NewLine); - sb.Append(KLRes.TryAgainSecs); - - m_strMsg = sb.ToString(); - } - } - - public sealed class FileLock : IDisposable - { - private const string LockFileExt = ".lock"; - private const string LockFileHeader = "KeePass Lock File"; - - private IOConnectionInfo m_iocLockFile; - - private sealed class LockFileInfo - { - public readonly string ID; - public readonly DateTime Time; - public readonly string UserName; - public readonly string Machine; - public readonly string Domain; - - private LockFileInfo(string strID, string strTime, string strUserName, - string strMachine, string strDomain) - { - this.ID = (strID ?? string.Empty).Trim(); - - DateTime dt; - if(TimeUtil.TryDeserializeUtc(strTime.Trim(), out dt)) - this.Time = dt; - else - { - Debug.Assert(false); - this.Time = DateTime.UtcNow; - } - - this.UserName = (strUserName ?? string.Empty).Trim(); - this.Machine = (strMachine ?? string.Empty).Trim(); - this.Domain = (strDomain ?? string.Empty).Trim(); - - if(this.Domain.Equals(this.Machine, StrUtil.CaseIgnoreCmp)) - this.Domain = string.Empty; - } - - public string GetOwner() - { - StringBuilder sb = new StringBuilder(); - sb.Append((this.UserName.Length > 0) ? this.UserName : "?"); - - bool bMachine = (this.Machine.Length > 0); - bool bDomain = (this.Domain.Length > 0); - if(bMachine || bDomain) - { - sb.Append(" ("); - sb.Append(this.Machine); - if(bMachine && bDomain) sb.Append(" @ "); - sb.Append(this.Domain); - sb.Append(")"); - } - - return sb.ToString(); - } - - public static LockFileInfo Load(IOConnectionInfo iocLockFile) - { - Stream s = null; - try - { - s = IOConnection.OpenRead(iocLockFile); - if(s == null) return null; - - string str = null; - using(StreamReader sr = new StreamReader(s, StrUtil.Utf8)) - { - str = sr.ReadToEnd(); - } - if(str == null) { Debug.Assert(false); return null; } - - str = StrUtil.NormalizeNewLines(str, false); - string[] v = str.Split('\n'); - if((v == null) || (v.Length < 6)) { Debug.Assert(false); return null; } - - if(!v[0].StartsWith(LockFileHeader)) { Debug.Assert(false); return null; } - return new LockFileInfo(v[1], v[2], v[3], v[4], v[5]); - } - catch(FileNotFoundException) { } - catch(Exception) { Debug.Assert(false); } - finally { if(s != null) s.Dispose(); } - - return null; - } - - // Throws on error - public static LockFileInfo Create(IOConnectionInfo iocLockFile) - { - LockFileInfo lfi; - Stream s = null; - try - { - byte[] pbID = CryptoRandom.Instance.GetRandomBytes(16); - string strTime = TimeUtil.SerializeUtc(DateTime.UtcNow); - - lfi = new LockFileInfo(Convert.ToBase64String(pbID), strTime, -#if KeePassUAP - EnvironmentExt.UserName, EnvironmentExt.MachineName, - EnvironmentExt.UserDomainName); -#elif ModernKeePassLib|| KeePassLibSD - string.Empty, string.Empty, string.Empty); -#else - Environment.UserName, Environment.MachineName, - Environment.UserDomainName); -#endif - - StringBuilder sb = new StringBuilder(); -#if !KeePassLibSD - sb.AppendLine(LockFileHeader); - sb.AppendLine(lfi.ID); - sb.AppendLine(strTime); - sb.AppendLine(lfi.UserName); - sb.AppendLine(lfi.Machine); - sb.AppendLine(lfi.Domain); -#else - sb.Append(LockFileHeader + Environment.NewLine); - sb.Append(lfi.ID + Environment.NewLine); - sb.Append(strTime + Environment.NewLine); - sb.Append(lfi.UserName + Environment.NewLine); - sb.Append(lfi.Machine + Environment.NewLine); - sb.Append(lfi.Domain + Environment.NewLine); -#endif - - byte[] pbFile = StrUtil.Utf8.GetBytes(sb.ToString()); - - s = IOConnection.OpenWrite(iocLockFile); - if(s == null) throw new IOException(iocLockFile.GetDisplayName()); - s.Write(pbFile, 0, pbFile.Length); - } - finally { if(s != null) s.Dispose(); } - - return lfi; - } - } - - public FileLock(IOConnectionInfo iocBaseFile) - { - if(iocBaseFile == null) throw new ArgumentNullException("strBaseFile"); - - m_iocLockFile = iocBaseFile.CloneDeep(); - m_iocLockFile.Path += LockFileExt; - - LockFileInfo lfiEx = LockFileInfo.Load(m_iocLockFile); - if(lfiEx != null) - { - m_iocLockFile = null; // Otherwise Dispose deletes the existing one - throw new FileLockException(iocBaseFile.GetDisplayName(), - lfiEx.GetOwner()); - } - - LockFileInfo.Create(m_iocLockFile); - } - - ~FileLock() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool bDisposing) - { - if(m_iocLockFile == null) return; - - bool bFileDeleted = false; - for(int r = 0; r < 5; ++r) - { - // if(!OwnLockFile()) { bFileDeleted = true; break; } - - try - { - IOConnection.DeleteFile(m_iocLockFile); - bFileDeleted = true; - } - catch(Exception) { Debug.Assert(false); } - - if(bFileDeleted) break; - -#if ModernKeePassLib - if(bDisposing) - Task.Delay(50).Wait(); -#else - if(bDisposing) Thread.Sleep(50); -#endif - } - - // if(bDisposing && !bFileDeleted) - // IOConnection.DeleteFile(m_iocLockFile); // Possibly with exception - - m_iocLockFile = null; - } - - // private bool OwnLockFile() - // { - // if(m_iocLockFile == null) { Debug.Assert(false); return false; } - // if(m_strLockID == null) { Debug.Assert(false); return false; } - // LockFileInfo lfi = LockFileInfo.Load(m_iocLockFile); - // if(lfi == null) return false; - // return m_strLockID.Equals(lfi.ID); - // } - } -} diff --git a/ModernKeePassLib/Serialization/FileTransactionEx.cs b/ModernKeePassLib/Serialization/FileTransactionEx.cs deleted file mode 100644 index 9cd871f..0000000 --- a/ModernKeePassLib/Serialization/FileTransactionEx.cs +++ /dev/null @@ -1,473 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Text; - -#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT) -using System.Security.AccessControl; -#endif - -using ModernKeePassLib.Native; -using ModernKeePassLib.Utility; -using System.Threading.Tasks; -using Windows.Storage; -using Windows.Storage.Streams; -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Resources; - -namespace ModernKeePassLib.Serialization -{ - public sealed class FileTransactionEx : IDisposable - { - private bool m_bTransacted; - private IOConnectionInfo m_iocBase; // Null means disposed - private IOConnectionInfo m_iocTemp; - private IOConnectionInfo m_iocTxfMidFallback = null; // Null <=> TxF not used - - private bool m_bMadeUnhidden = false; - - private List m_lToDelete = new List(); - - private const string StrTempSuffix = ".tmp"; - private const string StrTxfTempPrefix = PwDefs.ShortProductName + "_TxF_"; - private const string StrTxfTempSuffix = ".tmp"; - - private static Dictionary g_dEnabled = - new Dictionary(StrUtil.CaseIgnoreComparer); - - private static bool g_bExtraSafe = false; - internal static bool ExtraSafe - { - get { return g_bExtraSafe; } - set { g_bExtraSafe = value; } - } - - public FileTransactionEx(IOConnectionInfo iocBaseFile) : - this(iocBaseFile, true) - { - } - - public FileTransactionEx(IOConnectionInfo iocBaseFile, bool bTransacted) - { - if(iocBaseFile == null) throw new ArgumentNullException("iocBaseFile"); - - m_bTransacted = bTransacted; - - m_iocBase = iocBaseFile.CloneDeep(); - if(m_iocBase.IsLocalFile()) - m_iocBase.Path = UrlUtil.GetShortestAbsolutePath(m_iocBase.Path); - - string strPath = m_iocBase.Path; - -#if !ModernKeePassLib - if(m_iocBase.IsLocalFile()) - { - try - { - if(File.Exists(strPath)) - { - // Symbolic links are realized via reparse points; - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365503.aspx - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365680.aspx - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365006.aspx - // Performing a file transaction on a symbolic link - // would delete/replace the symbolic link instead of - // writing to its target - FileAttributes fa = File.GetAttributes(strPath); - if((long)(fa & FileAttributes.ReparsePoint) != 0) - m_bTransacted = false; - } - else - { - // If the base and the temporary file are in different - // folders and the base file doesn't exist (i.e. we can't - // backup the ACL), a transaction would cause the new file - // to have the default ACL of the temporary folder instead - // of the one of the base folder; therefore, we don't use - // a transaction when the base file doesn't exist (this - // also results in other applications monitoring the folder - // to see one file creation only) - m_bTransacted = false; - } - } - catch(Exception) { Debug.Assert(false); } - } -#endif - -#if !ModernKeePassLib - // Prevent transactions for FTP URLs under .NET 4.0 in order to - // avoid/workaround .NET bug 621450: - // https://connect.microsoft.com/VisualStudio/feedback/details/621450/problem-renaming-file-on-ftp-server-using-ftpwebrequest-in-net-framework-4-0-vs2010-only - if(strPath.StartsWith("ftp:", StrUtil.CaseIgnoreCmp) && - (Environment.Version.Major >= 4) && !NativeLib.IsUnix()) - m_bTransacted = false; -#endif - - foreach(KeyValuePair kvp in g_dEnabled) - { - if(strPath.StartsWith(kvp.Key, StrUtil.CaseIgnoreCmp)) - { - m_bTransacted = kvp.Value; - break; - } - } - - if(m_bTransacted) - { - m_iocTemp = m_iocBase.CloneDeep(); - m_iocTemp.Path += StrTempSuffix; - - TxfPrepare(); // Adjusts m_iocTemp - } - else m_iocTemp = m_iocBase; - } - - ~FileTransactionEx() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool bDisposing) - { - m_iocBase = null; - if(!bDisposing) return; - - try - { - foreach(IOConnectionInfo ioc in m_lToDelete) - { - if(IOConnection.FileExists(ioc, false)) - IOConnection.DeleteFile(ioc); - } - - m_lToDelete.Clear(); - } - catch(Exception) { Debug.Assert(false); } - } - - public Stream OpenWrite() - { - if(m_iocBase == null) { Debug.Assert(false); throw new ObjectDisposedException(null); } - - if(!m_bTransacted) m_bMadeUnhidden |= UrlUtil.UnhideFile(m_iocTemp.Path); - - return IOConnection.OpenWrite(m_iocTemp); - } - - public void CommitWrite() - { - if(m_iocBase == null) { Debug.Assert(false); throw new ObjectDisposedException(null); } - - if(!m_bTransacted) - { - if(m_bMadeUnhidden) UrlUtil.HideFile(m_iocTemp.Path, true); - } - else CommitWriteTransaction(); - - m_iocBase = null; // Dispose - } - - private void CommitWriteTransaction() - { - if(g_bExtraSafe) - { - if(!IOConnection.FileExists(m_iocTemp)) - throw new FileNotFoundException(m_iocTemp.Path + - MessageService.NewLine + KLRes.FileSaveFailed); - } - - bool bMadeUnhidden = UrlUtil.UnhideFile(m_iocBase.Path); - -#if !ModernKeePassLib - // 'All' includes 'Audit' (SACL), which requires SeSecurityPrivilege, - // which we usually don't have and therefore get an exception; - // trying to set 'Owner' or 'Group' can result in an - // UnauthorizedAccessException; thus we restore 'Access' (DACL) only - const AccessControlSections acs = AccessControlSections.Access; - -#endif - bool bEfsEncrypted = false; - byte[] pbSec = null; - DateTime? otCreation = null; - - bool bBaseExists = IOConnection.FileExists(m_iocBase); - if(bBaseExists && m_iocBase.IsLocalFile()) - { - // FileAttributes faBase = FileAttributes.Normal; - try - { -#if !ModernKeePassLib - FileAttributes faBase = File.GetAttributes(m_iocBase.Path); - bEfsEncrypted = ((long)(faBase & FileAttributes.Encrypted) != 0); - try { if(bEfsEncrypted) File.Decrypt(m_iocBase.Path); } // For TxF - catch(Exception) { Debug.Assert(false); } -#endif -#if ModernKeePassLib - otCreation = m_iocBase.StorageFile.DateCreated.UtcDateTime; -#else - otCreation = File.GetCreationTimeUtc(m_iocBase.Path); -#endif -#if !ModernKeePassLib - // May throw with Mono - FileSecurity sec = File.GetAccessControl(m_iocBase.Path, acs); - if(sec != null) pbSec = sec.GetSecurityDescriptorBinaryForm(); -#endif - } - catch(Exception) { Debug.Assert(NativeLib.IsUnix()); } - - // if((long)(faBase & FileAttributes.ReadOnly) != 0) - // throw new UnauthorizedAccessException(); - } - - if(!TxfMove()) - { - if(bBaseExists) IOConnection.DeleteFile(m_iocBase); - IOConnection.RenameFile(m_iocTemp, m_iocBase); - } - else { Debug.Assert(pbSec != null); } // TxF success => NTFS => has ACL - - try - { - // If File.GetCreationTimeUtc fails, it may return a - // date with year 1601, and Unix times start in 1970, - // so testing for 1971 should ensure validity; - // https://msdn.microsoft.com/en-us/library/system.io.file.getcreationtimeutc.aspx -#if !ModernKeePassLib - if(otCreation.HasValue && (otCreation.Value.Year >= 1971)) - File.SetCreationTimeUtc(m_iocBase.Path, otCreation.Value); -#endif - -#if !ModernKeePassLib - if(bEfsEncrypted) - { - try { File.Encrypt(m_iocBase.Path); } - catch(Exception) { Debug.Assert(false); } - } - - // File.SetAccessControl(m_iocBase.Path, secPrev); - // Directly calling File.SetAccessControl with the previous - // FileSecurity object does not work; the binary form - // indirection is required; - // https://sourceforge.net/p/keepass/bugs/1738/ - // https://msdn.microsoft.com/en-us/library/system.io.file.setaccesscontrol.aspx - if((pbSec != null) && (pbSec.Length != 0)) - { - FileSecurity sec = new FileSecurity(); - sec.SetSecurityDescriptorBinaryForm(pbSec, acs); - - File.SetAccessControl(m_iocBase.Path, sec); - } -#endif - } - catch (Exception) { Debug.Assert(false); } - - if(bMadeUnhidden) UrlUtil.HideFile(m_iocBase.Path, true); - } - - // For plugins - public static void Configure(string strPrefix, bool? obTransacted) - { - if(string.IsNullOrEmpty(strPrefix)) { Debug.Assert(false); return; } - - if(obTransacted.HasValue) - g_dEnabled[strPrefix] = obTransacted.Value; - else g_dEnabled.Remove(strPrefix); - } - - private static bool TxfIsSupported(char chDriveLetter) - { - if(chDriveLetter == '\0') return false; - -#if ModernKeePassLib - return true; -#else - try - { - string strRoot = (new string(chDriveLetter, 1)) + ":\\"; - - const int cch = NativeMethods.MAX_PATH + 1; - StringBuilder sbName = new StringBuilder(cch + 1); - uint uSerial = 0, cchMaxComp = 0, uFlags = 0; - StringBuilder sbFileSystem = new StringBuilder(cch + 1); - - if(!NativeMethods.GetVolumeInformation(strRoot, sbName, (uint)cch, - ref uSerial, ref cchMaxComp, ref uFlags, sbFileSystem, (uint)cch)) - { - Debug.Assert(false, (new Win32Exception()).Message); - return false; - } - - return ((uFlags & NativeMethods.FILE_SUPPORTS_TRANSACTIONS) != 0); - } - catch(Exception) { Debug.Assert(false); } - return false; -#endif - } - - private void TxfPrepare() - { - try - { - if(NativeLib.IsUnix()) return; - if(!m_iocBase.IsLocalFile()) return; - - string strID = StrUtil.AlphaNumericOnly(Convert.ToBase64String( - CryptoRandom.Instance.GetRandomBytes(16))); - string strTempDir = UrlUtil.GetTempPath(); - // See also ClearOld method - string strTemp = UrlUtil.EnsureTerminatingSeparator(strTempDir, - false) + StrTxfTempPrefix + strID + StrTxfTempSuffix; - - char chB = UrlUtil.GetDriveLetter(m_iocBase.Path); - char chT = UrlUtil.GetDriveLetter(strTemp); - if(!TxfIsSupported(chB)) return; - if((chT != chB) && !TxfIsSupported(chT)) return; - - m_iocTxfMidFallback = m_iocTemp; -#if ModernKeePassLib - var tempFile = ApplicationData.Current.TemporaryFolder.CreateFileAsync(m_iocTemp.Path).GetAwaiter() - .GetResult(); - m_iocTemp = IOConnectionInfo.FromFile(tempFile); -#else - m_iocTemp = IOConnectionInfo.FromPath(strTemp); -#endif - - m_lToDelete.Add(m_iocTemp); - } - catch(Exception) { Debug.Assert(false); m_iocTxfMidFallback = null; } - } - - private bool TxfMove() - { - if(m_iocTxfMidFallback == null) return false; - - if(TxfMoveWithTx()) return true; - - // Move the temporary file onto the base file's drive first, - // such that it cannot happen that both the base file and - // the temporary file are deleted/corrupted -#if ModernKeePassLib - m_iocTemp.StorageFile = ApplicationData.Current.TemporaryFolder.CreateFileAsync(m_iocTemp.Path).GetAwaiter() - .GetResult(); -#else - const uint f = (NativeMethods.MOVEFILE_COPY_ALLOWED | - NativeMethods.MOVEFILE_REPLACE_EXISTING); - bool b = NativeMethods.MoveFileEx(m_iocTemp.Path, m_iocTxfMidFallback.Path, f); - if(b) b = NativeMethods.MoveFileEx(m_iocTxfMidFallback.Path, m_iocBase.Path, f); - if(!b) throw new Win32Exception(); - - Debug.Assert(!File.Exists(m_iocTemp.Path)); - Debug.Assert(!File.Exists(m_iocTxfMidFallback.Path)); -#endif - return true; - } - - private bool TxfMoveWithTx() - { -#if ModernKeePassLib - return true; -#else - IntPtr hTx = new IntPtr((int)NativeMethods.INVALID_HANDLE_VALUE); - Debug.Assert(hTx.ToInt64() == NativeMethods.INVALID_HANDLE_VALUE); - try - { - string strTx = PwDefs.ShortProductName + " TxF - " + - StrUtil.AlphaNumericOnly(Convert.ToBase64String( - CryptoRandom.Instance.GetRandomBytes(16))); - const int mchTx = NativeMethods.MAX_TRANSACTION_DESCRIPTION_LENGTH; - if(strTx.Length >= mchTx) strTx = strTx.Substring(0, mchTx - 1); - - hTx = NativeMethods.CreateTransaction(IntPtr.Zero, - IntPtr.Zero, 0, 0, 0, 0, strTx); - if(hTx.ToInt64() == NativeMethods.INVALID_HANDLE_VALUE) - { - Debug.Assert(false, (new Win32Exception()).Message); - return false; - } - - if(!NativeMethods.MoveFileTransacted(m_iocTemp.Path, m_iocBase.Path, - IntPtr.Zero, IntPtr.Zero, (NativeMethods.MOVEFILE_COPY_ALLOWED | - NativeMethods.MOVEFILE_REPLACE_EXISTING), hTx)) - { - Debug.Assert(false, (new Win32Exception()).Message); - return false; - } - - if(!NativeMethods.CommitTransaction(hTx)) - { - Debug.Assert(false, (new Win32Exception()).Message); - return false; - } - - Debug.Assert(!File.Exists(m_iocTemp.Path)); - return true; - } - catch(Exception) { Debug.Assert(false); } - finally - { - if(hTx.ToInt64() != NativeMethods.INVALID_HANDLE_VALUE) - { - try { if(!NativeMethods.CloseHandle(hTx)) { Debug.Assert(false); } } - catch(Exception) { Debug.Assert(false); } - } - } - return false; -#endif - } - - internal static void ClearOld() - { - try - { -#if ModernKeePassLib - ApplicationData.Current.TemporaryFolder.GetFileAsync(UrlUtil.GetTempPath()).GetAwaiter() - .GetResult().DeleteAsync().GetAwaiter().GetResult(); -#else -// See also TxfPrepare method - DirectoryInfo di = new DirectoryInfo(UrlUtil.GetTempPath()); - List l = UrlUtil.GetFileInfos(di, StrTxfTempPrefix + - "*" + StrTxfTempSuffix, SearchOption.TopDirectoryOnly); - - foreach(FileInfo fi in l) - { - if(fi == null) { Debug.Assert(false); continue; } - if(!fi.Name.StartsWith(StrTxfTempPrefix, StrUtil.CaseIgnoreCmp) || - !fi.Name.EndsWith(StrTxfTempSuffix, StrUtil.CaseIgnoreCmp)) - continue; - - if((DateTime.UtcNow - fi.LastWriteTimeUtc).TotalDays > 1.0) - fi.Delete(); - } -#endif - } - catch(Exception) { Debug.Assert(false); } - } - } -} diff --git a/ModernKeePassLib/Serialization/HashedBlockStream.cs b/ModernKeePassLib/Serialization/HashedBlockStream.cs deleted file mode 100644 index 8454ae9..0000000 --- a/ModernKeePassLib/Serialization/HashedBlockStream.cs +++ /dev/null @@ -1,312 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Diagnostics; -using System.IO; -using System.Text; - -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Native; -using ModernKeePassLib.Utility; - -#if KeePassLibSD -using KeePassLibSD; -#endif - -namespace ModernKeePassLib.Serialization -{ - public sealed class HashedBlockStream : Stream - { - private const int NbDefaultBufferSize = 1024 * 1024; // 1 MB - - private Stream m_sBaseStream; - private bool m_bWriting; - private bool m_bVerify; - private bool m_bEos = false; - - private BinaryReader m_brInput; - private BinaryWriter m_bwOutput; - - private byte[] m_pbBuffer; - private int m_nBufferPos = 0; - - private uint m_uBlockIndex = 0; - - public override bool CanRead - { - get { return !m_bWriting; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return m_bWriting; } - } - - public override long Length - { - get { Debug.Assert(false); throw new NotSupportedException(); } - } - - public override long Position - { - get { Debug.Assert(false); throw new NotSupportedException(); } - set { Debug.Assert(false); throw new NotSupportedException(); } - } - - public HashedBlockStream(Stream sBaseStream, bool bWriting) - { - Initialize(sBaseStream, bWriting, 0, true); - } - - public HashedBlockStream(Stream sBaseStream, bool bWriting, int nBufferSize) - { - Initialize(sBaseStream, bWriting, nBufferSize, true); - } - - public HashedBlockStream(Stream sBaseStream, bool bWriting, int nBufferSize, - bool bVerify) - { - Initialize(sBaseStream, bWriting, nBufferSize, bVerify); - } - - private void Initialize(Stream sBaseStream, bool bWriting, int nBufferSize, - bool bVerify) - { - if(sBaseStream == null) throw new ArgumentNullException("sBaseStream"); - if(nBufferSize < 0) throw new ArgumentOutOfRangeException("nBufferSize"); - - if(nBufferSize == 0) nBufferSize = NbDefaultBufferSize; - - m_sBaseStream = sBaseStream; - m_bWriting = bWriting; - m_bVerify = bVerify; - - UTF8Encoding utf8 = StrUtil.Utf8; - if(!m_bWriting) // Reading mode - { - if(!m_sBaseStream.CanRead) - throw new InvalidOperationException(); - - m_brInput = new BinaryReader(sBaseStream, utf8); - - m_pbBuffer = MemUtil.EmptyByteArray; - } - else // Writing mode - { - if(!m_sBaseStream.CanWrite) - throw new InvalidOperationException(); - - m_bwOutput = new BinaryWriter(sBaseStream, utf8); - - m_pbBuffer = new byte[nBufferSize]; - } - } - - protected override void Dispose(bool disposing) - { - if(disposing && (m_sBaseStream != null)) - { - if(!m_bWriting) // Reading mode - { - m_brInput.Dispose(); - m_brInput = null; - } - else // Writing mode - { - if(m_nBufferPos == 0) // No data left in buffer - WriteHashedBlock(); // Write terminating block - else - { - WriteHashedBlock(); // Write remaining buffered data - WriteHashedBlock(); // Write terminating block - } - - Flush(); - m_bwOutput.Dispose(); - m_bwOutput = null; - } - - m_sBaseStream.Dispose(); - m_sBaseStream = null; - } - - base.Dispose(disposing); - } - - public override void Flush() - { - if(m_bWriting) m_bwOutput.Flush(); - } - - public override long Seek(long lOffset, SeekOrigin soOrigin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long lValue) - { - throw new NotSupportedException(); - } - - public override int Read(byte[] pbBuffer, int nOffset, int nCount) - { - if(m_bWriting) throw new InvalidOperationException(); - - int nRemaining = nCount; - while(nRemaining > 0) - { - if(m_nBufferPos == m_pbBuffer.Length) - { - if(ReadHashedBlock() == false) - return (nCount - nRemaining); // Bytes actually read - } - - int nCopy = Math.Min(m_pbBuffer.Length - m_nBufferPos, nRemaining); - - Array.Copy(m_pbBuffer, m_nBufferPos, pbBuffer, nOffset, nCopy); - - nOffset += nCopy; - m_nBufferPos += nCopy; - - nRemaining -= nCopy; - } - - return nCount; - } - - private bool ReadHashedBlock() - { - if(m_bEos) return false; // End of stream reached already - - m_nBufferPos = 0; - - if(m_brInput.ReadUInt32() != m_uBlockIndex) - throw new InvalidDataException(); - ++m_uBlockIndex; - - byte[] pbStoredHash = m_brInput.ReadBytes(32); - if((pbStoredHash == null) || (pbStoredHash.Length != 32)) - throw new InvalidDataException(); - - int nBufferSize = 0; - try { nBufferSize = m_brInput.ReadInt32(); } - catch(NullReferenceException) // Mono bug workaround (LaunchPad 783268) - { - if(!NativeLib.IsUnix()) throw; - } - - if(nBufferSize < 0) - throw new InvalidDataException(); - - if(nBufferSize == 0) - { - for(int iHash = 0; iHash < 32; ++iHash) - { - if(pbStoredHash[iHash] != 0) - throw new InvalidDataException(); - } - - m_bEos = true; - m_pbBuffer = MemUtil.EmptyByteArray; - return false; - } - - m_pbBuffer = m_brInput.ReadBytes(nBufferSize); - if((m_pbBuffer == null) || ((m_pbBuffer.Length != nBufferSize) && m_bVerify)) - throw new InvalidDataException(); - - if(m_bVerify) - { - byte[] pbComputedHash = CryptoUtil.HashSha256(m_pbBuffer); - if((pbComputedHash == null) || (pbComputedHash.Length != 32)) - throw new InvalidOperationException(); - - if(!MemUtil.ArraysEqual(pbStoredHash, pbComputedHash)) - throw new InvalidDataException(); - } - - return true; - } - - public override void Write(byte[] pbBuffer, int nOffset, int nCount) - { - if(!m_bWriting) throw new InvalidOperationException(); - - while(nCount > 0) - { - if(m_nBufferPos == m_pbBuffer.Length) - WriteHashedBlock(); - - int nCopy = Math.Min(m_pbBuffer.Length - m_nBufferPos, nCount); - - Array.Copy(pbBuffer, nOffset, m_pbBuffer, m_nBufferPos, nCopy); - - nOffset += nCopy; - m_nBufferPos += nCopy; - - nCount -= nCopy; - } - } - - private void WriteHashedBlock() - { - m_bwOutput.Write(m_uBlockIndex); - ++m_uBlockIndex; - - if(m_nBufferPos > 0) - { - byte[] pbHash = CryptoUtil.HashSha256(m_pbBuffer, 0, m_nBufferPos); - - // For KeePassLibSD: - // SHA256Managed sha256 = new SHA256Managed(); - // byte[] pbHash; - // if(m_nBufferPos == m_pbBuffer.Length) - // pbHash = sha256.ComputeHash(m_pbBuffer); - // else - // { - // byte[] pbData = new byte[m_nBufferPos]; - // Array.Copy(m_pbBuffer, 0, pbData, 0, m_nBufferPos); - // pbHash = sha256.ComputeHash(pbData); - // } - - m_bwOutput.Write(pbHash); - } - else - { - m_bwOutput.Write((ulong)0); // Zero hash - m_bwOutput.Write((ulong)0); - m_bwOutput.Write((ulong)0); - m_bwOutput.Write((ulong)0); - } - - m_bwOutput.Write(m_nBufferPos); - - if(m_nBufferPos > 0) - m_bwOutput.Write(m_pbBuffer, 0, m_nBufferPos); - - m_nBufferPos = 0; - } - } -} diff --git a/ModernKeePassLib/Serialization/HmacBlockStream.cs b/ModernKeePassLib/Serialization/HmacBlockStream.cs deleted file mode 100644 index 96be7e8..0000000 --- a/ModernKeePassLib/Serialization/HmacBlockStream.cs +++ /dev/null @@ -1,326 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; - -#if ModernKeePassLib -using ModernKeePassLib.Cryptography.Hash; -#elif !KeePassUAP -using System.Security.Cryptography; -#endif - -using ModernKeePassLib.Resources; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Serialization -{ - public sealed class HmacBlockStream : Stream - { - private const int NbDefaultBufferSize = 1024 * 1024; // 1 MB - - private Stream m_sBase; - private readonly bool m_bWriting; - private readonly bool m_bVerify; - private byte[] m_pbKey; - - private bool m_bEos = false; - private byte[] m_pbBuffer; - private int m_iBufferPos = 0; - - private ulong m_uBlockIndex = 0; - - public override bool CanRead - { - get { return !m_bWriting; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return m_bWriting; } - } - - public override long Length - { - get { Debug.Assert(false); throw new NotSupportedException(); } - } - - public override long Position - { - get { Debug.Assert(false); throw new NotSupportedException(); } - set { Debug.Assert(false); throw new NotSupportedException(); } - } - - public HmacBlockStream(Stream sBase, bool bWriting, bool bVerify, - byte[] pbKey) - { - if(sBase == null) throw new ArgumentNullException("sBase"); - if(pbKey == null) throw new ArgumentNullException("pbKey"); - - m_sBase = sBase; - m_bWriting = bWriting; - m_bVerify = bVerify; - m_pbKey = pbKey; - - if(!m_bWriting) // Reading mode - { - if(!m_sBase.CanRead) throw new InvalidOperationException(); - - m_pbBuffer = MemUtil.EmptyByteArray; - } - else // Writing mode - { - if(!m_sBase.CanWrite) throw new InvalidOperationException(); - - m_pbBuffer = new byte[NbDefaultBufferSize]; - } - } - - protected override void Dispose(bool disposing) - { - if(disposing && (m_sBase != null)) - { - if(m_bWriting) - { - if(m_iBufferPos == 0) // No data left in buffer - WriteSafeBlock(); // Write terminating block - else - { - WriteSafeBlock(); // Write remaining buffered data - WriteSafeBlock(); // Write terminating block - } - - Flush(); - } - - m_sBase.Dispose(); - m_sBase = null; - } - - base.Dispose(disposing); - } - - public override void Flush() - { - Debug.Assert(m_sBase != null); // Object should not be disposed - if(m_bWriting && (m_sBase != null)) m_sBase.Flush(); - } - - public override long Seek(long lOffset, SeekOrigin soOrigin) - { - Debug.Assert(false); - throw new NotSupportedException(); - } - - public override void SetLength(long lValue) - { - Debug.Assert(false); - throw new NotSupportedException(); - } - - internal static byte[] GetHmacKey64(byte[] pbKey, ulong uBlockIndex) - { - if(pbKey == null) throw new ArgumentNullException("pbKey"); - Debug.Assert(pbKey.Length == 64); - - // We are computing the HMAC using SHA-256, whose internal - // block size is 512 bits; thus create a key that is 512 - // bits long (using SHA-512) - - byte[] pbBlockKey; - using(SHA512Managed h = new SHA512Managed()) - { - byte[] pbIndex = MemUtil.UInt64ToBytes(uBlockIndex); - - h.TransformBlock(pbIndex, 0, pbIndex.Length, pbIndex, 0); - h.TransformBlock(pbKey, 0, pbKey.Length, pbKey, 0); - h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); - - pbBlockKey = h.Hash; - } - -#if DEBUG - byte[] pbZero = new byte[64]; - Debug.Assert((pbBlockKey.Length == 64) && !MemUtil.ArraysEqual( - pbBlockKey, pbZero)); // Ensure we own pbBlockKey -#endif - return pbBlockKey; - } - - public override int Read(byte[] pbBuffer, int iOffset, int nCount) - { - if(m_bWriting) throw new InvalidOperationException(); - - int nRemaining = nCount; - while(nRemaining > 0) - { - if(m_iBufferPos == m_pbBuffer.Length) - { - if(!ReadSafeBlock()) - return (nCount - nRemaining); // Bytes actually read - } - - int nCopy = Math.Min(m_pbBuffer.Length - m_iBufferPos, nRemaining); - Debug.Assert(nCopy > 0); - - Array.Copy(m_pbBuffer, m_iBufferPos, pbBuffer, iOffset, nCopy); - - iOffset += nCopy; - m_iBufferPos += nCopy; - - nRemaining -= nCopy; - } - - return nCount; - } - - private bool ReadSafeBlock() - { - if(m_bEos) return false; // End of stream reached already - - byte[] pbStoredHmac = MemUtil.Read(m_sBase, 32); - if((pbStoredHmac == null) || (pbStoredHmac.Length != 32)) - throw new EndOfStreamException(KLRes.FileCorrupted + " " + - KLRes.FileIncomplete); - - // Block index is implicit: it's used in the HMAC computation, - // but does not need to be stored - // byte[] pbBlockIndex = MemUtil.Read(m_sBase, 8); - // if((pbBlockIndex == null) || (pbBlockIndex.Length != 8)) - // throw new EndOfStreamException(); - // ulong uBlockIndex = MemUtil.BytesToUInt64(pbBlockIndex); - // if((uBlockIndex != m_uBlockIndex) && m_bVerify) - // throw new InvalidDataException(); - byte[] pbBlockIndex = MemUtil.UInt64ToBytes(m_uBlockIndex); - - byte[] pbBlockSize = MemUtil.Read(m_sBase, 4); - if((pbBlockSize == null) || (pbBlockSize.Length != 4)) - throw new EndOfStreamException(KLRes.FileCorrupted + " " + - KLRes.FileIncomplete); - int nBlockSize = MemUtil.BytesToInt32(pbBlockSize); - if(nBlockSize < 0) - throw new InvalidDataException(KLRes.FileCorrupted); - - m_iBufferPos = 0; - - m_pbBuffer = MemUtil.Read(m_sBase, nBlockSize); - if((m_pbBuffer == null) || ((m_pbBuffer.Length != nBlockSize) && m_bVerify)) - throw new EndOfStreamException(KLRes.FileCorrupted + " " + - KLRes.FileIncompleteExpc); - - if(m_bVerify) - { - byte[] pbCmpHmac; - byte[] pbBlockKey = GetHmacKey64(m_pbKey, m_uBlockIndex); - using(HMACSHA256 h = new HMACSHA256(pbBlockKey)) - { - h.TransformBlock(pbBlockIndex, 0, pbBlockIndex.Length, - pbBlockIndex, 0); - h.TransformBlock(pbBlockSize, 0, pbBlockSize.Length, - pbBlockSize, 0); - - if(m_pbBuffer.Length > 0) - h.TransformBlock(m_pbBuffer, 0, m_pbBuffer.Length, - m_pbBuffer, 0); - - h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); - - pbCmpHmac = h.Hash; - } - MemUtil.ZeroByteArray(pbBlockKey); - - if(!MemUtil.ArraysEqual(pbCmpHmac, pbStoredHmac)) - throw new InvalidDataException(KLRes.FileCorrupted); - } - - ++m_uBlockIndex; - - if(nBlockSize == 0) - { - m_bEos = true; - return false; // No further data available - } - return true; - } - - public override void Write(byte[] pbBuffer, int iOffset, int nCount) - { - if(!m_bWriting) throw new InvalidOperationException(); - - while(nCount > 0) - { - if(m_iBufferPos == m_pbBuffer.Length) - WriteSafeBlock(); - - int nCopy = Math.Min(m_pbBuffer.Length - m_iBufferPos, nCount); - Debug.Assert(nCopy > 0); - - Array.Copy(pbBuffer, iOffset, m_pbBuffer, m_iBufferPos, nCopy); - - iOffset += nCopy; - m_iBufferPos += nCopy; - - nCount -= nCopy; - } - } - - private void WriteSafeBlock() - { - byte[] pbBlockIndex = MemUtil.UInt64ToBytes(m_uBlockIndex); - - int cbBlockSize = m_iBufferPos; - byte[] pbBlockSize = MemUtil.Int32ToBytes(cbBlockSize); - - byte[] pbBlockHmac; - byte[] pbBlockKey = GetHmacKey64(m_pbKey, m_uBlockIndex); - using(HMACSHA256 h = new HMACSHA256(pbBlockKey)) - { - h.TransformBlock(pbBlockIndex, 0, pbBlockIndex.Length, - pbBlockIndex, 0); - h.TransformBlock(pbBlockSize, 0, pbBlockSize.Length, - pbBlockSize, 0); - - if(cbBlockSize > 0) - h.TransformBlock(m_pbBuffer, 0, cbBlockSize, m_pbBuffer, 0); - - h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); - - pbBlockHmac = h.Hash; - } - MemUtil.ZeroByteArray(pbBlockKey); - - MemUtil.Write(m_sBase, pbBlockHmac); - // MemUtil.Write(m_sBase, pbBlockIndex); // Implicit - MemUtil.Write(m_sBase, pbBlockSize); - if(cbBlockSize > 0) - m_sBase.Write(m_pbBuffer, 0, cbBlockSize); - - ++m_uBlockIndex; - m_iBufferPos = 0; - } - } -} diff --git a/ModernKeePassLib/Serialization/IOConnection.cs b/ModernKeePassLib/Serialization/IOConnection.cs deleted file mode 100644 index a3a9161..0000000 --- a/ModernKeePassLib/Serialization/IOConnection.cs +++ /dev/null @@ -1,926 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Net; -using System.Reflection; -using System.Text; - -#if (!ModernKeePassLib && !KeePassLibSD && !KeePassUAP) -using System.Net.Cache; -using System.Net.Security; -#endif - -#if !ModernKeePassLib && !KeePassUAP -using System.Security.Cryptography.X509Certificates; -#endif - -#if ModernKeePassLib -using Windows.Storage; -using Windows.Storage.Streams; -#endif -using ModernKeePassLib.Native; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Serialization -{ -#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT) - internal sealed class IOWebClient : WebClient - { - private IOConnectionInfo m_ioc; - - public IOWebClient(IOConnectionInfo ioc) : base() - { - m_ioc = ioc; - } - - protected override WebRequest GetWebRequest(Uri address) - { - WebRequest request = base.GetWebRequest(address); - IOConnection.ConfigureWebRequest(request, m_ioc); - return request; - } - } -#endif - -#if !ModernKeePassLib - internal abstract class WrapperStream : Stream - { - private readonly Stream m_s; - protected Stream BaseStream - { - get { return m_s; } - } - - public override bool CanRead - { - get { return m_s.CanRead; } - } - - public override bool CanSeek - { - get { return m_s.CanSeek; } - } - - public override bool CanTimeout - { - get { return m_s.CanTimeout; } - } - - public override bool CanWrite - { - get { return m_s.CanWrite; } - } - - public override long Length - { - get { return m_s.Length; } - } - - public override long Position - { - get { return m_s.Position; } - set { m_s.Position = value; } - } - - public override int ReadTimeout - { - get { return m_s.ReadTimeout; } - set { m_s.ReadTimeout = value; } - } - - public override int WriteTimeout - { - get { return m_s.WriteTimeout; } - set { m_s.WriteTimeout = value; } - } - - public WrapperStream(Stream sBase) : base() - { - if(sBase == null) throw new ArgumentNullException("sBase"); - - m_s = sBase; - } - -#if !KeePassUAP - public override IAsyncResult BeginRead(byte[] buffer, int offset, - int count, AsyncCallback callback, object state) - { - return m_s.BeginRead(buffer, offset, count, callback, state); - } - - public override IAsyncResult BeginWrite(byte[] buffer, int offset, - int count, AsyncCallback callback, object state) - { - return BeginWrite(buffer, offset, count, callback, state); - } -#endif - - protected override void Dispose(bool disposing) - { - if(disposing) m_s.Dispose(); - - base.Dispose(disposing); - } - -#if !KeePassUAP - public override int EndRead(IAsyncResult asyncResult) - { - return m_s.EndRead(asyncResult); - } - - public override void EndWrite(IAsyncResult asyncResult) - { - m_s.EndWrite(asyncResult); - } -#endif - - public override void Flush() - { - m_s.Flush(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - return m_s.Read(buffer, offset, count); - } - - public override int ReadByte() - { - return m_s.ReadByte(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - return m_s.Seek(offset, origin); - } - - public override void SetLength(long value) - { - m_s.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - m_s.Write(buffer, offset, count); - } - - public override void WriteByte(byte value) - { - m_s.WriteByte(value); - } - } - - internal sealed class IocStream : WrapperStream - { - private readonly bool m_bWrite; // Initially opened for writing - private bool m_bDisposed = false; - - public IocStream(Stream sBase) : base(sBase) - { - m_bWrite = sBase.CanWrite; - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if(disposing && MonoWorkarounds.IsRequired(10163) && m_bWrite && - !m_bDisposed) - { - try - { - Stream s = this.BaseStream; - Type t = s.GetType(); - if(t.Name == "WebConnectionStream") - { - PropertyInfo pi = t.GetProperty("Request", - BindingFlags.Instance | BindingFlags.NonPublic); - if(pi != null) - { - WebRequest wr = (pi.GetValue(s, null) as WebRequest); - if(wr != null) - IOConnection.DisposeResponse(wr.GetResponse(), false); - else { Debug.Assert(false); } - } - else { Debug.Assert(false); } - } - } - catch(Exception) { Debug.Assert(false); } - } - - m_bDisposed = true; - } - - public static Stream WrapIfRequired(Stream s) - { - if(s == null) { Debug.Assert(false); return null; } - - if(MonoWorkarounds.IsRequired(10163) && s.CanWrite) - return new IocStream(s); - - return s; - } - } -#endif - - public static class IOConnection - { -#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT) - private static ProxyServerType m_pstProxyType = ProxyServerType.System; - private static string m_strProxyAddr = string.Empty; - private static string m_strProxyPort = string.Empty; - private static ProxyAuthType m_patProxyAuthType = ProxyAuthType.Auto; - private static string m_strProxyUserName = string.Empty; - private static string m_strProxyPassword = string.Empty; - -#if !KeePassUAP - private static bool? m_obDefaultExpect100Continue = null; - - private static bool m_bSslCertsAcceptInvalid = false; - internal static bool SslCertsAcceptInvalid - { - // get { return m_bSslCertsAcceptInvalid; } - set { m_bSslCertsAcceptInvalid = value; } - } -#endif -#endif - - // Web request methods - public const string WrmDeleteFile = "DELETEFILE"; - public const string WrmMoveFile = "MOVEFILE"; - - // Web request headers - public const string WrhMoveFileTo = "MoveFileTo"; - - public static event EventHandler IOAccessPre; - -#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT) - // Allow self-signed certificates, expired certificates, etc. - private static bool AcceptCertificate(object sender, - X509Certificate certificate, X509Chain chain, - SslPolicyErrors sslPolicyErrors) - { - return true; - } - - internal static void SetProxy(ProxyServerType pst, string strAddr, - string strPort, ProxyAuthType pat, string strUserName, - string strPassword) - { - m_pstProxyType = pst; - m_strProxyAddr = (strAddr ?? string.Empty); - m_strProxyPort = (strPort ?? string.Empty); - m_patProxyAuthType = pat; - m_strProxyUserName = (strUserName ?? string.Empty); - m_strProxyPassword = (strPassword ?? string.Empty); - } - - internal static void ConfigureWebRequest(WebRequest request, - IOConnectionInfo ioc) - { - if(request == null) { Debug.Assert(false); return; } // No throw - - IocProperties p = ((ioc != null) ? ioc.Properties : null); - if(p == null) { Debug.Assert(false); p = new IocProperties(); } - - IHasIocProperties ihpReq = (request as IHasIocProperties); - if(ihpReq != null) - { - IocProperties pEx = ihpReq.IOConnectionProperties; - if(pEx != null) p.CopyTo(pEx); - else ihpReq.IOConnectionProperties = p.CloneDeep(); - } - - if(IsHttpWebRequest(request)) - { - // WebDAV support -#if !KeePassUAP - request.PreAuthenticate = true; // Also auth GET -#endif - if(string.Equals(request.Method, WebRequestMethods.Http.Post, - StrUtil.CaseIgnoreCmp)) - request.Method = WebRequestMethods.Http.Put; - -#if !KeePassUAP - HttpWebRequest hwr = (request as HttpWebRequest); - if(hwr != null) - { - string strUA = p.Get(IocKnownProperties.UserAgent); - if(!string.IsNullOrEmpty(strUA)) hwr.UserAgent = strUA; - } - else { Debug.Assert(false); } -#endif - } -#if !KeePassUAP - else if(IsFtpWebRequest(request)) - { - FtpWebRequest fwr = (request as FtpWebRequest); - if(fwr != null) - { - bool? obPassive = p.GetBool(IocKnownProperties.Passive); - if(obPassive.HasValue) fwr.UsePassive = obPassive.Value; - } - else { Debug.Assert(false); } - } -#endif - -#if !KeePassUAP - // Not implemented and ignored in Mono < 2.10 - try - { - request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); - } - catch(NotImplementedException) { } - catch(Exception) { Debug.Assert(false); } -#endif - - try - { - IWebProxy prx; - if(GetWebProxy(out prx)) request.Proxy = prx; - } - catch(Exception) { Debug.Assert(false); } - -#if !KeePassUAP - long? olTimeout = p.GetLong(IocKnownProperties.Timeout); - if(olTimeout.HasValue && (olTimeout.Value >= 0)) - request.Timeout = (int)Math.Min(olTimeout.Value, (long)int.MaxValue); - - bool? ob = p.GetBool(IocKnownProperties.PreAuth); - if(ob.HasValue) request.PreAuthenticate = ob.Value; -#endif - } - - internal static void ConfigureWebClient(WebClient wc) - { -#if !KeePassUAP - // Not implemented and ignored in Mono < 2.10 - try - { - wc.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); - } - catch(NotImplementedException) { } - catch(Exception) { Debug.Assert(false); } -#endif - - try - { - IWebProxy prx; - if(GetWebProxy(out prx)) wc.Proxy = prx; - } - catch(Exception) { Debug.Assert(false); } - } - - private static bool GetWebProxy(out IWebProxy prx) - { - bool b = GetWebProxyServer(out prx); - if(b) AssignCredentials(prx); - return b; - } - - private static bool GetWebProxyServer(out IWebProxy prx) - { - prx = null; - - if(m_pstProxyType == ProxyServerType.None) - return true; // Use null proxy - - if(m_pstProxyType == ProxyServerType.Manual) - { - try - { - if(m_strProxyAddr.Length == 0) - { - // First try default (from config), then system - prx = WebRequest.DefaultWebProxy; -#if !KeePassUAP - if(prx == null) prx = WebRequest.GetSystemWebProxy(); -#endif - } - else if(m_strProxyPort.Length > 0) - prx = new WebProxy(m_strProxyAddr, int.Parse(m_strProxyPort)); - else prx = new WebProxy(m_strProxyAddr); - - return (prx != null); - } -#if KeePassUAP - catch(Exception) { Debug.Assert(false); } -#else - catch(Exception ex) - { - string strInfo = m_strProxyAddr; - if(m_strProxyPort.Length > 0) - strInfo += ":" + m_strProxyPort; - MessageService.ShowWarning(strInfo, ex); - } -#endif - - return false; // Use default - } - - Debug.Assert(m_pstProxyType == ProxyServerType.System); - try - { - // First try system, then default (from config) -#if !KeePassUAP - prx = WebRequest.GetSystemWebProxy(); -#endif - if(prx == null) prx = WebRequest.DefaultWebProxy; - - return (prx != null); - } - catch(Exception) { Debug.Assert(false); } - - return false; - } - - private static void AssignCredentials(IWebProxy prx) - { - if(prx == null) return; // No assert - - string strUserName = m_strProxyUserName; - string strPassword = m_strProxyPassword; - - ProxyAuthType pat = m_patProxyAuthType; - if(pat == ProxyAuthType.Auto) - { - if((strUserName.Length > 0) || (strPassword.Length > 0)) - pat = ProxyAuthType.Manual; - else pat = ProxyAuthType.Default; - } - - try - { - if(pat == ProxyAuthType.None) - prx.Credentials = null; - else if(pat == ProxyAuthType.Default) - prx.Credentials = CredentialCache.DefaultCredentials; - else if(pat == ProxyAuthType.Manual) - { - if((strUserName.Length > 0) || (strPassword.Length > 0)) - prx.Credentials = new NetworkCredential( - strUserName, strPassword); - } - else { Debug.Assert(false); } - } - catch(Exception) { Debug.Assert(false); } - } - - private static void PrepareWebAccess(IOConnectionInfo ioc) - { -#if !KeePassUAP - IocProperties p = ((ioc != null) ? ioc.Properties : null); - if(p == null) { Debug.Assert(false); p = new IocProperties(); } - - try - { - if(m_bSslCertsAcceptInvalid) - ServicePointManager.ServerCertificateValidationCallback = - IOConnection.AcceptCertificate; - else - ServicePointManager.ServerCertificateValidationCallback = null; - } - catch(Exception) { Debug.Assert(false); } - - try - { - SecurityProtocolType spt = (SecurityProtocolType.Ssl3 | - SecurityProtocolType.Tls); - - // The flags Tls11 and Tls12 in SecurityProtocolType have been - // introduced in .NET 4.5 and must not be set when running under - // older .NET versions (otherwise an exception is thrown) - Type tSpt = typeof(SecurityProtocolType); - string[] vSpt = Enum.GetNames(tSpt); - foreach(string strSpt in vSpt) - { - if(strSpt.Equals("Tls11", StrUtil.CaseIgnoreCmp)) - spt |= (SecurityProtocolType)Enum.Parse(tSpt, "Tls11", true); - else if(strSpt.Equals("Tls12", StrUtil.CaseIgnoreCmp)) - spt |= (SecurityProtocolType)Enum.Parse(tSpt, "Tls12", true); - } - - ServicePointManager.SecurityProtocol = spt; - } - catch(Exception) { Debug.Assert(false); } - - try - { - bool bCurCont = ServicePointManager.Expect100Continue; - if(!m_obDefaultExpect100Continue.HasValue) - { - Debug.Assert(bCurCont); // Default should be true - m_obDefaultExpect100Continue = bCurCont; - } - - bool bNewCont = m_obDefaultExpect100Continue.Value; - bool? ob = p.GetBool(IocKnownProperties.Expect100Continue); - if(ob.HasValue) bNewCont = ob.Value; - - if(bNewCont != bCurCont) - ServicePointManager.Expect100Continue = bNewCont; - } - catch(Exception) { Debug.Assert(false); } -#endif - } - - private static IOWebClient CreateWebClient(IOConnectionInfo ioc) - { - PrepareWebAccess(ioc); - - IOWebClient wc = new IOWebClient(ioc); - ConfigureWebClient(wc); - - if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0)) - wc.Credentials = new NetworkCredential(ioc.UserName, ioc.Password); - else if(NativeLib.IsUnix()) // Mono requires credentials - wc.Credentials = new NetworkCredential("anonymous", string.Empty); - - return wc; - } - - private static WebRequest CreateWebRequest(IOConnectionInfo ioc) - { - PrepareWebAccess(ioc); - - WebRequest req = WebRequest.Create(ioc.Path); - ConfigureWebRequest(req, ioc); - - if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0)) - req.Credentials = new NetworkCredential(ioc.UserName, ioc.Password); - else if(NativeLib.IsUnix()) // Mono requires credentials - req.Credentials = new NetworkCredential("anonymous", string.Empty); - - return req; - } - - public static Stream OpenRead(IOConnectionInfo ioc) - { - RaiseIOAccessPreEvent(ioc, IOAccessType.Read); - - if(StrUtil.IsDataUri(ioc.Path)) - { - byte[] pbData = StrUtil.DataUriToData(ioc.Path); - if(pbData != null) return new MemoryStream(pbData, false); - } - - if(ioc.IsLocalFile()) return OpenReadLocal(ioc); - - return IocStream.WrapIfRequired(CreateWebClient(ioc).OpenRead( - new Uri(ioc.Path))); - } -#else - public static Stream OpenRead(IOConnectionInfo ioc) - { - RaiseIOAccessPreEvent(ioc, IOAccessType.Read); - - return OpenReadLocal(ioc); - } -#endif - - private static Stream OpenReadLocal(IOConnectionInfo ioc) - { - return ioc.StorageFile.OpenAsync(FileAccessMode.Read).GetAwaiter().GetResult().AsStream(); - } - -#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT) - public static Stream OpenWrite(IOConnectionInfo ioc) - { - if(ioc == null) { Debug.Assert(false); return null; } - - RaiseIOAccessPreEvent(ioc, IOAccessType.Write); - - if(ioc.IsLocalFile()) return OpenWriteLocal(ioc); - - Uri uri = new Uri(ioc.Path); - Stream s; - - // Mono does not set HttpWebRequest.Method to POST for writes, - // so one needs to set the method to PUT explicitly - if(NativeLib.IsUnix() && IsHttpWebRequest(uri)) - s = CreateWebClient(ioc).OpenWrite(uri, WebRequestMethods.Http.Put); - else s = CreateWebClient(ioc).OpenWrite(uri); - - return IocStream.WrapIfRequired(s); - } -#else - public static Stream OpenWrite(IOConnectionInfo ioc) - { - RaiseIOAccessPreEvent(ioc, IOAccessType.Write); - - return OpenWriteLocal(ioc); - } -#endif - - private static Stream OpenWriteLocal(IOConnectionInfo ioc) - { -#if ModernKeePassLib - return ioc.StorageFile.OpenAsync(FileAccessMode.ReadWrite).GetAwaiter().GetResult().AsStream(); -#else - return new FileStream(ioc.Path, FileMode.Create, FileAccess.Write, - FileShare.None); -#endif - } - - public static bool FileExists(IOConnectionInfo ioc) - { - return FileExists(ioc, false); - } - - public static bool FileExists(IOConnectionInfo ioc, bool bThrowErrors) - { - if(ioc == null) { Debug.Assert(false); return false; } - - RaiseIOAccessPreEvent(ioc, IOAccessType.Exists); - -#if ModernKeePassLib - return ioc.StorageFile.IsAvailable; -#else - if(ioc.IsLocalFile()) return File.Exists(ioc.Path); - -#if !KeePassLibSD - if(ioc.Path.StartsWith("ftp://", StrUtil.CaseIgnoreCmp)) - { - bool b = SendCommand(ioc, WebRequestMethods.Ftp.GetDateTimestamp); - if(!b && bThrowErrors) throw new InvalidOperationException(); - return b; - } -#endif - - try - { - Stream s = OpenRead(ioc); - if(s == null) throw new FileNotFoundException(); - - try { s.ReadByte(); } - catch(Exception) { } - - // We didn't download the file completely; close may throw - // an exception -- that's okay - try { s.Close(); } - catch(Exception) { } - } - catch(Exception) - { - if(bThrowErrors) throw; - return false; - } - - return true; -#endif - } - - public static void DeleteFile(IOConnectionInfo ioc) - { - RaiseIOAccessPreEvent(ioc, IOAccessType.Delete); - -#if ModernKeePassLib - if (!ioc.IsLocalFile()) return; - ioc.StorageFile?.DeleteAsync().GetAwaiter().GetResult(); -#else - if(ioc.IsLocalFile()) { File.Delete(ioc.Path); return; } - -#if !KeePassLibSD - WebRequest req = CreateWebRequest(ioc); - if(req != null) - { - if(IsHttpWebRequest(req)) req.Method = "DELETE"; - else if(IsFtpWebRequest(req)) - req.Method = WebRequestMethods.Ftp.DeleteFile; - else if(IsFileWebRequest(req)) - { - File.Delete(UrlUtil.FileUrlToPath(ioc.Path)); - return; - } - else req.Method = WrmDeleteFile; - - DisposeResponse(req.GetResponse(), true); - } -#endif -#endif - } - - /// - /// Rename/move a file. For local file system and WebDAV, the - /// specified file is moved, i.e. the file destination can be - /// in a different directory/path. In contrast, for FTP the - /// file is renamed, i.e. its destination must be in the same - /// directory/path. - /// - /// Source file path. - /// Target file path. - public static void RenameFile(IOConnectionInfo iocFrom, IOConnectionInfo iocTo) - { - RaiseIOAccessPreEvent(iocFrom, iocTo, IOAccessType.Move); - -#if ModernKeePassLib - if (!iocFrom.IsLocalFile()) return; - iocFrom.StorageFile?.RenameAsync(iocTo.Path).GetAwaiter().GetResult(); -#else - if(iocFrom.IsLocalFile()) { File.Move(iocFrom.Path, iocTo.Path); return; } - -#if !KeePassLibSD - WebRequest req = CreateWebRequest(iocFrom); - if(req != null) - { - if(IsHttpWebRequest(req)) - { -#if KeePassUAP - throw new NotSupportedException(); -#else - req.Method = "MOVE"; - req.Headers.Set("Destination", iocTo.Path); // Full URL supported -#endif - } - else if(IsFtpWebRequest(req)) - { -#if KeePassUAP - throw new NotSupportedException(); -#else - req.Method = WebRequestMethods.Ftp.Rename; - string strTo = UrlUtil.GetFileName(iocTo.Path); - - // We're affected by .NET bug 621450: - // https://connect.microsoft.com/VisualStudio/feedback/details/621450/problem-renaming-file-on-ftp-server-using-ftpwebrequest-in-net-framework-4-0-vs2010-only - // Prepending "./", "%2E/" or "Dummy/../" doesn't work. - - ((FtpWebRequest)req).RenameTo = strTo; -#endif - } - else if(IsFileWebRequest(req)) - { - File.Move(UrlUtil.FileUrlToPath(iocFrom.Path), - UrlUtil.FileUrlToPath(iocTo.Path)); - return; - } - else - { -#if KeePassUAP - throw new NotSupportedException(); -#else - req.Method = WrmMoveFile; - req.Headers.Set(WrhMoveFileTo, iocTo.Path); -#endif - } - -#if !KeePassUAP // Unreachable code - DisposeResponse(req.GetResponse(), true); -#endif - } -#endif - - // using(Stream sIn = IOConnection.OpenRead(iocFrom)) - // { - // using(Stream sOut = IOConnection.OpenWrite(iocTo)) - // { - // MemUtil.CopyStream(sIn, sOut); - // sOut.Close(); - // } - // - // sIn.Close(); - // } - // DeleteFile(iocFrom); -#endif - } - -#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT) - private static bool SendCommand(IOConnectionInfo ioc, string strMethod) - { - try - { - WebRequest req = CreateWebRequest(ioc); - req.Method = strMethod; - DisposeResponse(req.GetResponse(), true); - } - catch(Exception) { return false; } - - return true; - } -#endif -#if !ModernKeePassLib - internal static void DisposeResponse(WebResponse wr, bool bGetStream) - { - if(wr == null) return; - - try - { - if(bGetStream) - { - Stream s = wr.GetResponseStream(); - if(s != null) s.Close(); - } - } - catch(Exception) { Debug.Assert(false); } - - try { wr.Close(); } - catch(Exception) { Debug.Assert(false); } - } -#endif - public static byte[] ReadFile(IOConnectionInfo ioc) - { - Stream sIn = null; - MemoryStream ms = null; - try - { - sIn = IOConnection.OpenRead(ioc); - if(sIn == null) return null; - - ms = new MemoryStream(); - MemUtil.CopyStream(sIn, ms); - - return ms.ToArray(); - } - catch(Exception) { } - finally - { - if(sIn != null) sIn.Dispose(); - if(ms != null) ms.Dispose(); - } - - return null; - } - - private static void RaiseIOAccessPreEvent(IOConnectionInfo ioc, IOAccessType t) - { - RaiseIOAccessPreEvent(ioc, null, t); - } - - private static void RaiseIOAccessPreEvent(IOConnectionInfo ioc, - IOConnectionInfo ioc2, IOAccessType t) - { - if(ioc == null) { Debug.Assert(false); return; } - // ioc2 may be null - - if(IOConnection.IOAccessPre != null) - { - IOConnectionInfo ioc2Lcl = ((ioc2 != null) ? ioc2.CloneDeep() : null); - IOAccessEventArgs e = new IOAccessEventArgs(ioc.CloneDeep(), ioc2Lcl, t); - IOConnection.IOAccessPre(null, e); - } - } -#if !ModernKeePassLib - private static bool IsHttpWebRequest(Uri uri) - { - if(uri == null) { Debug.Assert(false); return false; } - - string sch = uri.Scheme; - if(sch == null) { Debug.Assert(false); return false; } - return (sch.Equals("http", StrUtil.CaseIgnoreCmp) || // Uri.UriSchemeHttp - sch.Equals("https", StrUtil.CaseIgnoreCmp)); // Uri.UriSchemeHttps - } - - internal static bool IsHttpWebRequest(WebRequest wr) - { - if(wr == null) { Debug.Assert(false); return false; } - -#if KeePassUAP - return IsHttpWebRequest(wr.RequestUri); -#else - return (wr is HttpWebRequest); -#endif - } - - internal static bool IsFtpWebRequest(WebRequest wr) - { - if(wr == null) { Debug.Assert(false); return false; } - -#if KeePassUAP - return string.Equals(wr.RequestUri.Scheme, "ftp", StrUtil.CaseIgnoreCmp); -#else - return (wr is FtpWebRequest); -#endif - } - - private static bool IsFileWebRequest(WebRequest wr) - { - if(wr == null) { Debug.Assert(false); return false; } - -#if KeePassUAP - return string.Equals(wr.RequestUri.Scheme, "file", StrUtil.CaseIgnoreCmp); -#else - return (wr is FileWebRequest); -#endif - } -#endif // ModernKeePass - } -} diff --git a/ModernKeePassLib/Serialization/IOConnectionInfo.cs b/ModernKeePassLib/Serialization/IOConnectionInfo.cs deleted file mode 100644 index fd37f02..0000000 --- a/ModernKeePassLib/Serialization/IOConnectionInfo.cs +++ /dev/null @@ -1,392 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Text; -using System.Xml.Serialization; -#if ModernKeePassLib -using Windows.Storage; -//using PCLStorage; -#endif - -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Utility; -using System.Threading.Tasks; - -namespace ModernKeePassLib.Serialization -{ - public enum IOCredSaveMode - { - /// - /// Do not remember user name or password. - /// - NoSave = 0, - - /// - /// Remember the user name only, not the password. - /// - UserNameOnly, - - /// - /// Save both user name and password. - /// - SaveCred - } - - public enum IOCredProtMode - { - None = 0, - Obf - } - - /* public enum IOFileFormatHint - { - None = 0, - Deprecated - } */ - - public sealed class IOConnectionInfo : IDeepCloneable - { - // private IOFileFormatHint m_ioHint = IOFileFormatHint.None; - - private string m_strUrl = string.Empty; - public string Path - { - get { return m_strUrl; } - set - { - Debug.Assert(value != null); - if(value == null) throw new ArgumentNullException("value"); - - m_strUrl = value; - } - } - - private string m_strUser = string.Empty; - [DefaultValue("")] - public string UserName - { - get { return m_strUser; } - set - { - Debug.Assert(value != null); - if(value == null) throw new ArgumentNullException("value"); - - m_strUser = value; - } - } - - private string m_strPassword = string.Empty; - [DefaultValue("")] - public string Password - { - get { return m_strPassword; } - set - { - Debug.Assert(value != null); - if(value == null) throw new ArgumentNullException("value"); - - m_strPassword = value; - } - } - - private IOCredProtMode m_ioCredProtMode = IOCredProtMode.None; - public IOCredProtMode CredProtMode - { - get { return m_ioCredProtMode; } - set { m_ioCredProtMode = value; } - } - - private IOCredSaveMode m_ioCredSaveMode = IOCredSaveMode.NoSave; - public IOCredSaveMode CredSaveMode - { - get { return m_ioCredSaveMode; } - set { m_ioCredSaveMode = value; } - } - - private bool m_bComplete = false; - [XmlIgnore] - public bool IsComplete // Credentials etc. fully specified - { - get { return m_bComplete; } - set { m_bComplete = value; } - } - - /* public IOFileFormatHint FileFormatHint - { - get { return m_ioHint; } - set { m_ioHint = value; } - } */ - - private IocProperties m_props = new IocProperties(); - [XmlIgnore] - public IocProperties Properties - { - get { return m_props; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_props = value; - } - } - - /// - /// For serialization only; use Properties in code. - /// - [DefaultValue("")] - public string PropertiesEx - { - get { return m_props.Serialize(); } - set - { - if(value == null) throw new ArgumentNullException("value"); - - IocProperties p = IocProperties.Deserialize(value); - Debug.Assert(p != null); - m_props = (p ?? new IocProperties()); - } - } - - public IOConnectionInfo CloneDeep() - { - IOConnectionInfo ioc = (IOConnectionInfo)this.MemberwiseClone(); - ioc.m_props = m_props.CloneDeep(); - return ioc; - } - -#if DEBUG // For debugger display only - public override string ToString() - { - return GetDisplayName(); - } -#endif - - /* - /// - /// Serialize the current connection info to a string. Credentials - /// are serialized based on the CredSaveMode property. - /// - /// Input object to be serialized. - /// Serialized object as string. - public static string SerializeToString(IOConnectionInfo iocToCompile) - { - Debug.Assert(iocToCompile != null); - if(iocToCompile == null) throw new ArgumentNullException("iocToCompile"); - - string strUrl = iocToCompile.Path; - string strUser = TransformUnreadable(iocToCompile.UserName, true); - string strPassword = TransformUnreadable(iocToCompile.Password, true); - - string strAll = strUrl + strUser + strPassword + "CUN"; - char chSep = StrUtil.GetUnusedChar(strAll); - if(chSep == char.MinValue) throw new FormatException(); - - StringBuilder sb = new StringBuilder(); - sb.Append(chSep); - sb.Append(strUrl); - sb.Append(chSep); - - if(iocToCompile.CredSaveMode == IOCredSaveMode.SaveCred) - { - sb.Append('C'); - sb.Append(chSep); - sb.Append(strUser); - sb.Append(chSep); - sb.Append(strPassword); - } - else if(iocToCompile.CredSaveMode == IOCredSaveMode.UserNameOnly) - { - sb.Append('U'); - sb.Append(chSep); - sb.Append(strUser); - sb.Append(chSep); - } - else // Don't remember credentials - { - sb.Append('N'); - sb.Append(chSep); - sb.Append(chSep); - } - - return sb.ToString(); - } - - public static IOConnectionInfo UnserializeFromString(string strToDecompile) - { - Debug.Assert(strToDecompile != null); - if(strToDecompile == null) throw new ArgumentNullException("strToDecompile"); - if(strToDecompile.Length <= 1) throw new ArgumentException(); - - char chSep = strToDecompile[0]; - string[] vParts = strToDecompile.Substring(1, strToDecompile.Length - - 1).Split(new char[]{ chSep }); - if(vParts.Length < 4) throw new ArgumentException(); - - IOConnectionInfo s = new IOConnectionInfo(); - s.Path = vParts[0]; - - if(vParts[1] == "C") - s.CredSaveMode = IOCredSaveMode.SaveCred; - else if(vParts[1] == "U") - s.CredSaveMode = IOCredSaveMode.UserNameOnly; - else - s.CredSaveMode = IOCredSaveMode.NoSave; - - s.UserName = TransformUnreadable(vParts[2], false); - s.Password = TransformUnreadable(vParts[3], false); - return s; - } - */ - - /* - /// - /// Very simple string protection. Doesn't really encrypt the input - /// string, only encodes it that it's not readable on the first glance. - /// - /// The string to encode/decode. - /// If true, the string will be encoded, - /// otherwise it'll be decoded. - /// Encoded/decoded string. - private static string TransformUnreadable(string strToEncode, bool bEncode) - { - Debug.Assert(strToEncode != null); - if(strToEncode == null) throw new ArgumentNullException("strToEncode"); - - if(bEncode) - { - byte[] pbUtf8 = StrUtil.Utf8.GetBytes(strToEncode); - - unchecked - { - for(int iPos = 0; iPos < pbUtf8.Length; ++iPos) - pbUtf8[iPos] += (byte)(iPos * 11); - } - - return Convert.ToBase64String(pbUtf8); - } - else // Decode - { - byte[] pbBase = Convert.FromBase64String(strToEncode); - - unchecked - { - for(int iPos = 0; iPos < pbBase.Length; ++iPos) - pbBase[iPos] -= (byte)(iPos * 11); - } - - return StrUtil.Utf8.GetString(pbBase, 0, pbBase.Length); - } - } - */ - - public string GetDisplayName() - { - string str = m_strUrl; - - if(m_strUser.Length > 0) - str += (" (" + m_strUser + ")"); - - return str; - } - - public bool IsEmpty() - { - return (m_strUrl.Length == 0); - } - - public static IOConnectionInfo FromPath(string strPath) - { - IOConnectionInfo ioc = new IOConnectionInfo(); - - ioc.Path = strPath; - ioc.CredSaveMode = IOCredSaveMode.NoSave; - - return ioc; - } - - public static IOConnectionInfo FromFile(StorageFile file) - { - IOConnectionInfo ioc = new IOConnectionInfo(); - - ioc.StorageFile = file; - ioc.Path = file.Path; - ioc.CredSaveMode = IOCredSaveMode.NoSave; - - return ioc; - } - - public StorageFile StorageFile { get; set; } - - public bool CanProbablyAccess() - { -#if ModernKeePassLib - if (IsLocalFile()) - { - //return (FileSystem.Current.GetFileFromPathAsync(m_strUrl).Result != null); - var file = StorageFile.GetFileFromPathAsync(m_strUrl).GetAwaiter().GetResult(); - return file != null; - } -#else - if(IsLocalFile()) return File.Exists(m_strUrl); -#endif - - return true; - } - - public bool IsLocalFile() - { - // Not just ":/", see e.g. AppConfigEx.ChangePathRelAbs - return (m_strUrl.IndexOf("://") < 0); - } - - public void ClearCredentials(bool bDependingOnRememberMode) - { - if((bDependingOnRememberMode == false) || - (m_ioCredSaveMode == IOCredSaveMode.NoSave)) - { - m_strUser = string.Empty; - } - - if((bDependingOnRememberMode == false) || - (m_ioCredSaveMode == IOCredSaveMode.NoSave) || - (m_ioCredSaveMode == IOCredSaveMode.UserNameOnly)) - { - m_strPassword = string.Empty; - } - } - - public void Obfuscate(bool bObf) - { - if(bObf && (m_ioCredProtMode == IOCredProtMode.None)) - { - m_strPassword = StrUtil.Obfuscate(m_strPassword); - m_ioCredProtMode = IOCredProtMode.Obf; - } - else if(!bObf && (m_ioCredProtMode == IOCredProtMode.Obf)) - { - m_strPassword = StrUtil.Deobfuscate(m_strPassword); - m_ioCredProtMode = IOCredProtMode.None; - } - } - } -} diff --git a/ModernKeePassLib/Serialization/IocProperties.cs b/ModernKeePassLib/Serialization/IocProperties.cs deleted file mode 100644 index 01c5a94..0000000 --- a/ModernKeePassLib/Serialization/IocProperties.cs +++ /dev/null @@ -1,192 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using System.Xml; - -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Utility; - -using StrDict = System.Collections.Generic.Dictionary; - -namespace ModernKeePassLib.Serialization -{ - public interface IHasIocProperties - { - IocProperties IOConnectionProperties { get; set; } - } - - public sealed class IocProperties : IDeepCloneable - { - private StrDict m_dict = new StrDict(); - - public IocProperties() - { - } - - public IocProperties CloneDeep() - { - IocProperties p = new IocProperties(); - p.m_dict = new StrDict(m_dict); - return p; - } - - public string Get(string strKey) - { - if(string.IsNullOrEmpty(strKey)) return null; - - foreach(KeyValuePair kvp in m_dict) - { - if(kvp.Key.Equals(strKey, StrUtil.CaseIgnoreCmp)) - return kvp.Value; - } - - return null; - } - - public void Set(string strKey, string strValue) - { - if(string.IsNullOrEmpty(strKey)) { Debug.Assert(false); return; } - - foreach(KeyValuePair kvp in m_dict) - { - if(kvp.Key.Equals(strKey, StrUtil.CaseIgnoreCmp)) - { - if(string.IsNullOrEmpty(strValue)) m_dict.Remove(kvp.Key); - else m_dict[kvp.Key] = strValue; - return; - } - } - - if(!string.IsNullOrEmpty(strValue)) m_dict[strKey] = strValue; - } - - public bool? GetBool(string strKey) - { - string str = Get(strKey); - if(string.IsNullOrEmpty(str)) return null; - - return StrUtil.StringToBool(str); - } - - public void SetBool(string strKey, bool? ob) - { - if(ob.HasValue) Set(strKey, (ob.Value ? "1" : "0")); - else Set(strKey, null); - } - - public long? GetLong(string strKey) - { - string str = Get(strKey); - if(string.IsNullOrEmpty(str)) return null; - - long l; - if(StrUtil.TryParseLongInvariant(str, out l)) return l; - Debug.Assert(false); - return null; - } - - public void SetLong(string strKey, long? ol) - { - if(ol.HasValue) - Set(strKey, ol.Value.ToString(NumberFormatInfo.InvariantInfo)); - else Set(strKey, null); - } - - public string Serialize() - { - if(m_dict.Count == 0) return string.Empty; - - StringBuilder sbAll = new StringBuilder(); - foreach(KeyValuePair kvp in m_dict) - { - sbAll.Append(kvp.Key); - sbAll.Append(kvp.Value); - } - - string strAll = sbAll.ToString(); - char chSepOuter = ';'; - if(strAll.IndexOf(chSepOuter) >= 0) - chSepOuter = StrUtil.GetUnusedChar(strAll); - - strAll += chSepOuter; - char chSepInner = '='; - if(strAll.IndexOf(chSepInner) >= 0) - chSepInner = StrUtil.GetUnusedChar(strAll); - - StringBuilder sb = new StringBuilder(); - sb.Append(chSepOuter); - sb.Append(chSepInner); - - foreach(KeyValuePair kvp in m_dict) - { - sb.Append(chSepOuter); - sb.Append(kvp.Key); - sb.Append(chSepInner); - sb.Append(kvp.Value); - } - - return sb.ToString(); - } - - public static IocProperties Deserialize(string strSerialized) - { - IocProperties p = new IocProperties(); - if(string.IsNullOrEmpty(strSerialized)) return p; // No assert - - char chSepOuter = strSerialized[0]; - string[] v = strSerialized.Substring(1).Split(new char[] { chSepOuter }); - if((v == null) || (v.Length < 2)) { Debug.Assert(false); return p; } - - string strMeta = v[0]; - if(string.IsNullOrEmpty(strMeta)) { Debug.Assert(false); return p; } - - char chSepInner = strMeta[0]; - char[] vSepInner = new char[] { chSepInner }; - - for(int i = 1; i < v.Length; ++i) - { - string strProp = v[i]; - if(string.IsNullOrEmpty(strProp)) { Debug.Assert(false); continue; } - - string[] vProp = strProp.Split(vSepInner); - if((vProp == null) || (vProp.Length < 2)) { Debug.Assert(false); continue; } - Debug.Assert(vProp.Length == 2); - - p.Set(vProp[0], vProp[1]); - } - - return p; - } - - public void CopyTo(IocProperties p) - { - if(p == null) { Debug.Assert(false); return; } - - foreach(KeyValuePair kvp in m_dict) - { - p.m_dict[kvp.Key] = kvp.Value; - } - } - } -} diff --git a/ModernKeePassLib/Serialization/IocPropertyInfo.cs b/ModernKeePassLib/Serialization/IocPropertyInfo.cs deleted file mode 100644 index c86c7c0..0000000 --- a/ModernKeePassLib/Serialization/IocPropertyInfo.cs +++ /dev/null @@ -1,99 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Serialization -{ - public sealed class IocPropertyInfo - { - private readonly string m_strName; - public string Name - { - get { return m_strName; } - } - - private readonly Type m_t; - public Type Type - { - get { return m_t; } - } - - private string m_strDisplayName; - public string DisplayName - { - get { return m_strDisplayName; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strDisplayName = value; - } - } - - private List m_lProtocols = new List(); - public IEnumerable Protocols - { - get { return m_lProtocols; } - } - - public IocPropertyInfo(string strName, Type t, string strDisplayName, - string[] vProtocols) - { - if(strName == null) throw new ArgumentNullException("strName"); - if(t == null) throw new ArgumentNullException("t"); - if(strDisplayName == null) throw new ArgumentNullException("strDisplayName"); - - m_strName = strName; - m_t = t; - m_strDisplayName = strDisplayName; - - AddProtocols(vProtocols); - } - - public void AddProtocols(string[] v) - { - if(v == null) { Debug.Assert(false); return; } - - foreach(string strProtocol in v) - { - if(strProtocol == null) continue; - - string str = strProtocol.Trim(); - if(str.Length == 0) continue; - - bool bFound = false; - foreach(string strEx in m_lProtocols) - { - if(strEx.Equals(str, StrUtil.CaseIgnoreCmp)) - { - bFound = true; - break; - } - } - - if(!bFound) m_lProtocols.Add(str); - } - } - } -} diff --git a/ModernKeePassLib/Serialization/IocPropertyInfoPool.cs b/ModernKeePassLib/Serialization/IocPropertyInfoPool.cs deleted file mode 100644 index cfe39be..0000000 --- a/ModernKeePassLib/Serialization/IocPropertyInfoPool.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -using ModernKeePassLib.Resources; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Serialization -{ - public static class IocKnownProtocols - { - public const string Http = "HTTP"; - public const string Https = "HTTPS"; - public const string WebDav = "WebDAV"; - public const string Ftp = "FTP"; - } - - public static class IocKnownProperties - { - public const string Timeout = "Timeout"; - public const string PreAuth = "PreAuth"; - - public const string UserAgent = "UserAgent"; - public const string Expect100Continue = "Expect100Continue"; - - public const string Passive = "Passive"; - } - - public static class IocPropertyInfoPool - { - private static List m_l = null; - public static IEnumerable PropertyInfos - { - get { EnsureInitialized(); return m_l; } - } - - private static void EnsureInitialized() - { - if(m_l != null) return; - - string strGen = KLRes.General; - string strHttp = IocKnownProtocols.Http; - string strHttps = IocKnownProtocols.Https; - string strWebDav = IocKnownProtocols.WebDav; - string strFtp = IocKnownProtocols.Ftp; - - string[] vGen = new string[] { strGen }; - string[] vHttp = new string[] { strHttp, strHttps, strWebDav }; - string[] vFtp = new string[] { strFtp }; - - List l = new List(); - - l.Add(new IocPropertyInfo(IocKnownProperties.Timeout, - typeof(long), KLRes.Timeout + " [ms]", vGen)); - l.Add(new IocPropertyInfo(IocKnownProperties.PreAuth, - typeof(bool), KLRes.PreAuth, vGen)); - - l.Add(new IocPropertyInfo(IocKnownProperties.UserAgent, - typeof(string), KLRes.UserAgent, vHttp)); - l.Add(new IocPropertyInfo(IocKnownProperties.Expect100Continue, - typeof(bool), KLRes.Expect100Continue, vHttp)); - - l.Add(new IocPropertyInfo(IocKnownProperties.Passive, - typeof(bool), KLRes.Passive, vFtp)); - - // l.Add(new IocPropertyInfo("Test", typeof(bool), - // "Long long long long long long long long long long long long long long long long long long long long", - // new string[] { "Proto 1/9", "Proto 2/9", "Proto 3/9", "Proto 4/9", "Proto 5/9", - // "Proto 6/9", "Proto 7/9", "Proto 8/9", "Proto 9/9" })); - - m_l = l; - } - - public static IocPropertyInfo Get(string strName) - { - if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return null; } - - EnsureInitialized(); - foreach(IocPropertyInfo pi in m_l) - { - if(pi.Name.Equals(strName, StrUtil.CaseIgnoreCmp)) - return pi; - } - - return null; - } - - public static bool Add(IocPropertyInfo pi) - { - if(pi == null) { Debug.Assert(false); return false; } - - // Name must be non-empty - string strName = pi.Name; - if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return false; } - - IocPropertyInfo piEx = Get(strName); // Ensures initialized - if(piEx != null) { Debug.Assert(false); return false; } // Exists already - - m_l.Add(pi); - return true; - } - } -} diff --git a/ModernKeePassLib/Serialization/KdbxFile.Read.Streamed.cs b/ModernKeePassLib/Serialization/KdbxFile.Read.Streamed.cs deleted file mode 100644 index 7966c79..0000000 --- a/ModernKeePassLib/Serialization/KdbxFile.Read.Streamed.cs +++ /dev/null @@ -1,1077 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; -using System.Xml; - -#if !ModernKeePassLib && !KeePassUAP -using System.Drawing; -#endif - -using ModernKeePassLib; -using ModernKeePassLib.Collections; -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Cryptography.Cipher; -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Resources; -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Serialization -{ - /// - /// Serialization to KeePass KDBX files. - /// - public sealed partial class KdbxFile - { - private enum KdbContext - { - Null, - KeePassFile, - Meta, - Root, - MemoryProtection, - CustomIcons, - CustomIcon, - Binaries, - CustomData, - CustomDataItem, - RootDeletedObjects, - DeletedObject, - Group, - GroupTimes, - GroupCustomData, - GroupCustomDataItem, - Entry, - EntryTimes, - EntryString, - EntryBinary, - EntryAutoType, - EntryAutoTypeItem, - EntryHistory, - EntryCustomData, - EntryCustomDataItem - } - - private bool m_bReadNextNode = true; - private Stack m_ctxGroups = new Stack(); - private PwGroup m_ctxGroup = null; - private PwEntry m_ctxEntry = null; - private string m_ctxStringName = null; - private ProtectedString m_ctxStringValue = null; - private string m_ctxBinaryName = null; - private ProtectedBinary m_ctxBinaryValue = null; - private string m_ctxATName = null; - private string m_ctxATSeq = null; - private bool m_bEntryInHistory = false; - private PwEntry m_ctxHistoryBase = null; - private PwDeletedObject m_ctxDeletedObject = null; - private PwUuid m_uuidCustomIconID = PwUuid.Zero; - private byte[] m_pbCustomIconData = null; - private string m_strCustomDataKey = null; - private string m_strCustomDataValue = null; - private string m_strGroupCustomDataKey = null; - private string m_strGroupCustomDataValue = null; - private string m_strEntryCustomDataKey = null; - private string m_strEntryCustomDataValue = null; - - private void ReadXmlStreamed(Stream sXml, Stream sParent) - { - ReadDocumentStreamed(CreateXmlReader(sXml), sParent); - } - - internal static XmlReaderSettings CreateStdXmlReaderSettings() - { - XmlReaderSettings xrs = new XmlReaderSettings(); - - xrs.CloseInput = true; - xrs.IgnoreComments = true; - xrs.IgnoreProcessingInstructions = true; - xrs.IgnoreWhitespace = true; - -#if ModernKeePassLib || KeePassUAP - xrs.DtdProcessing = DtdProcessing.Prohibit; -#else -#if !KeePassLibSD - // Also see PrepMonoDev.sh script - xrs.ProhibitDtd = true; // Obsolete in .NET 4, but still there - // xrs.DtdProcessing = DtdProcessing.Prohibit; // .NET 4 only -#endif - xrs.ValidationType = ValidationType.None; -#endif - - return xrs; - } - - private static XmlReader CreateXmlReader(Stream readerStream) - { - XmlReaderSettings xrs = CreateStdXmlReaderSettings(); - return XmlReader.Create(readerStream, xrs); - } - - private void ReadDocumentStreamed(XmlReader xr, Stream sParentStream) - { - Debug.Assert(xr != null); - if(xr == null) throw new ArgumentNullException("xr"); - - m_ctxGroups.Clear(); - - KdbContext ctx = KdbContext.Null; - - uint uTagCounter = 0; - - bool bSupportsStatus = (m_slLogger != null); - long lStreamLength = 1; - try - { - sParentStream.Position.ToString(); // Test Position support - lStreamLength = sParentStream.Length; - } - catch(Exception) { bSupportsStatus = false; } - if(lStreamLength <= 0) { Debug.Assert(false); lStreamLength = 1; } - - m_bReadNextNode = true; - - while(true) - { - if(m_bReadNextNode) - { - if(!xr.Read()) break; - } - else m_bReadNextNode = true; - - switch(xr.NodeType) - { - case XmlNodeType.Element: - ctx = ReadXmlElement(ctx, xr); - break; - - case XmlNodeType.EndElement: - ctx = EndXmlElement(ctx, xr); - break; - - case XmlNodeType.XmlDeclaration: - break; // Ignore - - default: - Debug.Assert(false); - break; - } - - ++uTagCounter; - if(((uTagCounter % 256) == 0) && bSupportsStatus) - { - Debug.Assert(lStreamLength == sParentStream.Length); - uint uPct = (uint)((sParentStream.Position * 100) / - lStreamLength); - - // Clip percent value in case the stream reports incorrect - // position/length values (M120413) - if(uPct > 100) { Debug.Assert(false); uPct = 100; } - - m_slLogger.SetProgress(uPct); - } - } - - Debug.Assert(ctx == KdbContext.Null); - if(ctx != KdbContext.Null) throw new FormatException(); - - Debug.Assert(m_ctxGroups.Count == 0); - if(m_ctxGroups.Count != 0) throw new FormatException(); - } - - private KdbContext ReadXmlElement(KdbContext ctx, XmlReader xr) - { - Debug.Assert(xr.NodeType == XmlNodeType.Element); - - switch(ctx) - { - case KdbContext.Null: - if(xr.Name == ElemDocNode) - return SwitchContext(ctx, KdbContext.KeePassFile, xr); - else ReadUnknown(xr); - break; - - case KdbContext.KeePassFile: - if(xr.Name == ElemMeta) - return SwitchContext(ctx, KdbContext.Meta, xr); - else if(xr.Name == ElemRoot) - return SwitchContext(ctx, KdbContext.Root, xr); - else ReadUnknown(xr); - break; - - case KdbContext.Meta: - if(xr.Name == ElemGenerator) - ReadString(xr); // Ignore - else if(xr.Name == ElemHeaderHash) - { - // The header hash is typically only stored in - // KDBX <= 3.1 files, not in KDBX >= 4 files - // (here, the header is verified via a HMAC), - // but we also support it for KDBX >= 4 files - // (i.e. if it's present, we check it) - - string strHash = ReadString(xr); - if(!string.IsNullOrEmpty(strHash) && (m_pbHashOfHeader != null) && - !m_bRepairMode) - { - Debug.Assert(m_uFileVersion < FileVersion32_4); - - byte[] pbHash = Convert.FromBase64String(strHash); - if(!MemUtil.ArraysEqual(pbHash, m_pbHashOfHeader)) - throw new InvalidDataException(KLRes.FileCorrupted); - } - } - else if(xr.Name == ElemSettingsChanged) - m_pwDatabase.SettingsChanged = ReadTime(xr); - else if(xr.Name == ElemDbName) - m_pwDatabase.Name = ReadString(xr); - else if(xr.Name == ElemDbNameChanged) - m_pwDatabase.NameChanged = ReadTime(xr); - else if(xr.Name == ElemDbDesc) - m_pwDatabase.Description = ReadString(xr); - else if(xr.Name == ElemDbDescChanged) - m_pwDatabase.DescriptionChanged = ReadTime(xr); - else if(xr.Name == ElemDbDefaultUser) - m_pwDatabase.DefaultUserName = ReadString(xr); - else if(xr.Name == ElemDbDefaultUserChanged) - m_pwDatabase.DefaultUserNameChanged = ReadTime(xr); - else if(xr.Name == ElemDbMntncHistoryDays) - m_pwDatabase.MaintenanceHistoryDays = ReadUInt(xr, 365); - else if(xr.Name == ElemDbColor) - { - string strColor = ReadString(xr); - if(!string.IsNullOrEmpty(strColor)) - m_pwDatabase.Color = ColorTranslator.FromHtml(strColor); - } - else if(xr.Name == ElemDbKeyChanged) - m_pwDatabase.MasterKeyChanged = ReadTime(xr); - else if(xr.Name == ElemDbKeyChangeRec) - m_pwDatabase.MasterKeyChangeRec = ReadLong(xr, -1); - else if(xr.Name == ElemDbKeyChangeForce) - m_pwDatabase.MasterKeyChangeForce = ReadLong(xr, -1); - else if(xr.Name == ElemDbKeyChangeForceOnce) - m_pwDatabase.MasterKeyChangeForceOnce = ReadBool(xr, false); - else if(xr.Name == ElemMemoryProt) - return SwitchContext(ctx, KdbContext.MemoryProtection, xr); - else if(xr.Name == ElemCustomIcons) - return SwitchContext(ctx, KdbContext.CustomIcons, xr); - else if(xr.Name == ElemRecycleBinEnabled) - m_pwDatabase.RecycleBinEnabled = ReadBool(xr, true); - else if(xr.Name == ElemRecycleBinUuid) - m_pwDatabase.RecycleBinUuid = ReadUuid(xr); - else if(xr.Name == ElemRecycleBinChanged) - m_pwDatabase.RecycleBinChanged = ReadTime(xr); - else if(xr.Name == ElemEntryTemplatesGroup) - m_pwDatabase.EntryTemplatesGroup = ReadUuid(xr); - else if(xr.Name == ElemEntryTemplatesGroupChanged) - m_pwDatabase.EntryTemplatesGroupChanged = ReadTime(xr); - else if(xr.Name == ElemHistoryMaxItems) - m_pwDatabase.HistoryMaxItems = ReadInt(xr, -1); - else if(xr.Name == ElemHistoryMaxSize) - m_pwDatabase.HistoryMaxSize = ReadLong(xr, -1); - else if(xr.Name == ElemLastSelectedGroup) - m_pwDatabase.LastSelectedGroup = ReadUuid(xr); - else if(xr.Name == ElemLastTopVisibleGroup) - m_pwDatabase.LastTopVisibleGroup = ReadUuid(xr); - else if(xr.Name == ElemBinaries) - return SwitchContext(ctx, KdbContext.Binaries, xr); - else if(xr.Name == ElemCustomData) - return SwitchContext(ctx, KdbContext.CustomData, xr); - else ReadUnknown(xr); - break; - - case KdbContext.MemoryProtection: - if(xr.Name == ElemProtTitle) - m_pwDatabase.MemoryProtection.ProtectTitle = ReadBool(xr, false); - else if(xr.Name == ElemProtUserName) - m_pwDatabase.MemoryProtection.ProtectUserName = ReadBool(xr, false); - else if(xr.Name == ElemProtPassword) - m_pwDatabase.MemoryProtection.ProtectPassword = ReadBool(xr, true); - else if(xr.Name == ElemProtUrl) - m_pwDatabase.MemoryProtection.ProtectUrl = ReadBool(xr, false); - else if(xr.Name == ElemProtNotes) - m_pwDatabase.MemoryProtection.ProtectNotes = ReadBool(xr, false); - // else if(xr.Name == ElemProtAutoHide) - // m_pwDatabase.MemoryProtection.AutoEnableVisualHiding = ReadBool(xr, true); - else ReadUnknown(xr); - break; - - case KdbContext.CustomIcons: - if(xr.Name == ElemCustomIconItem) - return SwitchContext(ctx, KdbContext.CustomIcon, xr); - else ReadUnknown(xr); - break; - - case KdbContext.CustomIcon: - if(xr.Name == ElemCustomIconItemID) - m_uuidCustomIconID = ReadUuid(xr); - else if(xr.Name == ElemCustomIconItemData) - { - string strData = ReadString(xr); - if(!string.IsNullOrEmpty(strData)) - m_pbCustomIconData = Convert.FromBase64String(strData); - else { Debug.Assert(false); } - } - else ReadUnknown(xr); - break; - - case KdbContext.Binaries: - if(xr.Name == ElemBinary) - { - if(xr.MoveToAttribute(AttrId)) - { - string strKey = xr.Value; - ProtectedBinary pbData = ReadProtectedBinary(xr); - - int iKey; - if(!StrUtil.TryParseIntInvariant(strKey, out iKey)) - throw new FormatException(); - if(iKey < 0) throw new FormatException(); - - Debug.Assert(m_pbsBinaries.Get(iKey) == null); - Debug.Assert(m_pbsBinaries.Find(pbData) < 0); - m_pbsBinaries.Set(iKey, pbData); - } - else ReadUnknown(xr); - } - else ReadUnknown(xr); - break; - - case KdbContext.CustomData: - if(xr.Name == ElemStringDictExItem) - return SwitchContext(ctx, KdbContext.CustomDataItem, xr); - else ReadUnknown(xr); - break; - - case KdbContext.CustomDataItem: - if(xr.Name == ElemKey) - m_strCustomDataKey = ReadString(xr); - else if(xr.Name == ElemValue) - m_strCustomDataValue = ReadString(xr); - else ReadUnknown(xr); - break; - - case KdbContext.Root: - if(xr.Name == ElemGroup) - { - Debug.Assert(m_ctxGroups.Count == 0); - if(m_ctxGroups.Count != 0) throw new FormatException(); - - m_pwDatabase.RootGroup = new PwGroup(false, false); - m_ctxGroups.Push(m_pwDatabase.RootGroup); - m_ctxGroup = m_ctxGroups.Peek(); - - return SwitchContext(ctx, KdbContext.Group, xr); - } - else if(xr.Name == ElemDeletedObjects) - return SwitchContext(ctx, KdbContext.RootDeletedObjects, xr); - else ReadUnknown(xr); - break; - - case KdbContext.Group: - if(xr.Name == ElemUuid) - m_ctxGroup.Uuid = ReadUuid(xr); - else if(xr.Name == ElemName) - m_ctxGroup.Name = ReadString(xr); - else if(xr.Name == ElemNotes) - m_ctxGroup.Notes = ReadString(xr); - else if(xr.Name == ElemIcon) - m_ctxGroup.IconId = ReadIconId(xr, PwIcon.Folder); - else if(xr.Name == ElemCustomIconID) - m_ctxGroup.CustomIconUuid = ReadUuid(xr); - else if(xr.Name == ElemTimes) - return SwitchContext(ctx, KdbContext.GroupTimes, xr); - else if(xr.Name == ElemIsExpanded) - m_ctxGroup.IsExpanded = ReadBool(xr, true); - else if(xr.Name == ElemGroupDefaultAutoTypeSeq) - m_ctxGroup.DefaultAutoTypeSequence = ReadString(xr); - else if(xr.Name == ElemEnableAutoType) - m_ctxGroup.EnableAutoType = StrUtil.StringToBoolEx(ReadString(xr)); - else if(xr.Name == ElemEnableSearching) - m_ctxGroup.EnableSearching = StrUtil.StringToBoolEx(ReadString(xr)); - else if(xr.Name == ElemLastTopVisibleEntry) - m_ctxGroup.LastTopVisibleEntry = ReadUuid(xr); - else if(xr.Name == ElemCustomData) - return SwitchContext(ctx, KdbContext.GroupCustomData, xr); - else if(xr.Name == ElemGroup) - { - m_ctxGroup = new PwGroup(false, false); - m_ctxGroups.Peek().AddGroup(m_ctxGroup, true); - - m_ctxGroups.Push(m_ctxGroup); - - return SwitchContext(ctx, KdbContext.Group, xr); - } - else if(xr.Name == ElemEntry) - { - m_ctxEntry = new PwEntry(false, false); - m_ctxGroup.AddEntry(m_ctxEntry, true); - - m_bEntryInHistory = false; - return SwitchContext(ctx, KdbContext.Entry, xr); - } - else ReadUnknown(xr); - break; - - case KdbContext.GroupCustomData: - if(xr.Name == ElemStringDictExItem) - return SwitchContext(ctx, KdbContext.GroupCustomDataItem, xr); - else ReadUnknown(xr); - break; - - case KdbContext.GroupCustomDataItem: - if(xr.Name == ElemKey) - m_strGroupCustomDataKey = ReadString(xr); - else if(xr.Name == ElemValue) - m_strGroupCustomDataValue = ReadString(xr); - else ReadUnknown(xr); - break; - - case KdbContext.Entry: - if(xr.Name == ElemUuid) - m_ctxEntry.Uuid = ReadUuid(xr); - else if(xr.Name == ElemIcon) - m_ctxEntry.IconId = ReadIconId(xr, PwIcon.Key); - else if(xr.Name == ElemCustomIconID) - m_ctxEntry.CustomIconUuid = ReadUuid(xr); - else if(xr.Name == ElemFgColor) - { - string strColor = ReadString(xr); - if(!string.IsNullOrEmpty(strColor)) - m_ctxEntry.ForegroundColor = ColorTranslator.FromHtml(strColor); - } - else if(xr.Name == ElemBgColor) - { - string strColor = ReadString(xr); - if(!string.IsNullOrEmpty(strColor)) - m_ctxEntry.BackgroundColor = ColorTranslator.FromHtml(strColor); - } - else if(xr.Name == ElemOverrideUrl) - m_ctxEntry.OverrideUrl = ReadString(xr); - else if(xr.Name == ElemTags) - m_ctxEntry.Tags = StrUtil.StringToTags(ReadString(xr)); - else if(xr.Name == ElemTimes) - return SwitchContext(ctx, KdbContext.EntryTimes, xr); - else if(xr.Name == ElemString) - return SwitchContext(ctx, KdbContext.EntryString, xr); - else if(xr.Name == ElemBinary) - return SwitchContext(ctx, KdbContext.EntryBinary, xr); - else if(xr.Name == ElemAutoType) - return SwitchContext(ctx, KdbContext.EntryAutoType, xr); - else if(xr.Name == ElemCustomData) - return SwitchContext(ctx, KdbContext.EntryCustomData, xr); - else if(xr.Name == ElemHistory) - { - Debug.Assert(m_bEntryInHistory == false); - - if(m_bEntryInHistory == false) - { - m_ctxHistoryBase = m_ctxEntry; - return SwitchContext(ctx, KdbContext.EntryHistory, xr); - } - else ReadUnknown(xr); - } - else ReadUnknown(xr); - break; - - case KdbContext.GroupTimes: - case KdbContext.EntryTimes: - ITimeLogger tl = ((ctx == KdbContext.GroupTimes) ? - (ITimeLogger)m_ctxGroup : (ITimeLogger)m_ctxEntry); - Debug.Assert(tl != null); - - if(xr.Name == ElemCreationTime) - tl.CreationTime = ReadTime(xr); - else if(xr.Name == ElemLastModTime) - tl.LastModificationTime = ReadTime(xr); - else if(xr.Name == ElemLastAccessTime) - tl.LastAccessTime = ReadTime(xr); - else if(xr.Name == ElemExpiryTime) - tl.ExpiryTime = ReadTime(xr); - else if(xr.Name == ElemExpires) - tl.Expires = ReadBool(xr, false); - else if(xr.Name == ElemUsageCount) - tl.UsageCount = ReadULong(xr, 0); - else if(xr.Name == ElemLocationChanged) - tl.LocationChanged = ReadTime(xr); - else ReadUnknown(xr); - break; - - case KdbContext.EntryString: - if(xr.Name == ElemKey) - m_ctxStringName = ReadString(xr); - else if(xr.Name == ElemValue) - m_ctxStringValue = ReadProtectedString(xr); - else ReadUnknown(xr); - break; - - case KdbContext.EntryBinary: - if(xr.Name == ElemKey) - m_ctxBinaryName = ReadString(xr); - else if(xr.Name == ElemValue) - m_ctxBinaryValue = ReadProtectedBinary(xr); - else ReadUnknown(xr); - break; - - case KdbContext.EntryAutoType: - if(xr.Name == ElemAutoTypeEnabled) - m_ctxEntry.AutoType.Enabled = ReadBool(xr, true); - else if(xr.Name == ElemAutoTypeObfuscation) - m_ctxEntry.AutoType.ObfuscationOptions = - (AutoTypeObfuscationOptions)ReadInt(xr, 0); - else if(xr.Name == ElemAutoTypeDefaultSeq) - m_ctxEntry.AutoType.DefaultSequence = ReadString(xr); - else if(xr.Name == ElemAutoTypeItem) - return SwitchContext(ctx, KdbContext.EntryAutoTypeItem, xr); - else ReadUnknown(xr); - break; - - case KdbContext.EntryAutoTypeItem: - if(xr.Name == ElemWindow) - m_ctxATName = ReadString(xr); - else if(xr.Name == ElemKeystrokeSequence) - m_ctxATSeq = ReadString(xr); - else ReadUnknown(xr); - break; - - case KdbContext.EntryCustomData: - if(xr.Name == ElemStringDictExItem) - return SwitchContext(ctx, KdbContext.EntryCustomDataItem, xr); - else ReadUnknown(xr); - break; - - case KdbContext.EntryCustomDataItem: - if(xr.Name == ElemKey) - m_strEntryCustomDataKey = ReadString(xr); - else if(xr.Name == ElemValue) - m_strEntryCustomDataValue = ReadString(xr); - else ReadUnknown(xr); - break; - - case KdbContext.EntryHistory: - if(xr.Name == ElemEntry) - { - m_ctxEntry = new PwEntry(false, false); - m_ctxHistoryBase.History.Add(m_ctxEntry); - - m_bEntryInHistory = true; - return SwitchContext(ctx, KdbContext.Entry, xr); - } - else ReadUnknown(xr); - break; - - case KdbContext.RootDeletedObjects: - if(xr.Name == ElemDeletedObject) - { - m_ctxDeletedObject = new PwDeletedObject(); - m_pwDatabase.DeletedObjects.Add(m_ctxDeletedObject); - - return SwitchContext(ctx, KdbContext.DeletedObject, xr); - } - else ReadUnknown(xr); - break; - - case KdbContext.DeletedObject: - if(xr.Name == ElemUuid) - m_ctxDeletedObject.Uuid = ReadUuid(xr); - else if(xr.Name == ElemDeletionTime) - m_ctxDeletedObject.DeletionTime = ReadTime(xr); - else ReadUnknown(xr); - break; - - default: - ReadUnknown(xr); - break; - } - - return ctx; - } - - private KdbContext EndXmlElement(KdbContext ctx, XmlReader xr) - { - Debug.Assert(xr.NodeType == XmlNodeType.EndElement); - - if((ctx == KdbContext.KeePassFile) && (xr.Name == ElemDocNode)) - return KdbContext.Null; - else if((ctx == KdbContext.Meta) && (xr.Name == ElemMeta)) - return KdbContext.KeePassFile; - else if((ctx == KdbContext.Root) && (xr.Name == ElemRoot)) - return KdbContext.KeePassFile; - else if((ctx == KdbContext.MemoryProtection) && (xr.Name == ElemMemoryProt)) - return KdbContext.Meta; - else if((ctx == KdbContext.CustomIcons) && (xr.Name == ElemCustomIcons)) - return KdbContext.Meta; - else if((ctx == KdbContext.CustomIcon) && (xr.Name == ElemCustomIconItem)) - { - if(!m_uuidCustomIconID.Equals(PwUuid.Zero) && - (m_pbCustomIconData != null)) - m_pwDatabase.CustomIcons.Add(new PwCustomIcon( - m_uuidCustomIconID, m_pbCustomIconData)); - else { Debug.Assert(false); } - - m_uuidCustomIconID = PwUuid.Zero; - m_pbCustomIconData = null; - - return KdbContext.CustomIcons; - } - else if((ctx == KdbContext.Binaries) && (xr.Name == ElemBinaries)) - return KdbContext.Meta; - else if((ctx == KdbContext.CustomData) && (xr.Name == ElemCustomData)) - return KdbContext.Meta; - else if((ctx == KdbContext.CustomDataItem) && (xr.Name == ElemStringDictExItem)) - { - if((m_strCustomDataKey != null) && (m_strCustomDataValue != null)) - m_pwDatabase.CustomData.Set(m_strCustomDataKey, m_strCustomDataValue); - else { Debug.Assert(false); } - - m_strCustomDataKey = null; - m_strCustomDataValue = null; - - return KdbContext.CustomData; - } - else if((ctx == KdbContext.Group) && (xr.Name == ElemGroup)) - { - if(PwUuid.Zero.Equals(m_ctxGroup.Uuid)) - m_ctxGroup.Uuid = new PwUuid(true); // No assert (import) - - m_ctxGroups.Pop(); - - if(m_ctxGroups.Count == 0) - { - m_ctxGroup = null; - return KdbContext.Root; - } - else - { - m_ctxGroup = m_ctxGroups.Peek(); - return KdbContext.Group; - } - } - else if((ctx == KdbContext.GroupTimes) && (xr.Name == ElemTimes)) - return KdbContext.Group; - else if((ctx == KdbContext.GroupCustomData) && (xr.Name == ElemCustomData)) - return KdbContext.Group; - else if((ctx == KdbContext.GroupCustomDataItem) && (xr.Name == ElemStringDictExItem)) - { - if((m_strGroupCustomDataKey != null) && (m_strGroupCustomDataValue != null)) - m_ctxGroup.CustomData.Set(m_strGroupCustomDataKey, m_strGroupCustomDataValue); - else { Debug.Assert(false); } - - m_strGroupCustomDataKey = null; - m_strGroupCustomDataValue = null; - - return KdbContext.GroupCustomData; - } - else if((ctx == KdbContext.Entry) && (xr.Name == ElemEntry)) - { - // Create new UUID if absent - if(PwUuid.Zero.Equals(m_ctxEntry.Uuid)) - m_ctxEntry.Uuid = new PwUuid(true); // No assert (import) - - if(m_bEntryInHistory) - { - m_ctxEntry = m_ctxHistoryBase; - return KdbContext.EntryHistory; - } - - return KdbContext.Group; - } - else if((ctx == KdbContext.EntryTimes) && (xr.Name == ElemTimes)) - return KdbContext.Entry; - else if((ctx == KdbContext.EntryString) && (xr.Name == ElemString)) - { - m_ctxEntry.Strings.Set(m_ctxStringName, m_ctxStringValue); - m_ctxStringName = null; - m_ctxStringValue = null; - return KdbContext.Entry; - } - else if((ctx == KdbContext.EntryBinary) && (xr.Name == ElemBinary)) - { - if(string.IsNullOrEmpty(m_strDetachBins)) - m_ctxEntry.Binaries.Set(m_ctxBinaryName, m_ctxBinaryValue); - else - { - SaveBinary(m_ctxBinaryName, m_ctxBinaryValue, m_strDetachBins); - - m_ctxBinaryValue = null; - GC.Collect(); - } - - m_ctxBinaryName = null; - m_ctxBinaryValue = null; - return KdbContext.Entry; - } - else if((ctx == KdbContext.EntryAutoType) && (xr.Name == ElemAutoType)) - return KdbContext.Entry; - else if((ctx == KdbContext.EntryAutoTypeItem) && (xr.Name == ElemAutoTypeItem)) - { - AutoTypeAssociation atAssoc = new AutoTypeAssociation(m_ctxATName, - m_ctxATSeq); - m_ctxEntry.AutoType.Add(atAssoc); - m_ctxATName = null; - m_ctxATSeq = null; - return KdbContext.EntryAutoType; - } - else if((ctx == KdbContext.EntryCustomData) && (xr.Name == ElemCustomData)) - return KdbContext.Entry; - else if((ctx == KdbContext.EntryCustomDataItem) && (xr.Name == ElemStringDictExItem)) - { - if((m_strEntryCustomDataKey != null) && (m_strEntryCustomDataValue != null)) - m_ctxEntry.CustomData.Set(m_strEntryCustomDataKey, m_strEntryCustomDataValue); - else { Debug.Assert(false); } - - m_strEntryCustomDataKey = null; - m_strEntryCustomDataValue = null; - - return KdbContext.EntryCustomData; - } - else if((ctx == KdbContext.EntryHistory) && (xr.Name == ElemHistory)) - { - m_bEntryInHistory = false; - return KdbContext.Entry; - } - else if((ctx == KdbContext.RootDeletedObjects) && (xr.Name == ElemDeletedObjects)) - return KdbContext.Root; - else if((ctx == KdbContext.DeletedObject) && (xr.Name == ElemDeletedObject)) - { - m_ctxDeletedObject = null; - return KdbContext.RootDeletedObjects; - } - else - { - Debug.Assert(false); - throw new FormatException(); - } - } - - private string ReadString(XmlReader xr) - { - XorredBuffer xb = ProcessNode(xr); - if(xb != null) - { - byte[] pb = xb.ReadPlainText(); - if(pb.Length == 0) return string.Empty; - return StrUtil.Utf8.GetString(pb, 0, pb.Length); - } - - m_bReadNextNode = false; // ReadElementString skips end tag -#if ModernKeePassLib - return xr.ReadElementContentAsString(); -#else - return xr.ReadElementString(); -#endif - } - - private string ReadStringRaw(XmlReader xr) - { - m_bReadNextNode = false; // ReadElementString skips end tag -#if ModernKeePassLib - return xr.ReadElementContentAsString(); -#else - return xr.ReadElementString(); -#endif - } - - private byte[] ReadBase64(XmlReader xr, bool bRaw) - { - // if(bRaw) return ReadBase64RawInChunks(xr); - - string str = (bRaw ? ReadStringRaw(xr) : ReadString(xr)); - if(string.IsNullOrEmpty(str)) return MemUtil.EmptyByteArray; - - return Convert.FromBase64String(str); - } - - /* private byte[] m_pbBase64ReadBuf = new byte[1024 * 1024 * 3]; - private byte[] ReadBase64RawInChunks(XmlReader xr) - { - xr.MoveToContent(); - - List lParts = new List(); - byte[] pbBuf = m_pbBase64ReadBuf; - while(true) - { - int cb = xr.ReadElementContentAsBase64(pbBuf, 0, pbBuf.Length); - if(cb == 0) break; - - byte[] pb = new byte[cb]; - Array.Copy(pbBuf, 0, pb, 0, cb); - lParts.Add(pb); - - // No break when cb < pbBuf.Length, because ReadElementContentAsBase64 - // moves to the next XML node only when returning 0 - } - m_bReadNextNode = false; - - if(lParts.Count == 0) return MemUtil.EmptyByteArray; - if(lParts.Count == 1) return lParts[0]; - - long cbRes = 0; - for(int i = 0; i < lParts.Count; ++i) - cbRes += lParts[i].Length; - - byte[] pbRes = new byte[cbRes]; - int cbCur = 0; - for(int i = 0; i < lParts.Count; ++i) - { - Array.Copy(lParts[i], 0, pbRes, cbCur, lParts[i].Length); - cbCur += lParts[i].Length; - } - - return pbRes; - } */ - - private bool ReadBool(XmlReader xr, bool bDefault) - { - string str = ReadString(xr); - if(str == ValTrue) return true; - else if(str == ValFalse) return false; - - Debug.Assert(false); - return bDefault; - } - - private PwUuid ReadUuid(XmlReader xr) - { - byte[] pb = ReadBase64(xr, false); - if(pb.Length == 0) return PwUuid.Zero; - return new PwUuid(pb); - } - - private int ReadInt(XmlReader xr, int nDefault) - { - string str = ReadString(xr); - - int n; - if(StrUtil.TryParseIntInvariant(str, out n)) return n; - - // Backward compatibility - if(StrUtil.TryParseInt(str, out n)) return n; - - Debug.Assert(false); - return nDefault; - } - - private uint ReadUInt(XmlReader xr, uint uDefault) - { - string str = ReadString(xr); - - uint u; - if(StrUtil.TryParseUIntInvariant(str, out u)) return u; - - // Backward compatibility - if(StrUtil.TryParseUInt(str, out u)) return u; - - Debug.Assert(false); - return uDefault; - } - - private long ReadLong(XmlReader xr, long lDefault) - { - string str = ReadString(xr); - - long l; - if(StrUtil.TryParseLongInvariant(str, out l)) return l; - - // Backward compatibility - if(StrUtil.TryParseLong(str, out l)) return l; - - Debug.Assert(false); - return lDefault; - } - - private ulong ReadULong(XmlReader xr, ulong uDefault) - { - string str = ReadString(xr); - - ulong u; - if(StrUtil.TryParseULongInvariant(str, out u)) return u; - - // Backward compatibility - if(StrUtil.TryParseULong(str, out u)) return u; - - Debug.Assert(false); - return uDefault; - } - - private DateTime ReadTime(XmlReader xr) - { - // Cf. WriteObject(string, DateTime) - if((m_format == KdbxFormat.Default) && (m_uFileVersion >= FileVersion32_4)) - { - // long l = ReadLong(xr, -1); - // if(l != -1) return DateTime.FromBinary(l); - - byte[] pb = ReadBase64(xr, false); - if(pb.Length != 8) - { - Debug.Assert(false); - byte[] pb8 = new byte[8]; - Array.Copy(pb, pb8, Math.Min(pb.Length, 8)); // Little-endian - pb = pb8; - } - long lSec = MemUtil.BytesToInt64(pb); - return new DateTime(lSec * TimeSpan.TicksPerSecond, DateTimeKind.Utc); - } - else - { - string str = ReadString(xr); - - DateTime dt; - if(TimeUtil.TryDeserializeUtc(str, out dt)) return dt; - } - - Debug.Assert(false); - return m_dtNow; - } - - private PwIcon ReadIconId(XmlReader xr, PwIcon icDefault) - { - int i = ReadInt(xr, (int)icDefault); - if((i >= 0) && (i < (int)PwIcon.Count)) return (PwIcon)i; - - Debug.Assert(false); - return icDefault; - } - - private ProtectedString ReadProtectedString(XmlReader xr) - { - XorredBuffer xb = ProcessNode(xr); - if(xb != null) return new ProtectedString(true, xb); - - bool bProtect = false; - if(m_format == KdbxFormat.PlainXml) - { - if(xr.MoveToAttribute(AttrProtectedInMemPlainXml)) - { - string strProtect = xr.Value; - bProtect = ((strProtect != null) && (strProtect == ValTrue)); - } - } - - ProtectedString ps = new ProtectedString(bProtect, ReadString(xr)); - return ps; - } - - private ProtectedBinary ReadProtectedBinary(XmlReader xr) - { - if(xr.MoveToAttribute(AttrRef)) - { - string strRef = xr.Value; - if(!string.IsNullOrEmpty(strRef)) - { - int iRef; - if(StrUtil.TryParseIntInvariant(strRef, out iRef)) - { - ProtectedBinary pb = m_pbsBinaries.Get(iRef); - if(pb != null) - { - // https://sourceforge.net/p/keepass/feature-requests/2023/ - xr.MoveToElement(); -#if DEBUG - string strInner = ReadStringRaw(xr); - Debug.Assert(string.IsNullOrEmpty(strInner)); -#else - ReadStringRaw(xr); -#endif - - return pb; - } - else { Debug.Assert(false); } - } - else { Debug.Assert(false); } - } - else { Debug.Assert(false); } - } - - bool bCompressed = false; - if(xr.MoveToAttribute(AttrCompressed)) - bCompressed = (xr.Value == ValTrue); - - XorredBuffer xb = ProcessNode(xr); - if(xb != null) - { - Debug.Assert(!bCompressed); // See SubWriteValue(ProtectedBinary value) - return new ProtectedBinary(true, xb); - } - - byte[] pbData = ReadBase64(xr, true); - if(pbData.Length == 0) return new ProtectedBinary(); - - if(bCompressed) pbData = MemUtil.Decompress(pbData); - return new ProtectedBinary(false, pbData); - } - - private void ReadUnknown(XmlReader xr) - { - Debug.Assert(false); // Unknown node! - - if(xr.IsEmptyElement) return; - - string strUnknownName = xr.Name; - ProcessNode(xr); - - while(xr.Read()) - { - if(xr.NodeType == XmlNodeType.EndElement) break; - if(xr.NodeType != XmlNodeType.Element) continue; - - ReadUnknown(xr); - } - - Debug.Assert(xr.Name == strUnknownName); - } - - private XorredBuffer ProcessNode(XmlReader xr) - { - // Debug.Assert(xr.NodeType == XmlNodeType.Element); - - XorredBuffer xb = null; - if(xr.HasAttributes) - { - if(xr.MoveToAttribute(AttrProtected)) - { - if(xr.Value == ValTrue) - { - xr.MoveToElement(); - - byte[] pbEncrypted = ReadBase64(xr, true); - byte[] pbPad = m_randomStream.GetRandomBytes((uint)pbEncrypted.Length); - - xb = new XorredBuffer(pbEncrypted, pbPad); - } - } - } - - return xb; - } - - private static KdbContext SwitchContext(KdbContext ctxCurrent, - KdbContext ctxNew, XmlReader xr) - { - if(xr.IsEmptyElement) return ctxCurrent; - return ctxNew; - } - } -} diff --git a/ModernKeePassLib/Serialization/KdbxFile.Read.cs b/ModernKeePassLib/Serialization/KdbxFile.Read.cs deleted file mode 100644 index 058977a..0000000 --- a/ModernKeePassLib/Serialization/KdbxFile.Read.cs +++ /dev/null @@ -1,592 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// #define KDBX_BENCHMARK - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Security; -using System.Text; -using System.Xml; - -#if !ModernKeePassLib && !KeePassUAP -using System.Security.Cryptography; -#endif - -#if !KeePassLibSD -using System.IO.Compression; -#else -using KeePassLibSD; -#endif - -using ModernKeePassLib.Collections; -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Cryptography.Cipher; -using ModernKeePassLib.Cryptography.KeyDerivation; -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Keys; -using ModernKeePassLib.Resources; -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Serialization -{ - /// - /// Serialization to KeePass KDBX files. - /// - public sealed partial class KdbxFile - { - /// - /// Load a KDBX file. - /// - /// File to load. - /// Format. - /// Status logger (optional). - public void Load(string strFilePath, KdbxFormat fmt, IStatusLogger slLogger) - { - IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFilePath); - Load(IOConnection.OpenRead(ioc), fmt, slLogger); - } - - /// - /// Load a KDBX file from a stream. - /// - /// Stream to read the data from. Must contain - /// a KDBX stream. - /// Format. - /// Status logger (optional). - public void Load(Stream sSource, KdbxFormat fmt, IStatusLogger slLogger) - { - Debug.Assert(sSource != null); - if(sSource == null) throw new ArgumentNullException("sSource"); - - if(m_bUsedOnce) - throw new InvalidOperationException("Do not reuse KdbxFile objects!"); - m_bUsedOnce = true; - -#if KDBX_BENCHMARK - Stopwatch swTime = Stopwatch.StartNew(); -#endif - - m_format = fmt; - m_slLogger = slLogger; - - m_pbsBinaries.Clear(); - - UTF8Encoding encNoBom = StrUtil.Utf8; - byte[] pbCipherKey = null; - byte[] pbHmacKey64 = null; - - List lStreams = new List(); - lStreams.Add(sSource); - - HashingStreamEx sHashing = new HashingStreamEx(sSource, false, null); - lStreams.Add(sHashing); - - try - { - Stream sXml; - if(fmt == KdbxFormat.Default) - { - BinaryReaderEx br = new BinaryReaderEx(sHashing, - encNoBom, KLRes.FileCorrupted); - byte[] pbHeader = LoadHeader(br); - m_pbHashOfHeader = CryptoUtil.HashSha256(pbHeader); - - int cbEncKey, cbEncIV; - ICipherEngine iCipher = GetCipher(out cbEncKey, out cbEncIV); - - ComputeKeys(out pbCipherKey, cbEncKey, out pbHmacKey64); - - string strIncomplete = KLRes.FileHeaderCorrupted + " " + - KLRes.FileIncomplete; - - Stream sPlain; - if(m_uFileVersion < FileVersion32_4) - { - Stream sDecrypted = EncryptStream(sHashing, iCipher, - pbCipherKey, cbEncIV, false); - if((sDecrypted == null) || (sDecrypted == sHashing)) - throw new SecurityException(KLRes.CryptoStreamFailed); - lStreams.Add(sDecrypted); - - BinaryReaderEx brDecrypted = new BinaryReaderEx(sDecrypted, - encNoBom, strIncomplete); - byte[] pbStoredStartBytes = brDecrypted.ReadBytes(32); - - if((m_pbStreamStartBytes == null) || (m_pbStreamStartBytes.Length != 32)) - throw new EndOfStreamException(strIncomplete); - if(!MemUtil.ArraysEqual(pbStoredStartBytes, m_pbStreamStartBytes)) - throw new InvalidCompositeKeyException(); - - sPlain = new HashedBlockStream(sDecrypted, false, 0, !m_bRepairMode); - } - else // KDBX >= 4 - { - byte[] pbStoredHash = MemUtil.Read(sHashing, 32); - if((pbStoredHash == null) || (pbStoredHash.Length != 32)) - throw new EndOfStreamException(strIncomplete); - if(!MemUtil.ArraysEqual(m_pbHashOfHeader, pbStoredHash)) - throw new InvalidDataException(KLRes.FileHeaderCorrupted); - - byte[] pbHeaderHmac = ComputeHeaderHmac(pbHeader, pbHmacKey64); - byte[] pbStoredHmac = MemUtil.Read(sHashing, 32); - if((pbStoredHmac == null) || (pbStoredHmac.Length != 32)) - throw new EndOfStreamException(strIncomplete); - if(!MemUtil.ArraysEqual(pbHeaderHmac, pbStoredHmac)) - throw new InvalidCompositeKeyException(); - - HmacBlockStream sBlocks = new HmacBlockStream(sHashing, - false, !m_bRepairMode, pbHmacKey64); - lStreams.Add(sBlocks); - - sPlain = EncryptStream(sBlocks, iCipher, pbCipherKey, - cbEncIV, false); - if((sPlain == null) || (sPlain == sBlocks)) - throw new SecurityException(KLRes.CryptoStreamFailed); - } - lStreams.Add(sPlain); - - if(m_pwDatabase.Compression == PwCompressionAlgorithm.GZip) - { - sXml = new GZipStream(sPlain, CompressionMode.Decompress); - lStreams.Add(sXml); - } - else sXml = sPlain; - - if(m_uFileVersion >= FileVersion32_4) - LoadInnerHeader(sXml); // Binary header before XML - } - else if(fmt == KdbxFormat.PlainXml) - sXml = sHashing; - else { Debug.Assert(false); throw new ArgumentOutOfRangeException("fmt"); } - - if(fmt == KdbxFormat.Default) - { - if(m_pbInnerRandomStreamKey == null) - { - Debug.Assert(false); - throw new SecurityException("Invalid inner random stream key!"); - } - - m_randomStream = new CryptoRandomStream(m_craInnerRandomStream, - m_pbInnerRandomStreamKey); - } - -#if KeePassDebug_WriteXml - // FileStream fsOut = new FileStream("Raw.xml", FileMode.Create, - // FileAccess.Write, FileShare.None); - // try - // { - // while(true) - // { - // int b = sXml.ReadByte(); - // if(b == -1) break; - // fsOut.WriteByte((byte)b); - // } - // } - // catch(Exception) { } - // fsOut.Close(); -#endif - - ReadXmlStreamed(sXml, sHashing); - // ReadXmlDom(sXml); - } -#if !ModernKeePassLib - catch(CryptographicException) // Thrown on invalid padding - { - throw new CryptographicException(KLRes.FileCorrupted); - } -#endif - finally - { - if(pbCipherKey != null) MemUtil.ZeroByteArray(pbCipherKey); - if(pbHmacKey64 != null) MemUtil.ZeroByteArray(pbHmacKey64); - - CommonCleanUpRead(lStreams, sHashing); - } - -#if KDBX_BENCHMARK - swTime.Stop(); - MessageService.ShowInfo("Loading KDBX took " + - swTime.ElapsedMilliseconds.ToString() + " ms."); -#endif - } - - private void CommonCleanUpRead(List lStreams, HashingStreamEx sHashing) - { - CloseStreams(lStreams); - - Debug.Assert(lStreams.Contains(sHashing)); // sHashing must be closed - m_pbHashOfFileOnDisk = sHashing.Hash; - Debug.Assert(m_pbHashOfFileOnDisk != null); - - CleanUpInnerRandomStream(); - - // Reset memory protection settings (to always use reasonable - // defaults) - m_pwDatabase.MemoryProtection = new MemoryProtectionConfig(); - - // Remove old backups (this call is required here in order to apply - // the default history maintenance settings for people upgrading from - // KeePass <= 2.14 to >= 2.15; also it ensures history integrity in - // case a different application has created the KDBX file and ignored - // the history maintenance settings) - m_pwDatabase.MaintainBackups(); // Don't mark database as modified - - // Expand the root group, such that in case the user accidently - // collapses the root group he can simply reopen the database - PwGroup pgRoot = m_pwDatabase.RootGroup; - if(pgRoot != null) pgRoot.IsExpanded = true; - else { Debug.Assert(false); } - - m_pbHashOfHeader = null; - } - - private byte[] LoadHeader(BinaryReaderEx br) - { - string strPrevExcpText = br.ReadExceptionText; - br.ReadExceptionText = KLRes.FileHeaderCorrupted + " " + - KLRes.FileIncompleteExpc; - - MemoryStream msHeader = new MemoryStream(); - Debug.Assert(br.CopyDataTo == null); - br.CopyDataTo = msHeader; - - byte[] pbSig1 = br.ReadBytes(4); - uint uSig1 = MemUtil.BytesToUInt32(pbSig1); - byte[] pbSig2 = br.ReadBytes(4); - uint uSig2 = MemUtil.BytesToUInt32(pbSig2); - - if((uSig1 == FileSignatureOld1) && (uSig2 == FileSignatureOld2)) - throw new OldFormatException(PwDefs.ShortProductName + @" 1.x", - OldFormatException.OldFormatType.KeePass1x); - - if((uSig1 == FileSignature1) && (uSig2 == FileSignature2)) { } - else if((uSig1 == FileSignaturePreRelease1) && (uSig2 == - FileSignaturePreRelease2)) { } - else throw new FormatException(KLRes.FileSigInvalid); - - byte[] pb = br.ReadBytes(4); - uint uVersion = MemUtil.BytesToUInt32(pb); - if((uVersion & FileVersionCriticalMask) > (FileVersion32 & FileVersionCriticalMask)) - throw new FormatException(KLRes.FileVersionUnsupported + - Environment.NewLine + KLRes.FileNewVerReq); - m_uFileVersion = uVersion; - - while(true) - { - if(!ReadHeaderField(br)) break; - } - - br.CopyDataTo = null; - byte[] pbHeader = msHeader.ToArray(); - msHeader.Dispose(); - - br.ReadExceptionText = strPrevExcpText; - return pbHeader; - } - - private bool ReadHeaderField(BinaryReaderEx brSource) - { - Debug.Assert(brSource != null); - if(brSource == null) throw new ArgumentNullException("brSource"); - - byte btFieldID = brSource.ReadByte(); - - int cbSize; - Debug.Assert(m_uFileVersion > 0); - if(m_uFileVersion < FileVersion32_4) - cbSize = (int)MemUtil.BytesToUInt16(brSource.ReadBytes(2)); - else cbSize = MemUtil.BytesToInt32(brSource.ReadBytes(4)); - if(cbSize < 0) throw new FormatException(KLRes.FileCorrupted); - - byte[] pbData = MemUtil.EmptyByteArray; - if(cbSize > 0) pbData = brSource.ReadBytes(cbSize); - - bool bResult = true; - KdbxHeaderFieldID kdbID = (KdbxHeaderFieldID)btFieldID; - switch(kdbID) - { - case KdbxHeaderFieldID.EndOfHeader: - bResult = false; // Returning false indicates end of header - break; - - case KdbxHeaderFieldID.CipherID: - SetCipher(pbData); - break; - - case KdbxHeaderFieldID.CompressionFlags: - SetCompressionFlags(pbData); - break; - - case KdbxHeaderFieldID.MasterSeed: - m_pbMasterSeed = pbData; - CryptoRandom.Instance.AddEntropy(pbData); - break; - - // Obsolete; for backward compatibility only - case KdbxHeaderFieldID.TransformSeed: - Debug.Assert(m_uFileVersion < FileVersion32_4); - - AesKdf kdfS = new AesKdf(); - if(!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfS.Uuid)) - m_pwDatabase.KdfParameters = kdfS.GetDefaultParameters(); - - // m_pbTransformSeed = pbData; - m_pwDatabase.KdfParameters.SetByteArray(AesKdf.ParamSeed, pbData); - - CryptoRandom.Instance.AddEntropy(pbData); - break; - - // Obsolete; for backward compatibility only - case KdbxHeaderFieldID.TransformRounds: - Debug.Assert(m_uFileVersion < FileVersion32_4); - - AesKdf kdfR = new AesKdf(); - if(!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfR.Uuid)) - m_pwDatabase.KdfParameters = kdfR.GetDefaultParameters(); - - // m_pwDatabase.KeyEncryptionRounds = MemUtil.BytesToUInt64(pbData); - m_pwDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, - MemUtil.BytesToUInt64(pbData)); - break; - - case KdbxHeaderFieldID.EncryptionIV: - m_pbEncryptionIV = pbData; - break; - - case KdbxHeaderFieldID.InnerRandomStreamKey: - Debug.Assert(m_uFileVersion < FileVersion32_4); - Debug.Assert(m_pbInnerRandomStreamKey == null); - m_pbInnerRandomStreamKey = pbData; - CryptoRandom.Instance.AddEntropy(pbData); - break; - - case KdbxHeaderFieldID.StreamStartBytes: - Debug.Assert(m_uFileVersion < FileVersion32_4); - m_pbStreamStartBytes = pbData; - break; - - case KdbxHeaderFieldID.InnerRandomStreamID: - Debug.Assert(m_uFileVersion < FileVersion32_4); - SetInnerRandomStreamID(pbData); - break; - - case KdbxHeaderFieldID.KdfParameters: - m_pwDatabase.KdfParameters = KdfParameters.DeserializeExt(pbData); - break; - - case KdbxHeaderFieldID.PublicCustomData: - Debug.Assert(m_pwDatabase.PublicCustomData.Count == 0); - m_pwDatabase.PublicCustomData = VariantDictionary.Deserialize(pbData); - break; - - default: - Debug.Assert(false); - if(m_slLogger != null) - m_slLogger.SetText(KLRes.UnknownHeaderId + @": " + - kdbID.ToString() + "!", LogStatusType.Warning); - break; - } - - return bResult; - } - - private void LoadInnerHeader(Stream s) - { - BinaryReaderEx br = new BinaryReaderEx(s, StrUtil.Utf8, - KLRes.FileCorrupted + " " + KLRes.FileIncompleteExpc); - - while(true) - { - if(!ReadInnerHeaderField(br)) break; - } - } - - private bool ReadInnerHeaderField(BinaryReaderEx br) - { - Debug.Assert(br != null); - if(br == null) throw new ArgumentNullException("br"); - - byte btFieldID = br.ReadByte(); - - int cbSize = MemUtil.BytesToInt32(br.ReadBytes(4)); - if(cbSize < 0) throw new FormatException(KLRes.FileCorrupted); - - byte[] pbData = MemUtil.EmptyByteArray; - if(cbSize > 0) pbData = br.ReadBytes(cbSize); - - bool bResult = true; - KdbxInnerHeaderFieldID kdbID = (KdbxInnerHeaderFieldID)btFieldID; - switch(kdbID) - { - case KdbxInnerHeaderFieldID.EndOfHeader: - bResult = false; // Returning false indicates end of header - break; - - case KdbxInnerHeaderFieldID.InnerRandomStreamID: - SetInnerRandomStreamID(pbData); - break; - - case KdbxInnerHeaderFieldID.InnerRandomStreamKey: - Debug.Assert(m_pbInnerRandomStreamKey == null); - m_pbInnerRandomStreamKey = pbData; - CryptoRandom.Instance.AddEntropy(pbData); - break; - - case KdbxInnerHeaderFieldID.Binary: - if(pbData.Length < 1) throw new FormatException(); - KdbxBinaryFlags f = (KdbxBinaryFlags)pbData[0]; - bool bProt = ((f & KdbxBinaryFlags.Protected) != KdbxBinaryFlags.None); - - ProtectedBinary pb = new ProtectedBinary(bProt, pbData, - 1, pbData.Length - 1); - m_pbsBinaries.Add(pb); - - if(bProt) MemUtil.ZeroByteArray(pbData); - break; - - default: - Debug.Assert(false); - break; - } - - return bResult; - } - - private void SetCipher(byte[] pbID) - { - if((pbID == null) || (pbID.Length != (int)PwUuid.UuidSize)) - throw new FormatException(KLRes.FileUnknownCipher); - - m_pwDatabase.DataCipherUuid = new PwUuid(pbID); - } - - private void SetCompressionFlags(byte[] pbFlags) - { - int nID = (int)MemUtil.BytesToUInt32(pbFlags); - if((nID < 0) || (nID >= (int)PwCompressionAlgorithm.Count)) - throw new FormatException(KLRes.FileUnknownCompression); - - m_pwDatabase.Compression = (PwCompressionAlgorithm)nID; - } - - private void SetInnerRandomStreamID(byte[] pbID) - { - uint uID = MemUtil.BytesToUInt32(pbID); - if(uID >= (uint)CrsAlgorithm.Count) - throw new FormatException(KLRes.FileUnknownCipher); - - m_craInnerRandomStream = (CrsAlgorithm)uID; - } - - [Obsolete] - public static List ReadEntries(Stream msData) - { - return ReadEntries(msData, null, false); - } - - [Obsolete] - public static List ReadEntries(PwDatabase pdContext, Stream msData) - { - return ReadEntries(msData, pdContext, true); - } - - /// - /// Read entries from a stream. - /// - /// Input stream to read the entries from. - /// Context database (e.g. for storing icons). - /// If true, custom icons required by - /// the loaded entries are copied to the context database. - /// Loaded entries. - public static List ReadEntries(Stream msData, PwDatabase pdContext, - bool bCopyIcons) - { - List lEntries = new List(); - - if(msData == null) { Debug.Assert(false); return lEntries; } - // pdContext may be null - - /* KdbxFile f = new KdbxFile(pwDatabase); - f.m_format = KdbxFormat.PlainXml; - - XmlDocument doc = XmlUtilEx.CreateXmlDocument(); - doc.Load(msData); - - XmlElement el = doc.DocumentElement; - if(el.Name != ElemRoot) throw new FormatException(); - - List vEntries = new List(); - - foreach(XmlNode xmlChild in el.ChildNodes) - { - if(xmlChild.Name == ElemEntry) - { - PwEntry pe = f.ReadEntry(xmlChild); - pe.Uuid = new PwUuid(true); - - foreach(PwEntry peHistory in pe.History) - peHistory.Uuid = pe.Uuid; - - vEntries.Add(pe); - } - else { Debug.Assert(false); } - } - - return vEntries; */ - - PwDatabase pd = new PwDatabase(); - pd.New(new IOConnectionInfo(), new CompositeKey()); - - KdbxFile f = new KdbxFile(pd); - f.Load(msData, KdbxFormat.PlainXml, null); - - foreach(PwEntry pe in pd.RootGroup.Entries) - { - pe.SetUuid(new PwUuid(true), true); - lEntries.Add(pe); - - if(bCopyIcons && (pdContext != null)) - { - PwUuid pu = pe.CustomIconUuid; - if(!pu.Equals(PwUuid.Zero)) - { - int iSrc = pd.GetCustomIconIndex(pu); - int iDst = pdContext.GetCustomIconIndex(pu); - - if(iSrc < 0) { Debug.Assert(false); } - else if(iDst < 0) - { - pdContext.CustomIcons.Add(pd.CustomIcons[iSrc]); - - pdContext.Modified = true; - pdContext.UINeedsIconUpdate = true; - } - } - } - } - - return lEntries; - } - } -} diff --git a/ModernKeePassLib/Serialization/KdbxFile.Write.cs b/ModernKeePassLib/Serialization/KdbxFile.Write.cs deleted file mode 100644 index 90ed336..0000000 --- a/ModernKeePassLib/Serialization/KdbxFile.Write.cs +++ /dev/null @@ -1,1051 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Security; -using System.Text; -using System.Xml; - -#if !ModernKeePassLib && !KeePassUAP -using System.Drawing; -using System.Security.Cryptography; -#endif - -#if KeePassLibSD -using KeePassLibSD; -#else -using System.IO.Compression; -#endif - -using ModernKeePassLib.Collections; -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Cryptography.Cipher; -using ModernKeePassLib.Cryptography.KeyDerivation; -using ModernKeePassLib.Delegates; -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Keys; -using ModernKeePassLib.Resources; -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Serialization -{ - /// - /// Serialization to KeePass KDBX files. - /// - public sealed partial class KdbxFile - { - // public void Save(string strFile, PwGroup pgDataSource, KdbxFormat fmt, - // IStatusLogger slLogger) - // { - // bool bMadeUnhidden = UrlUtil.UnhideFile(strFile); - // - // IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile); - // this.Save(IOConnection.OpenWrite(ioc), pgDataSource, format, slLogger); - // - // if(bMadeUnhidden) UrlUtil.HideFile(strFile, true); // Hide again - // } - - /// - /// Save the contents of the current PwDatabase to a KDBX file. - /// - /// Stream to write the KDBX file into. - /// Group containing all groups and - /// entries to write. If null, the complete database will - /// be written. - /// Format of the file to create. - /// Logger that recieves status information. - public void Save(Stream sSaveTo, PwGroup pgDataSource, KdbxFormat fmt, - IStatusLogger slLogger) - { - Debug.Assert(sSaveTo != null); - if(sSaveTo == null) throw new ArgumentNullException("sSaveTo"); - - if(m_bUsedOnce) - throw new InvalidOperationException("Do not reuse KdbxFile objects!"); - m_bUsedOnce = true; - - m_format = fmt; - m_slLogger = slLogger; - m_xmlWriter = null; - - PwGroup pgRoot = (pgDataSource ?? m_pwDatabase.RootGroup); - UTF8Encoding encNoBom = StrUtil.Utf8; - CryptoRandom cr = CryptoRandom.Instance; - byte[] pbCipherKey = null; - byte[] pbHmacKey64 = null; - - m_pbsBinaries.Clear(); - m_pbsBinaries.AddFrom(pgRoot); - - List lStreams = new List(); - lStreams.Add(sSaveTo); - - HashingStreamEx sHashing = new HashingStreamEx(sSaveTo, true, null); - lStreams.Add(sHashing); - - try - { - m_uFileVersion = GetMinKdbxVersion(); - - int cbEncKey, cbEncIV; - ICipherEngine iCipher = GetCipher(out cbEncKey, out cbEncIV); - - m_pbMasterSeed = cr.GetRandomBytes(32); - m_pbEncryptionIV = cr.GetRandomBytes((uint)cbEncIV); - - // m_pbTransformSeed = cr.GetRandomBytes(32); - PwUuid puKdf = m_pwDatabase.KdfParameters.KdfUuid; - KdfEngine kdf = KdfPool.Get(puKdf); - if(kdf == null) - throw new Exception(KLRes.UnknownKdf + Environment.NewLine + - // KLRes.FileNewVerOrPlgReq + Environment.NewLine + - "UUID: " + puKdf.ToHexString() + "."); - kdf.Randomize(m_pwDatabase.KdfParameters); - - if(m_format == KdbxFormat.Default) - { - if(m_uFileVersion < FileVersion32_4) - { - m_craInnerRandomStream = CrsAlgorithm.Salsa20; - m_pbInnerRandomStreamKey = cr.GetRandomBytes(32); - } - else // KDBX >= 4 - { - m_craInnerRandomStream = CrsAlgorithm.ChaCha20; - m_pbInnerRandomStreamKey = cr.GetRandomBytes(64); - } - - m_randomStream = new CryptoRandomStream(m_craInnerRandomStream, - m_pbInnerRandomStreamKey); - } - - if(m_uFileVersion < FileVersion32_4) - m_pbStreamStartBytes = cr.GetRandomBytes(32); - - Stream sXml; - if(m_format == KdbxFormat.Default) - { - byte[] pbHeader = GenerateHeader(); - m_pbHashOfHeader = CryptoUtil.HashSha256(pbHeader); - - MemUtil.Write(sHashing, pbHeader); - sHashing.Flush(); - - ComputeKeys(out pbCipherKey, cbEncKey, out pbHmacKey64); - - Stream sPlain; - if(m_uFileVersion < FileVersion32_4) - { - Stream sEncrypted = EncryptStream(sHashing, iCipher, - pbCipherKey, cbEncIV, true); - if((sEncrypted == null) || (sEncrypted == sHashing)) - throw new SecurityException(KLRes.CryptoStreamFailed); - lStreams.Add(sEncrypted); - - MemUtil.Write(sEncrypted, m_pbStreamStartBytes); - - sPlain = new HashedBlockStream(sEncrypted, true); - } - else // KDBX >= 4 - { - // For integrity checking (without knowing the master key) - MemUtil.Write(sHashing, m_pbHashOfHeader); - - byte[] pbHeaderHmac = ComputeHeaderHmac(pbHeader, pbHmacKey64); - MemUtil.Write(sHashing, pbHeaderHmac); - - Stream sBlocks = new HmacBlockStream(sHashing, true, - true, pbHmacKey64); - lStreams.Add(sBlocks); - - sPlain = EncryptStream(sBlocks, iCipher, pbCipherKey, - cbEncIV, true); - if((sPlain == null) || (sPlain == sBlocks)) - throw new SecurityException(KLRes.CryptoStreamFailed); - } - lStreams.Add(sPlain); - - if(m_pwDatabase.Compression == PwCompressionAlgorithm.GZip) - { - sXml = new GZipStream(sPlain, CompressionMode.Compress); - lStreams.Add(sXml); - } - else sXml = sPlain; - - if(m_uFileVersion >= FileVersion32_4) - WriteInnerHeader(sXml); // Binary header before XML - } - else if(m_format == KdbxFormat.PlainXml) - sXml = sHashing; - else - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("fmt"); - } - - m_xmlWriter = XmlUtilEx.CreateXmlWriter(sXml, m_uFileVersion >= FileVersion32_4); - - WriteDocument(pgRoot); - - m_xmlWriter.Flush(); - } - finally - { - CommonCleanUpWrite(lStreams, sHashing); - - if(pbCipherKey != null) MemUtil.ZeroByteArray(pbCipherKey); - if(pbHmacKey64 != null) MemUtil.ZeroByteArray(pbHmacKey64); - } - } - - private void CommonCleanUpWrite(List lStreams, HashingStreamEx sHashing) - { - if(m_xmlWriter != null) { m_xmlWriter.Dispose(); m_xmlWriter = null; } - - CloseStreams(lStreams); - - Debug.Assert(lStreams.Contains(sHashing)); // sHashing must be closed - m_pbHashOfFileOnDisk = sHashing.Hash; - Debug.Assert(m_pbHashOfFileOnDisk != null); - - CleanUpInnerRandomStream(); - - m_pbHashOfHeader = null; - } - - private byte[] GenerateHeader() - { - byte[] pbHeader; - using(MemoryStream ms = new MemoryStream()) - { - MemUtil.Write(ms, MemUtil.UInt32ToBytes(FileSignature1)); - MemUtil.Write(ms, MemUtil.UInt32ToBytes(FileSignature2)); - MemUtil.Write(ms, MemUtil.UInt32ToBytes(m_uFileVersion)); - - WriteHeaderField(ms, KdbxHeaderFieldID.CipherID, - m_pwDatabase.DataCipherUuid.UuidBytes); - - int nCprID = (int)m_pwDatabase.Compression; - WriteHeaderField(ms, KdbxHeaderFieldID.CompressionFlags, - MemUtil.UInt32ToBytes((uint)nCprID)); - - WriteHeaderField(ms, KdbxHeaderFieldID.MasterSeed, m_pbMasterSeed); - - if(m_uFileVersion < FileVersion32_4) - { - Debug.Assert(m_pwDatabase.KdfParameters.KdfUuid.Equals( - (new AesKdf()).Uuid)); - WriteHeaderField(ms, KdbxHeaderFieldID.TransformSeed, - m_pwDatabase.KdfParameters.GetByteArray(AesKdf.ParamSeed)); - WriteHeaderField(ms, KdbxHeaderFieldID.TransformRounds, - MemUtil.UInt64ToBytes(m_pwDatabase.KdfParameters.GetUInt64( - AesKdf.ParamRounds, PwDefs.DefaultKeyEncryptionRounds))); - } - else - WriteHeaderField(ms, KdbxHeaderFieldID.KdfParameters, - KdfParameters.SerializeExt(m_pwDatabase.KdfParameters)); - - if(m_pbEncryptionIV.Length > 0) - WriteHeaderField(ms, KdbxHeaderFieldID.EncryptionIV, m_pbEncryptionIV); - - if(m_uFileVersion < FileVersion32_4) - { - WriteHeaderField(ms, KdbxHeaderFieldID.InnerRandomStreamKey, - m_pbInnerRandomStreamKey); - - WriteHeaderField(ms, KdbxHeaderFieldID.StreamStartBytes, - m_pbStreamStartBytes); - - int nIrsID = (int)m_craInnerRandomStream; - WriteHeaderField(ms, KdbxHeaderFieldID.InnerRandomStreamID, - MemUtil.Int32ToBytes(nIrsID)); - } - - // Write public custom data only when there is at least one item, - // because KDBX 3.1 didn't support this field yet - if(m_pwDatabase.PublicCustomData.Count > 0) - WriteHeaderField(ms, KdbxHeaderFieldID.PublicCustomData, - VariantDictionary.Serialize(m_pwDatabase.PublicCustomData)); - - WriteHeaderField(ms, KdbxHeaderFieldID.EndOfHeader, new byte[] { - (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }); - - pbHeader = ms.ToArray(); - } - - return pbHeader; - } - - private void WriteHeaderField(Stream s, KdbxHeaderFieldID kdbID, - byte[] pbData) - { - s.WriteByte((byte)kdbID); - - byte[] pb = (pbData ?? MemUtil.EmptyByteArray); - int cb = pb.Length; - if(cb < 0) { Debug.Assert(false); throw new OutOfMemoryException(); } - - Debug.Assert(m_uFileVersion > 0); - if(m_uFileVersion < FileVersion32_4) - { - if(cb > (int)ushort.MaxValue) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("pbData"); - } - - MemUtil.Write(s, MemUtil.UInt16ToBytes((ushort)cb)); - } - else MemUtil.Write(s, MemUtil.Int32ToBytes(cb)); - - MemUtil.Write(s, pb); - } - - private void WriteInnerHeader(Stream s) - { - int nIrsID = (int)m_craInnerRandomStream; - WriteInnerHeaderField(s, KdbxInnerHeaderFieldID.InnerRandomStreamID, - MemUtil.Int32ToBytes(nIrsID), null); - - WriteInnerHeaderField(s, KdbxInnerHeaderFieldID.InnerRandomStreamKey, - m_pbInnerRandomStreamKey, null); - - ProtectedBinary[] vBin = m_pbsBinaries.ToArray(); - for(int i = 0; i < vBin.Length; ++i) - { - ProtectedBinary pb = vBin[i]; - if(pb == null) throw new InvalidOperationException(); - - KdbxBinaryFlags f = KdbxBinaryFlags.None; - if(pb.IsProtected) f |= KdbxBinaryFlags.Protected; - - byte[] pbFlags = new byte[1] { (byte)f }; - byte[] pbData = pb.ReadData(); - - WriteInnerHeaderField(s, KdbxInnerHeaderFieldID.Binary, - pbFlags, pbData); - - if(pb.IsProtected) MemUtil.ZeroByteArray(pbData); - } - - WriteInnerHeaderField(s, KdbxInnerHeaderFieldID.EndOfHeader, - null, null); - } - - private void WriteInnerHeaderField(Stream s, KdbxInnerHeaderFieldID kdbID, - byte[] pbData1, byte[] pbData2) - { - s.WriteByte((byte)kdbID); - - byte[] pb1 = (pbData1 ?? MemUtil.EmptyByteArray); - byte[] pb2 = (pbData2 ?? MemUtil.EmptyByteArray); - - int cb = pb1.Length + pb2.Length; - if(cb < 0) { Debug.Assert(false); throw new OutOfMemoryException(); } - - MemUtil.Write(s, MemUtil.Int32ToBytes(cb)); - MemUtil.Write(s, pb1); - MemUtil.Write(s, pb2); - } - - private void WriteDocument(PwGroup pgRoot) - { - Debug.Assert(m_xmlWriter != null); - if(m_xmlWriter == null) throw new InvalidOperationException(); - - uint uNumGroups, uNumEntries, uCurEntry = 0; - pgRoot.GetCounts(true, out uNumGroups, out uNumEntries); - - m_xmlWriter.WriteStartDocument(true); - m_xmlWriter.WriteStartElement(ElemDocNode); - - WriteMeta(); - - m_xmlWriter.WriteStartElement(ElemRoot); - StartGroup(pgRoot); - - Stack groupStack = new Stack(); - groupStack.Push(pgRoot); - - GroupHandler gh = delegate(PwGroup pg) - { - Debug.Assert(pg != null); - if(pg == null) throw new ArgumentNullException("pg"); - - while(true) - { - if(pg.ParentGroup == groupStack.Peek()) - { - groupStack.Push(pg); - StartGroup(pg); - break; - } - else - { - groupStack.Pop(); - if(groupStack.Count <= 0) return false; - - EndGroup(); - } - } - - return true; - }; - - EntryHandler eh = delegate(PwEntry pe) - { - Debug.Assert(pe != null); - WriteEntry(pe, false); - - ++uCurEntry; - if(m_slLogger != null) - if(!m_slLogger.SetProgress((100 * uCurEntry) / uNumEntries)) - return false; - - return true; - }; - - if(!pgRoot.TraverseTree(TraversalMethod.PreOrder, gh, eh)) - throw new InvalidOperationException(); - - while(groupStack.Count > 1) - { - m_xmlWriter.WriteEndElement(); - groupStack.Pop(); - } - - EndGroup(); - - WriteList(ElemDeletedObjects, m_pwDatabase.DeletedObjects); - m_xmlWriter.WriteEndElement(); // Root - - m_xmlWriter.WriteEndElement(); // ElemDocNode - m_xmlWriter.WriteEndDocument(); - } - - private void WriteMeta() - { - m_xmlWriter.WriteStartElement(ElemMeta); - - WriteObject(ElemGenerator, PwDatabase.LocalizedAppName, false); - - if((m_pbHashOfHeader != null) && (m_uFileVersion < FileVersion32_4)) - WriteObject(ElemHeaderHash, Convert.ToBase64String( - m_pbHashOfHeader), false); - - if(m_uFileVersion >= FileVersion32_4) - WriteObject(ElemSettingsChanged, m_pwDatabase.SettingsChanged); - - WriteObject(ElemDbName, m_pwDatabase.Name, true); - WriteObject(ElemDbNameChanged, m_pwDatabase.NameChanged); - WriteObject(ElemDbDesc, m_pwDatabase.Description, true); - WriteObject(ElemDbDescChanged, m_pwDatabase.DescriptionChanged); - WriteObject(ElemDbDefaultUser, m_pwDatabase.DefaultUserName, true); - WriteObject(ElemDbDefaultUserChanged, m_pwDatabase.DefaultUserNameChanged); - WriteObject(ElemDbMntncHistoryDays, m_pwDatabase.MaintenanceHistoryDays); - WriteObject(ElemDbColor, StrUtil.ColorToUnnamedHtml(m_pwDatabase.Color, true), false); - WriteObject(ElemDbKeyChanged, m_pwDatabase.MasterKeyChanged); - WriteObject(ElemDbKeyChangeRec, m_pwDatabase.MasterKeyChangeRec); - WriteObject(ElemDbKeyChangeForce, m_pwDatabase.MasterKeyChangeForce); - if(m_pwDatabase.MasterKeyChangeForceOnce) - WriteObject(ElemDbKeyChangeForceOnce, true); - - WriteList(ElemMemoryProt, m_pwDatabase.MemoryProtection); - - WriteCustomIconList(); - - WriteObject(ElemRecycleBinEnabled, m_pwDatabase.RecycleBinEnabled); - WriteObject(ElemRecycleBinUuid, m_pwDatabase.RecycleBinUuid); - WriteObject(ElemRecycleBinChanged, m_pwDatabase.RecycleBinChanged); - WriteObject(ElemEntryTemplatesGroup, m_pwDatabase.EntryTemplatesGroup); - WriteObject(ElemEntryTemplatesGroupChanged, m_pwDatabase.EntryTemplatesGroupChanged); - WriteObject(ElemHistoryMaxItems, m_pwDatabase.HistoryMaxItems); - WriteObject(ElemHistoryMaxSize, m_pwDatabase.HistoryMaxSize); - - WriteObject(ElemLastSelectedGroup, m_pwDatabase.LastSelectedGroup); - WriteObject(ElemLastTopVisibleGroup, m_pwDatabase.LastTopVisibleGroup); - - if((m_format != KdbxFormat.Default) || (m_uFileVersion < FileVersion32_4)) - WriteBinPool(); - - WriteList(ElemCustomData, m_pwDatabase.CustomData); - - m_xmlWriter.WriteEndElement(); - } - - private void StartGroup(PwGroup pg) - { - m_xmlWriter.WriteStartElement(ElemGroup); - WriteObject(ElemUuid, pg.Uuid); - WriteObject(ElemName, pg.Name, true); - WriteObject(ElemNotes, pg.Notes, true); - WriteObject(ElemIcon, (int)pg.IconId); - - if(!pg.CustomIconUuid.Equals(PwUuid.Zero)) - WriteObject(ElemCustomIconID, pg.CustomIconUuid); - - WriteList(ElemTimes, pg); - WriteObject(ElemIsExpanded, pg.IsExpanded); - WriteObject(ElemGroupDefaultAutoTypeSeq, pg.DefaultAutoTypeSequence, true); - WriteObject(ElemEnableAutoType, StrUtil.BoolToStringEx(pg.EnableAutoType), false); - WriteObject(ElemEnableSearching, StrUtil.BoolToStringEx(pg.EnableSearching), false); - WriteObject(ElemLastTopVisibleEntry, pg.LastTopVisibleEntry); - - if(pg.CustomData.Count > 0) - WriteList(ElemCustomData, pg.CustomData); - } - - private void EndGroup() - { - m_xmlWriter.WriteEndElement(); // Close group element - } - - private void WriteEntry(PwEntry pe, bool bIsHistory) - { - Debug.Assert(pe != null); if(pe == null) throw new ArgumentNullException("pe"); - - m_xmlWriter.WriteStartElement(ElemEntry); - - WriteObject(ElemUuid, pe.Uuid); - WriteObject(ElemIcon, (int)pe.IconId); - - if(!pe.CustomIconUuid.Equals(PwUuid.Zero)) - WriteObject(ElemCustomIconID, pe.CustomIconUuid); - - WriteObject(ElemFgColor, StrUtil.ColorToUnnamedHtml(pe.ForegroundColor, true), false); - WriteObject(ElemBgColor, StrUtil.ColorToUnnamedHtml(pe.BackgroundColor, true), false); - WriteObject(ElemOverrideUrl, pe.OverrideUrl, true); - WriteObject(ElemTags, StrUtil.TagsToString(pe.Tags, false), true); - - WriteList(ElemTimes, pe); - - WriteList(pe.Strings, true); - WriteList(pe.Binaries); - WriteList(ElemAutoType, pe.AutoType); - - if(pe.CustomData.Count > 0) - WriteList(ElemCustomData, pe.CustomData); - - if(!bIsHistory) WriteList(ElemHistory, pe.History, true); - else { Debug.Assert(pe.History.UCount == 0); } - - m_xmlWriter.WriteEndElement(); - } - - private void WriteList(ProtectedStringDictionary dictStrings, bool bEntryStrings) - { - Debug.Assert(dictStrings != null); - if(dictStrings == null) throw new ArgumentNullException("dictStrings"); - - foreach(KeyValuePair kvp in dictStrings) - WriteObject(kvp.Key, kvp.Value, bEntryStrings); - } - - private void WriteList(ProtectedBinaryDictionary dictBinaries) - { - Debug.Assert(dictBinaries != null); - if(dictBinaries == null) throw new ArgumentNullException("dictBinaries"); - - foreach(KeyValuePair kvp in dictBinaries) - WriteObject(kvp.Key, kvp.Value, true); - } - - private void WriteList(string name, AutoTypeConfig cfgAutoType) - { - Debug.Assert(name != null); - Debug.Assert(cfgAutoType != null); - if(cfgAutoType == null) throw new ArgumentNullException("cfgAutoType"); - - m_xmlWriter.WriteStartElement(name); - - WriteObject(ElemAutoTypeEnabled, cfgAutoType.Enabled); - WriteObject(ElemAutoTypeObfuscation, (int)cfgAutoType.ObfuscationOptions); - - if(cfgAutoType.DefaultSequence.Length > 0) - WriteObject(ElemAutoTypeDefaultSeq, cfgAutoType.DefaultSequence, true); - - foreach(AutoTypeAssociation a in cfgAutoType.Associations) - WriteObject(ElemAutoTypeItem, ElemWindow, ElemKeystrokeSequence, - new KeyValuePair(a.WindowName, a.Sequence)); - - m_xmlWriter.WriteEndElement(); - } - - private void WriteList(string name, ITimeLogger times) - { - Debug.Assert(name != null); - Debug.Assert(times != null); if(times == null) throw new ArgumentNullException("times"); - - m_xmlWriter.WriteStartElement(name); - - WriteObject(ElemCreationTime, times.CreationTime); - WriteObject(ElemLastModTime, times.LastModificationTime); - WriteObject(ElemLastAccessTime, times.LastAccessTime); - WriteObject(ElemExpiryTime, times.ExpiryTime); - WriteObject(ElemExpires, times.Expires); - WriteObject(ElemUsageCount, times.UsageCount); - WriteObject(ElemLocationChanged, times.LocationChanged); - - m_xmlWriter.WriteEndElement(); // Name - } - - private void WriteList(string name, PwObjectList value, bool bIsHistory) - { - Debug.Assert(name != null); - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - - m_xmlWriter.WriteStartElement(name); - - foreach(PwEntry pe in value) - WriteEntry(pe, bIsHistory); - - m_xmlWriter.WriteEndElement(); - } - - private void WriteList(string name, PwObjectList value) - { - Debug.Assert(name != null); - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - - m_xmlWriter.WriteStartElement(name); - - foreach(PwDeletedObject pdo in value) - WriteObject(ElemDeletedObject, pdo); - - m_xmlWriter.WriteEndElement(); - } - - private void WriteList(string name, MemoryProtectionConfig value) - { - Debug.Assert(name != null); - Debug.Assert(value != null); - - m_xmlWriter.WriteStartElement(name); - - WriteObject(ElemProtTitle, value.ProtectTitle); - WriteObject(ElemProtUserName, value.ProtectUserName); - WriteObject(ElemProtPassword, value.ProtectPassword); - WriteObject(ElemProtUrl, value.ProtectUrl); - WriteObject(ElemProtNotes, value.ProtectNotes); - // WriteObject(ElemProtAutoHide, value.AutoEnableVisualHiding); - - m_xmlWriter.WriteEndElement(); - } - - private void WriteList(string name, StringDictionaryEx value) - { - Debug.Assert(name != null); - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - - m_xmlWriter.WriteStartElement(name); - - foreach(KeyValuePair kvp in value) - WriteObject(ElemStringDictExItem, ElemKey, ElemValue, kvp); - - m_xmlWriter.WriteEndElement(); - } - - private void WriteCustomIconList() - { - if(m_pwDatabase.CustomIcons.Count == 0) return; - - m_xmlWriter.WriteStartElement(ElemCustomIcons); - - foreach(PwCustomIcon pwci in m_pwDatabase.CustomIcons) - { - m_xmlWriter.WriteStartElement(ElemCustomIconItem); - - WriteObject(ElemCustomIconItemID, pwci.Uuid); - - string strData = Convert.ToBase64String(pwci.ImageDataPng); - WriteObject(ElemCustomIconItemData, strData, false); - - m_xmlWriter.WriteEndElement(); - } - - m_xmlWriter.WriteEndElement(); - } - - private void WriteObject(string name, string value, - bool bFilterValueXmlChars) - { - Debug.Assert(name != null); - Debug.Assert(value != null); - - m_xmlWriter.WriteStartElement(name); - - if(bFilterValueXmlChars) - m_xmlWriter.WriteString(StrUtil.SafeXmlString(value)); - else m_xmlWriter.WriteString(value); - - m_xmlWriter.WriteEndElement(); - } - - private void WriteObject(string name, bool value) - { - Debug.Assert(name != null); - - WriteObject(name, value ? ValTrue : ValFalse, false); - } - - private void WriteObject(string name, PwUuid value) - { - Debug.Assert(name != null); - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - - WriteObject(name, Convert.ToBase64String(value.UuidBytes), false); - } - - private void WriteObject(string name, int value) - { - Debug.Assert(name != null); - - m_xmlWriter.WriteStartElement(name); - m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo)); - m_xmlWriter.WriteEndElement(); - } - - private void WriteObject(string name, uint value) - { - Debug.Assert(name != null); - - m_xmlWriter.WriteStartElement(name); - m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo)); - m_xmlWriter.WriteEndElement(); - } - - private void WriteObject(string name, long value) - { - Debug.Assert(name != null); - - m_xmlWriter.WriteStartElement(name); - m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo)); - m_xmlWriter.WriteEndElement(); - } - - private void WriteObject(string name, ulong value) - { - Debug.Assert(name != null); - - m_xmlWriter.WriteStartElement(name); - m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo)); - m_xmlWriter.WriteEndElement(); - } - - private void WriteObject(string name, DateTime value) - { - Debug.Assert(name != null); - Debug.Assert(value.Kind == DateTimeKind.Utc); - - // Cf. ReadTime - if((m_format == KdbxFormat.Default) && (m_uFileVersion >= FileVersion32_4)) - { - DateTime dt = TimeUtil.ToUtc(value, false); - - // DateTime dtBase = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc); - // dt -= new TimeSpan(dtBase.Ticks); - - // WriteObject(name, dt.ToBinary()); - - // dt = TimeUtil.RoundToMultOf2PowLess1s(dt); - // long lBin = dt.ToBinary(); - - long lSec = dt.Ticks / TimeSpan.TicksPerSecond; - // WriteObject(name, lSec); - - byte[] pb = MemUtil.Int64ToBytes(lSec); - WriteObject(name, Convert.ToBase64String(pb), false); - } - else WriteObject(name, TimeUtil.SerializeUtc(value), false); - } - - private void WriteObject(string name, string strKeyName, - string strValueName, KeyValuePair kvp) - { - m_xmlWriter.WriteStartElement(name); - - m_xmlWriter.WriteStartElement(strKeyName); - m_xmlWriter.WriteString(StrUtil.SafeXmlString(kvp.Key)); - m_xmlWriter.WriteEndElement(); - m_xmlWriter.WriteStartElement(strValueName); - m_xmlWriter.WriteString(StrUtil.SafeXmlString(kvp.Value)); - m_xmlWriter.WriteEndElement(); - - m_xmlWriter.WriteEndElement(); - } - - private void WriteObject(string name, ProtectedString value, bool bIsEntryString) - { - Debug.Assert(name != null); - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - - m_xmlWriter.WriteStartElement(ElemString); - m_xmlWriter.WriteStartElement(ElemKey); - m_xmlWriter.WriteString(StrUtil.SafeXmlString(name)); - m_xmlWriter.WriteEndElement(); - m_xmlWriter.WriteStartElement(ElemValue); - - bool bProtected = value.IsProtected; - if(bIsEntryString) - { - // Adjust memory protection setting (which might be different - // from the database default, e.g. due to an import which - // didn't specify the correct setting) - if(name == PwDefs.TitleField) - bProtected = m_pwDatabase.MemoryProtection.ProtectTitle; - else if(name == PwDefs.UserNameField) - bProtected = m_pwDatabase.MemoryProtection.ProtectUserName; - else if(name == PwDefs.PasswordField) - bProtected = m_pwDatabase.MemoryProtection.ProtectPassword; - else if(name == PwDefs.UrlField) - bProtected = m_pwDatabase.MemoryProtection.ProtectUrl; - else if(name == PwDefs.NotesField) - bProtected = m_pwDatabase.MemoryProtection.ProtectNotes; - } - - if(bProtected && (m_format == KdbxFormat.Default)) - { - m_xmlWriter.WriteAttributeString(AttrProtected, ValTrue); - - byte[] pbEncoded = value.ReadXorredString(m_randomStream); - if(pbEncoded.Length > 0) - m_xmlWriter.WriteBase64(pbEncoded, 0, pbEncoded.Length); - } - else - { - string strValue = value.ReadString(); - - // If names should be localized, we need to apply the language-dependent - // string transformation here. By default, language-dependent conversions - // should be applied, otherwise characters could be rendered incorrectly - // (code page problems). - if(m_bLocalizedNames) - { - StringBuilder sb = new StringBuilder(); - foreach(char ch in strValue) - { - char chMapped = ch; - - // Symbols and surrogates must be moved into the correct code - // page area - if(char.IsSymbol(ch) || char.IsSurrogate(ch)) - { - System.Globalization.UnicodeCategory cat = - CharUnicodeInfo.GetUnicodeCategory(ch); - // Map character to correct position in code page - chMapped = (char)((int)cat * 32 + ch); - } - else if(char.IsControl(ch)) - { - if(ch >= 256) // Control character in high ANSI code page - { - // Some of the control characters map to corresponding ones - // in the low ANSI range (up to 255) when calling - // ToLower on them with invariant culture (see - // http://lists.ximian.com/pipermail/mono-patches/2002-February/086106.html ) -#if !KeePassLibSD - chMapped = char.ToLowerInvariant(ch); -#else - chMapped = char.ToLower(ch); -#endif - } - } - - sb.Append(chMapped); - } - - strValue = sb.ToString(); // Correct string for current code page - } - - if((m_format == KdbxFormat.PlainXml) && bProtected) - m_xmlWriter.WriteAttributeString(AttrProtectedInMemPlainXml, ValTrue); - - m_xmlWriter.WriteString(StrUtil.SafeXmlString(strValue)); - } - - m_xmlWriter.WriteEndElement(); // ElemValue - m_xmlWriter.WriteEndElement(); // ElemString - } - - private void WriteObject(string name, ProtectedBinary value, bool bAllowRef) - { - Debug.Assert(name != null); - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - - m_xmlWriter.WriteStartElement(ElemBinary); - m_xmlWriter.WriteStartElement(ElemKey); - m_xmlWriter.WriteString(StrUtil.SafeXmlString(name)); - m_xmlWriter.WriteEndElement(); - m_xmlWriter.WriteStartElement(ElemValue); - - string strRef = null; - if(bAllowRef) - { - int iRef = m_pbsBinaries.Find(value); - if(iRef >= 0) strRef = iRef.ToString(NumberFormatInfo.InvariantInfo); - else { Debug.Assert(false); } - } - if(strRef != null) - m_xmlWriter.WriteAttributeString(AttrRef, strRef); - else SubWriteValue(value); - - m_xmlWriter.WriteEndElement(); // ElemValue - m_xmlWriter.WriteEndElement(); // ElemBinary - } - - private void SubWriteValue(ProtectedBinary value) - { - if(value.IsProtected && (m_format == KdbxFormat.Default)) - { - m_xmlWriter.WriteAttributeString(AttrProtected, ValTrue); - - byte[] pbEncoded = value.ReadXorredData(m_randomStream); - if(pbEncoded.Length > 0) - m_xmlWriter.WriteBase64(pbEncoded, 0, pbEncoded.Length); - } - else - { - if(m_pwDatabase.Compression != PwCompressionAlgorithm.None) - { - m_xmlWriter.WriteAttributeString(AttrCompressed, ValTrue); - - byte[] pbRaw = value.ReadData(); - byte[] pbCmp = MemUtil.Compress(pbRaw); - m_xmlWriter.WriteBase64(pbCmp, 0, pbCmp.Length); - - if(value.IsProtected) - { - MemUtil.ZeroByteArray(pbRaw); - MemUtil.ZeroByteArray(pbCmp); - } - } - else - { - byte[] pbRaw = value.ReadData(); - m_xmlWriter.WriteBase64(pbRaw, 0, pbRaw.Length); - - if(value.IsProtected) MemUtil.ZeroByteArray(pbRaw); - } - } - } - - private void WriteObject(string name, PwDeletedObject value) - { - Debug.Assert(name != null); - Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value"); - - m_xmlWriter.WriteStartElement(name); - WriteObject(ElemUuid, value.Uuid); - WriteObject(ElemDeletionTime, value.DeletionTime); - m_xmlWriter.WriteEndElement(); - } - - private void WriteBinPool() - { - m_xmlWriter.WriteStartElement(ElemBinaries); - - ProtectedBinary[] v = m_pbsBinaries.ToArray(); - for(int i = 0; i < v.Length; ++i) - { - m_xmlWriter.WriteStartElement(ElemBinary); - m_xmlWriter.WriteAttributeString(AttrId, - i.ToString(NumberFormatInfo.InvariantInfo)); - SubWriteValue(v[i]); - m_xmlWriter.WriteEndElement(); - } - - m_xmlWriter.WriteEndElement(); - } - - [Obsolete] - public static bool WriteEntries(Stream msOutput, PwEntry[] vEntries) - { - return WriteEntries(msOutput, null, vEntries); - } - - public static bool WriteEntries(Stream msOutput, PwDatabase pdContext, - PwEntry[] vEntries) - { - if(msOutput == null) { Debug.Assert(false); return false; } - // pdContext may be null - if(vEntries == null) { Debug.Assert(false); return false; } - - /* KdbxFile f = new KdbxFile(pwDatabase); - f.m_format = KdbxFormat.PlainXml; - - XmlTextWriter xtw = null; - try { xtw = new XmlTextWriter(msOutput, StrUtil.Utf8); } - catch(Exception) { Debug.Assert(false); return false; } - if(xtw == null) { Debug.Assert(false); return false; } - - f.m_xmlWriter = xtw; - - xtw.Formatting = Formatting.Indented; - xtw.IndentChar = '\t'; - xtw.Indentation = 1; - - xtw.WriteStartDocument(true); - xtw.WriteStartElement(ElemRoot); - - foreach(PwEntry pe in vEntries) - f.WriteEntry(pe, false); - - xtw.WriteEndElement(); - xtw.WriteEndDocument(); - - xtw.Flush(); - xtw.Close(); - return true; */ - - PwDatabase pd = new PwDatabase(); - pd.New(new IOConnectionInfo(), new CompositeKey()); - - PwGroup pg = pd.RootGroup; - if(pg == null) { Debug.Assert(false); return false; } - - foreach(PwEntry pe in vEntries) - { - PwUuid pu = pe.CustomIconUuid; - if(!pu.Equals(PwUuid.Zero) && (pd.GetCustomIconIndex(pu) < 0)) - { - int i = -1; - if(pdContext != null) i = pdContext.GetCustomIconIndex(pu); - if(i >= 0) - { - PwCustomIcon ci = pdContext.CustomIcons[i]; - pd.CustomIcons.Add(ci); - } - else { Debug.Assert(pdContext == null); } - } - - PwEntry peCopy = pe.CloneDeep(); - pg.AddEntry(peCopy, true); - } - - KdbxFile f = new KdbxFile(pd); - f.Save(msOutput, null, KdbxFormat.PlainXml, null); - return true; - } - } -} diff --git a/ModernKeePassLib/Serialization/KdbxFile.cs b/ModernKeePassLib/Serialization/KdbxFile.cs deleted file mode 100644 index 82248a0..0000000 --- a/ModernKeePassLib/Serialization/KdbxFile.cs +++ /dev/null @@ -1,547 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Security; -using System.Text; -using System.Xml; - -#if ModernKeePassLib -using Windows.Storage; -using ModernKeePassLib.Cryptography.Hash; -#endif - -using ModernKeePassLib.Collections; -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Cryptography.Cipher; -using ModernKeePassLib.Cryptography.KeyDerivation; -using ModernKeePassLib.Delegates; -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Resources; -using ModernKeePassLib.Security; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Serialization -{ - /// - /// The KdbxFile class supports saving the data to various - /// formats. - /// - public enum KdbxFormat - { - /// - /// The default, encrypted file format. - /// - Default = 0, - - /// - /// Use this flag when exporting data to a plain-text XML file. - /// - PlainXml - } - - /// - /// Serialization to KeePass KDBX files. - /// - public sealed partial class KdbxFile - { - /// - /// File identifier, first 32-bit value. - /// - internal const uint FileSignature1 = 0x9AA2D903; - - /// - /// File identifier, second 32-bit value. - /// - internal const uint FileSignature2 = 0xB54BFB67; - - /// - /// File version of files saved by the current KdbxFile class. - /// KeePass 2.07 has version 1.01, 2.08 has 1.02, 2.09 has 2.00, - /// 2.10 has 2.02, 2.11 has 2.04, 2.15 has 3.00, 2.20 has 3.01. - /// The first 2 bytes are critical (i.e. loading will fail, if the - /// file version is too high), the last 2 bytes are informational. - /// - private const uint FileVersion32 = 0x00040000; - - internal const uint FileVersion32_4 = 0x00040000; // First of 4.x series - internal const uint FileVersion32_3 = 0x00030001; // Old format 3.1 - - private const uint FileVersionCriticalMask = 0xFFFF0000; - - // KeePass 1.x signature - internal const uint FileSignatureOld1 = 0x9AA2D903; - internal const uint FileSignatureOld2 = 0xB54BFB65; - // KeePass 2.x pre-release (alpha and beta) signature - internal const uint FileSignaturePreRelease1 = 0x9AA2D903; - internal const uint FileSignaturePreRelease2 = 0xB54BFB66; - - private const string ElemDocNode = "KeePassFile"; - private const string ElemMeta = "Meta"; - private const string ElemRoot = "Root"; - private const string ElemGroup = "Group"; - private const string ElemEntry = "Entry"; - - private const string ElemGenerator = "Generator"; - private const string ElemHeaderHash = "HeaderHash"; - private const string ElemSettingsChanged = "SettingsChanged"; - private const string ElemDbName = "DatabaseName"; - private const string ElemDbNameChanged = "DatabaseNameChanged"; - private const string ElemDbDesc = "DatabaseDescription"; - private const string ElemDbDescChanged = "DatabaseDescriptionChanged"; - private const string ElemDbDefaultUser = "DefaultUserName"; - private const string ElemDbDefaultUserChanged = "DefaultUserNameChanged"; - private const string ElemDbMntncHistoryDays = "MaintenanceHistoryDays"; - private const string ElemDbColor = "Color"; - private const string ElemDbKeyChanged = "MasterKeyChanged"; - private const string ElemDbKeyChangeRec = "MasterKeyChangeRec"; - private const string ElemDbKeyChangeForce = "MasterKeyChangeForce"; - private const string ElemDbKeyChangeForceOnce = "MasterKeyChangeForceOnce"; - private const string ElemRecycleBinEnabled = "RecycleBinEnabled"; - private const string ElemRecycleBinUuid = "RecycleBinUUID"; - private const string ElemRecycleBinChanged = "RecycleBinChanged"; - private const string ElemEntryTemplatesGroup = "EntryTemplatesGroup"; - private const string ElemEntryTemplatesGroupChanged = "EntryTemplatesGroupChanged"; - private const string ElemHistoryMaxItems = "HistoryMaxItems"; - private const string ElemHistoryMaxSize = "HistoryMaxSize"; - private const string ElemLastSelectedGroup = "LastSelectedGroup"; - private const string ElemLastTopVisibleGroup = "LastTopVisibleGroup"; - - private const string ElemMemoryProt = "MemoryProtection"; - private const string ElemProtTitle = "ProtectTitle"; - private const string ElemProtUserName = "ProtectUserName"; - private const string ElemProtPassword = "ProtectPassword"; - private const string ElemProtUrl = "ProtectURL"; - private const string ElemProtNotes = "ProtectNotes"; - // private const string ElemProtAutoHide = "AutoEnableVisualHiding"; - - private const string ElemCustomIcons = "CustomIcons"; - private const string ElemCustomIconItem = "Icon"; - private const string ElemCustomIconItemID = "UUID"; - private const string ElemCustomIconItemData = "Data"; - - private const string ElemAutoType = "AutoType"; - private const string ElemHistory = "History"; - - private const string ElemName = "Name"; - private const string ElemNotes = "Notes"; - private const string ElemUuid = "UUID"; - private const string ElemIcon = "IconID"; - private const string ElemCustomIconID = "CustomIconUUID"; - private const string ElemFgColor = "ForegroundColor"; - private const string ElemBgColor = "BackgroundColor"; - private const string ElemOverrideUrl = "OverrideURL"; - private const string ElemTimes = "Times"; - private const string ElemTags = "Tags"; - - private const string ElemCreationTime = "CreationTime"; - private const string ElemLastModTime = "LastModificationTime"; - private const string ElemLastAccessTime = "LastAccessTime"; - private const string ElemExpiryTime = "ExpiryTime"; - private const string ElemExpires = "Expires"; - private const string ElemUsageCount = "UsageCount"; - private const string ElemLocationChanged = "LocationChanged"; - - private const string ElemGroupDefaultAutoTypeSeq = "DefaultAutoTypeSequence"; - private const string ElemEnableAutoType = "EnableAutoType"; - private const string ElemEnableSearching = "EnableSearching"; - - private const string ElemString = "String"; - private const string ElemBinary = "Binary"; - private const string ElemKey = "Key"; - private const string ElemValue = "Value"; - - private const string ElemAutoTypeEnabled = "Enabled"; - private const string ElemAutoTypeObfuscation = "DataTransferObfuscation"; - private const string ElemAutoTypeDefaultSeq = "DefaultSequence"; - private const string ElemAutoTypeItem = "Association"; - private const string ElemWindow = "Window"; - private const string ElemKeystrokeSequence = "KeystrokeSequence"; - - private const string ElemBinaries = "Binaries"; - - private const string AttrId = "ID"; - private const string AttrRef = "Ref"; - private const string AttrProtected = "Protected"; - private const string AttrProtectedInMemPlainXml = "ProtectInMemory"; - private const string AttrCompressed = "Compressed"; - - private const string ElemIsExpanded = "IsExpanded"; - private const string ElemLastTopVisibleEntry = "LastTopVisibleEntry"; - - private const string ElemDeletedObjects = "DeletedObjects"; - private const string ElemDeletedObject = "DeletedObject"; - private const string ElemDeletionTime = "DeletionTime"; - - private const string ValFalse = "False"; - private const string ValTrue = "True"; - - private const string ElemCustomData = "CustomData"; - private const string ElemStringDictExItem = "Item"; - - private PwDatabase m_pwDatabase; // Not null, see constructor - private bool m_bUsedOnce = false; - - private XmlWriter m_xmlWriter = null; - private CryptoRandomStream m_randomStream = null; - private KdbxFormat m_format = KdbxFormat.Default; - private IStatusLogger m_slLogger = null; - - private uint m_uFileVersion = 0; - private byte[] m_pbMasterSeed = null; - // private byte[] m_pbTransformSeed = null; - private byte[] m_pbEncryptionIV = null; - private byte[] m_pbStreamStartBytes = null; - - // ArcFourVariant only for backward compatibility; KeePass defaults - // to a more secure algorithm when *writing* databases - private CrsAlgorithm m_craInnerRandomStream = CrsAlgorithm.ArcFourVariant; - private byte[] m_pbInnerRandomStreamKey = null; - - private ProtectedBinarySet m_pbsBinaries = new ProtectedBinarySet(); - - private byte[] m_pbHashOfHeader = null; - private byte[] m_pbHashOfFileOnDisk = null; - - private readonly DateTime m_dtNow = DateTime.UtcNow; // Cache current time - - private const uint NeutralLanguageOffset = 0x100000; // 2^20, see 32-bit Unicode specs - private const uint NeutralLanguageIDSec = 0x7DC5C; // See 32-bit Unicode specs - private const uint NeutralLanguageID = NeutralLanguageOffset + NeutralLanguageIDSec; - private static bool m_bLocalizedNames = false; - - private enum KdbxHeaderFieldID : byte - { - EndOfHeader = 0, - Comment = 1, - CipherID = 2, - CompressionFlags = 3, - MasterSeed = 4, - TransformSeed = 5, // KDBX 3.1, for backward compatibility only - TransformRounds = 6, // KDBX 3.1, for backward compatibility only - EncryptionIV = 7, - InnerRandomStreamKey = 8, // KDBX 3.1, for backward compatibility only - StreamStartBytes = 9, // KDBX 3.1, for backward compatibility only - InnerRandomStreamID = 10, // KDBX 3.1, for backward compatibility only - KdfParameters = 11, // KDBX 4, superseding Transform* - PublicCustomData = 12 // KDBX 4 - } - - // Inner header in KDBX >= 4 files - private enum KdbxInnerHeaderFieldID : byte - { - EndOfHeader = 0, - InnerRandomStreamID = 1, // Supersedes KdbxHeaderFieldID.InnerRandomStreamID - InnerRandomStreamKey = 2, // Supersedes KdbxHeaderFieldID.InnerRandomStreamKey - Binary = 3 - } - - [Flags] - private enum KdbxBinaryFlags : byte - { - None = 0, - Protected = 1 - } - - public byte[] HashOfFileOnDisk - { - get { return m_pbHashOfFileOnDisk; } - } - - private bool m_bRepairMode = false; - public bool RepairMode - { - get { return m_bRepairMode; } - set { m_bRepairMode = value; } - } - - private uint m_uForceVersion = 0; - internal uint ForceVersion - { - get { return m_uForceVersion; } - set { m_uForceVersion = value; } - } - - private string m_strDetachBins = null; - /// - /// Detach binaries when opening a file. If this isn't null, - /// all binaries are saved to the specified path and are removed - /// from the database. - /// - public string DetachBinaries - { - get { return m_strDetachBins; } - set { m_strDetachBins = value; } - } - - /// - /// Default constructor. - /// - /// The PwDatabase instance that the - /// class will load file data into or use to create a KDBX file. - public KdbxFile(PwDatabase pwDataStore) - { - Debug.Assert(pwDataStore != null); - if(pwDataStore == null) throw new ArgumentNullException("pwDataStore"); - - m_pwDatabase = pwDataStore; - } - - /// - /// Call this once to determine the current localization settings. - /// - public static void DetermineLanguageId() - { - // Test if localized names should be used. If localized names are used, - // the m_bLocalizedNames value must be set to true. By default, localized - // names should be used! (Otherwise characters could be corrupted - // because of different code pages). - unchecked - { - uint uTest = 0; - foreach(char ch in PwDatabase.LocalizedAppName) - uTest = uTest * 5 + ch; - - m_bLocalizedNames = (uTest != NeutralLanguageID); - } - } - - private uint GetMinKdbxVersion() - { - if(m_uForceVersion != 0) return m_uForceVersion; - - // See also KeePassKdb2x3.Export (KDBX 3.1 export module) - - AesKdf kdfAes = new AesKdf(); - if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid)) - return FileVersion32; - - if(m_pwDatabase.PublicCustomData.Count > 0) - return FileVersion32; - - bool bCustomData = false; - GroupHandler gh = delegate(PwGroup pg) - { - if(pg == null) { Debug.Assert(false); return true; } - if(pg.CustomData.Count > 0) { bCustomData = true; return false; } - return true; - }; - EntryHandler eh = delegate(PwEntry pe) - { - if(pe == null) { Debug.Assert(false); return true; } - if(pe.CustomData.Count > 0) { bCustomData = true; return false; } - return true; - }; - gh(m_pwDatabase.RootGroup); - m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh); - if(bCustomData) return FileVersion32; - - return FileVersion32_3; // KDBX 3.1 is sufficient - } - - private void ComputeKeys(out byte[] pbCipherKey, int cbCipherKey, - out byte[] pbHmacKey64) - { - byte[] pbCmp = new byte[32 + 32 + 1]; - try - { - Debug.Assert(m_pbMasterSeed != null); - if(m_pbMasterSeed == null) - throw new ArgumentNullException("m_pbMasterSeed"); - Debug.Assert(m_pbMasterSeed.Length == 32); - if(m_pbMasterSeed.Length != 32) - throw new FormatException(KLRes.MasterSeedLengthInvalid); - Array.Copy(m_pbMasterSeed, 0, pbCmp, 0, 32); - - Debug.Assert(m_pwDatabase != null); - Debug.Assert(m_pwDatabase.MasterKey != null); - ProtectedBinary pbinUser = m_pwDatabase.MasterKey.GenerateKey32( - m_pwDatabase.KdfParameters); - Debug.Assert(pbinUser != null); - if(pbinUser == null) - throw new SecurityException(KLRes.InvalidCompositeKey); - byte[] pUserKey32 = pbinUser.ReadData(); - if((pUserKey32 == null) || (pUserKey32.Length != 32)) - throw new SecurityException(KLRes.InvalidCompositeKey); - Array.Copy(pUserKey32, 0, pbCmp, 32, 32); - MemUtil.ZeroByteArray(pUserKey32); - - pbCipherKey = CryptoUtil.ResizeKey(pbCmp, 0, 64, cbCipherKey); - - pbCmp[64] = 1; - using(SHA512Managed h = new SHA512Managed()) - { - pbHmacKey64 = h.ComputeHash(pbCmp); - } - } - finally { MemUtil.ZeroByteArray(pbCmp); } - } - - private ICipherEngine GetCipher(out int cbEncKey, out int cbEncIV) - { - PwUuid pu = m_pwDatabase.DataCipherUuid; - ICipherEngine iCipher = CipherPool.GlobalPool.GetCipher(pu); - if(iCipher == null) // CryptographicExceptions are translated to "file corrupted" - throw new Exception(KLRes.FileUnknownCipher + - MessageService.NewParagraph + KLRes.FileNewVerOrPlgReq + - MessageService.NewParagraph + "UUID: " + pu.ToHexString() + "."); - - ICipherEngine2 iCipher2 = (iCipher as ICipherEngine2); - if(iCipher2 != null) - { - cbEncKey = iCipher2.KeyLength; - if(cbEncKey < 0) throw new InvalidOperationException("EncKey.Length"); - - cbEncIV = iCipher2.IVLength; - if(cbEncIV < 0) throw new InvalidOperationException("EncIV.Length"); - } - else - { - cbEncKey = 32; - cbEncIV = 16; - } - - return iCipher; - } - - private Stream EncryptStream(Stream s, ICipherEngine iCipher, - byte[] pbKey, int cbIV, bool bEncrypt) - { - byte[] pbIV = (m_pbEncryptionIV ?? MemUtil.EmptyByteArray); - if(pbIV.Length != cbIV) - { - Debug.Assert(false); - throw new Exception(KLRes.FileCorrupted); - } - - if(bEncrypt) - return iCipher.EncryptStream(s, pbKey, pbIV); - return iCipher.DecryptStream(s, pbKey, pbIV); - } - - private byte[] ComputeHeaderHmac(byte[] pbHeader, byte[] pbKey) - { - byte[] pbHeaderHmac; - byte[] pbBlockKey = HmacBlockStream.GetHmacKey64( - pbKey, ulong.MaxValue); - using(HMACSHA256 h = new HMACSHA256(pbBlockKey)) - { - pbHeaderHmac = h.ComputeHash(pbHeader); - } - MemUtil.ZeroByteArray(pbBlockKey); - - return pbHeaderHmac; - } - - private void CloseStreams(List lStreams) - { - if(lStreams == null) { Debug.Assert(false); return; } - - // Typically, closing a stream also closes its base - // stream; however, there may be streams that do not - // do this (e.g. some cipher plugin), thus for safety - // we close all streams manually, from the innermost - // to the outermost - - for(int i = lStreams.Count - 1; i >= 0; --i) - { - // Check for duplicates - Debug.Assert((lStreams.IndexOf(lStreams[i]) == i) && - (lStreams.LastIndexOf(lStreams[i]) == i)); - - try { lStreams[i].Dispose(); } - // Unnecessary exception from CryptoStream with - // RijndaelManagedTransform when a stream hasn't been - // read completely (e.g. incorrect master key) -#if !ModernKeePassLib - catch(CryptographicException) { } -#endif - catch(Exception) { Debug.Assert(false); } - } - - // Do not clear the list - } - - private void CleanUpInnerRandomStream() - { - if(m_randomStream != null) m_randomStream.Dispose(); - - if(m_pbInnerRandomStreamKey != null) - MemUtil.ZeroByteArray(m_pbInnerRandomStreamKey); - } - - private static void SaveBinary(string strName, ProtectedBinary pb, - string strSaveDir) - { - if(pb == null) { Debug.Assert(false); return; } - - if(string.IsNullOrEmpty(strName)) strName = "File.bin"; - - string strPath; - int iTry = 1; - do - { - strPath = UrlUtil.EnsureTerminatingSeparator(strSaveDir, false); - - string strExt = UrlUtil.GetExtension(strName); - string strDesc = UrlUtil.StripExtension(strName); - - strPath += strDesc; - if(iTry > 1) - strPath += " (" + iTry.ToString(NumberFormatInfo.InvariantInfo) + - ")"; - - if(!string.IsNullOrEmpty(strExt)) strPath += "." + strExt; - - ++iTry; - } -#if ModernKeePassLib - while (StorageFile.GetFileFromPathAsync(strPath).GetResults() != null); -#else - while(File.Exists(strPath)); -#endif - -#if ModernKeePassLib - byte[] pbData = pb.ReadData(); - /*var file = FileSystem.Current.GetFileFromPathAsync(strPath).Result; - using (var stream = file.OpenAsync(FileAccess.ReadAndWrite).Result) {*/ - var file = StorageFile.GetFileFromPathAsync(strPath).GetAwaiter().GetResult(); - using (var stream = file.OpenAsync(FileAccessMode.ReadWrite).GetAwaiter().GetResult().AsStream()) - { - stream.Write (pbData, 0, pbData.Length); - } - MemUtil.ZeroByteArray(pbData); -#elif !KeePassLibSD - byte[] pbData = pb.ReadData(); - File.WriteAllBytes(strPath, pbData); - MemUtil.ZeroByteArray(pbData); -#else - FileStream fs = new FileStream(strPath, FileMode.Create, - FileAccess.Write, FileShare.None); - byte[] pbData = pb.ReadData(); - try { File.WriteAllBytes(strPath, pbData); } - finally { if(pb.IsProtected) MemUtil.ZeroByteArray(pbData); } -#endif - } - } -} diff --git a/ModernKeePassLib/Serialization/OldFormatException.cs b/ModernKeePassLib/Serialization/OldFormatException.cs deleted file mode 100644 index fcf660a..0000000 --- a/ModernKeePassLib/Serialization/OldFormatException.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -using ModernKeePassLib.Resources; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Serialization -{ - public sealed class OldFormatException : Exception - { - private string m_strFormat = string.Empty; - private OldFormatType m_type = OldFormatType.Unknown; - - public enum OldFormatType - { - Unknown = 0, - KeePass1x = 1 - } - - public override string Message - { - get - { - string str = KLRes.OldFormat + ((m_strFormat.Length > 0) ? - (@" (" + m_strFormat + @")") : string.Empty) + "."; - - if(m_type == OldFormatType.KeePass1x) - str += Environment.NewLine + KLRes.KeePass1xHint; - - return str; - } - } - - public OldFormatException(string strFormatName) - { - if(strFormatName != null) m_strFormat = strFormatName; - } - - public OldFormatException(string strFormatName, OldFormatType t) - { - if(strFormatName != null) m_strFormat = strFormatName; - - m_type = t; - } - } -} diff --git a/ModernKeePassLib/Translation/KPControlCustomization.cs b/ModernKeePassLib/Translation/KPControlCustomization.cs deleted file mode 100644 index 5edcefc..0000000 --- a/ModernKeePassLib/Translation/KPControlCustomization.cs +++ /dev/null @@ -1,400 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using System.Xml.Serialization; - -#if !KeePassUAP -using System.Drawing; -using System.Windows.Forms; -#endif - -using ModernKeePassLib.Cryptography; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Translation -{ - public sealed class KpccLayout - { - public enum LayoutParameterEx - { - X, Y, Width, Height - } - - private const string m_strControlRelative = @"%c"; - - internal const NumberStyles m_nsParser = (NumberStyles.AllowLeadingSign | - NumberStyles.AllowDecimalPoint); - internal static readonly CultureInfo m_lclInv = CultureInfo.InvariantCulture; - - private string m_strPosX = string.Empty; - [XmlAttribute] - [DefaultValue("")] - public string X - { - get { return m_strPosX; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strPosX = value; - } - } - - private string m_strPosY = string.Empty; - [XmlAttribute] - [DefaultValue("")] - public string Y - { - get { return m_strPosY; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strPosY = value; - } - } - - private string m_strSizeW = string.Empty; - [XmlAttribute] - [DefaultValue("")] - public string Width - { - get { return m_strSizeW; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strSizeW = value; - } - } - - private string m_strSizeH = string.Empty; - [XmlAttribute] - [DefaultValue("")] - public string Height - { - get { return m_strSizeH; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strSizeH = value; - } - } - - public void SetControlRelativeValue(LayoutParameterEx lp, string strValue) - { - Debug.Assert(strValue != null); - if(strValue == null) throw new ArgumentNullException("strValue"); - - if(strValue.Length > 0) strValue += m_strControlRelative; - - if(lp == LayoutParameterEx.X) m_strPosX = strValue; - else if(lp == LayoutParameterEx.Y) m_strPosY = strValue; - else if(lp == LayoutParameterEx.Width) m_strSizeW = strValue; - else if(lp == LayoutParameterEx.Height) m_strSizeH = strValue; - else { Debug.Assert(false); } - } - -#if (!KeePassLibSD && !KeePassUAP) - internal void ApplyTo(Control c) - { - Debug.Assert(c != null); if(c == null) return; - - int? v; - v = GetModControlParameter(c, LayoutParameterEx.X, m_strPosX); - if(v.HasValue) c.Left = v.Value; - v = GetModControlParameter(c, LayoutParameterEx.Y, m_strPosY); - if(v.HasValue) c.Top = v.Value; - v = GetModControlParameter(c, LayoutParameterEx.Width, m_strSizeW); - if(v.HasValue) c.Width = v.Value; - v = GetModControlParameter(c, LayoutParameterEx.Height, m_strSizeH); - if(v.HasValue) c.Height = v.Value; - } - - private static int? GetModControlParameter(Control c, LayoutParameterEx p, - string strModParam) - { - if(strModParam.Length == 0) return null; - - Debug.Assert(c.Left == c.Location.X); - Debug.Assert(c.Top == c.Location.Y); - Debug.Assert(c.Width == c.Size.Width); - Debug.Assert(c.Height == c.Size.Height); - - int iPrev; - if(p == LayoutParameterEx.X) iPrev = c.Left; - else if(p == LayoutParameterEx.Y) iPrev = c.Top; - else if(p == LayoutParameterEx.Width) iPrev = c.Width; - else if(p == LayoutParameterEx.Height) iPrev = c.Height; - else { Debug.Assert(false); return null; } - - double? dRel = ToControlRelativePercent(strModParam); - if(dRel.HasValue) - return (iPrev + (int)((dRel.Value * (double)iPrev) / 100.0)); - - Debug.Assert(false); - return null; - } - - public static double? ToControlRelativePercent(string strEncoded) - { - Debug.Assert(strEncoded != null); - if(strEncoded == null) throw new ArgumentNullException("strEncoded"); - - if(strEncoded.Length == 0) return null; - - if(strEncoded.EndsWith(m_strControlRelative)) - { - string strValue = strEncoded.Substring(0, strEncoded.Length - - m_strControlRelative.Length); - if((strValue.Length == 1) && (strValue == "-")) - strValue = "0"; - - double dRel; - if(double.TryParse(strValue, m_nsParser, m_lclInv, out dRel)) - { - return dRel; - } - else - { - Debug.Assert(false); - return null; - } - } - - Debug.Assert(false); - return null; - } -#endif - - public static string ToControlRelativeString(string strEncoded) - { - Debug.Assert(strEncoded != null); - if(strEncoded == null) throw new ArgumentNullException("strEncoded"); - - if(strEncoded.Length == 0) return string.Empty; - - if(strEncoded.EndsWith(m_strControlRelative)) - return strEncoded.Substring(0, strEncoded.Length - - m_strControlRelative.Length); - - Debug.Assert(false); - return string.Empty; - } - } - - public sealed class KPControlCustomization : IComparable - { - private string m_strMemberName = string.Empty; - /// - /// Member variable name of the control to be translated. - /// - [XmlAttribute] - public string Name - { - get { return m_strMemberName; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strMemberName = value; - } - } - - private string m_strHash = string.Empty; - [XmlAttribute] - public string BaseHash - { - get { return m_strHash; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strHash = value; - } - } - - private string m_strText = string.Empty; - [DefaultValue("")] - public string Text - { - get { return m_strText; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strText = value; - } - } - - private string m_strEngText = string.Empty; - [XmlIgnore] - public string TextEnglish - { - get { return m_strEngText; } - set { m_strEngText = value; } - } - - private KpccLayout m_layout = new KpccLayout(); - public KpccLayout Layout - { - get { return m_layout; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_layout = value; - } - } - - public int CompareTo(KPControlCustomization kpOther) - { - if(kpOther == null) { Debug.Assert(false); return 1; } - - return m_strMemberName.CompareTo(kpOther.Name); - } - -#if (!KeePassLibSD && !KeePassUAP) - private static readonly Type[] m_vTextControls = new Type[] { - typeof(MenuStrip), typeof(PictureBox), typeof(ListView), - typeof(TreeView), typeof(ToolStrip), typeof(WebBrowser), - typeof(Panel), typeof(StatusStrip), typeof(ProgressBar), - typeof(NumericUpDown), typeof(TabControl) - }; - - public static bool ControlSupportsText(object oControl) - { - if(oControl == null) return false; - - Type t = oControl.GetType(); - for(int i = 0; i < m_vTextControls.Length; ++i) - { - if(t == m_vTextControls[i]) return false; - } - - return true; - } - - // Name-unchecked (!) property application method - internal void ApplyTo(Control c) - { - if((m_strText.Length > 0) && ControlSupportsText(c) && - (c.Text.Length > 0)) - { - c.Text = m_strText; - } - - m_layout.ApplyTo(c); - } - - public static string HashControl(Control c) - { - if(c == null) { Debug.Assert(false); return string.Empty; } - - StringBuilder sb = new StringBuilder(); - WriteCpiParam(sb, c.Text); - - if(c is Form) - { - WriteCpiParam(sb, c.ClientSize.Width.ToString(KpccLayout.m_lclInv)); - WriteCpiParam(sb, c.ClientSize.Height.ToString(KpccLayout.m_lclInv)); - } - else // Normal control - { - WriteCpiParam(sb, c.Left.ToString(KpccLayout.m_lclInv)); - WriteCpiParam(sb, c.Top.ToString(KpccLayout.m_lclInv)); - WriteCpiParam(sb, c.Width.ToString(KpccLayout.m_lclInv)); - WriteCpiParam(sb, c.Height.ToString(KpccLayout.m_lclInv)); - WriteCpiParam(sb, c.Dock.ToString()); - } - - WriteCpiParam(sb, c.Font.Name); - WriteCpiParam(sb, c.Font.SizeInPoints.ToString(KpccLayout.m_lclInv)); - WriteCpiParam(sb, c.Font.Bold ? "B" : "N"); - WriteCpiParam(sb, c.Font.Italic ? "I" : "N"); - WriteCpiParam(sb, c.Font.Underline ? "U" : "N"); - WriteCpiParam(sb, c.Font.Strikeout ? "S" : "N"); - - WriteControlDependentParams(sb, c); - - byte[] pb = StrUtil.Utf8.GetBytes(sb.ToString()); - byte[] pbSha = CryptoUtil.HashSha256(pb); - - // See also MatchHash - return "v1:" + Convert.ToBase64String(pbSha, 0, 3, - Base64FormattingOptions.None); - } - - private static void WriteControlDependentParams(StringBuilder sb, Control c) - { - CheckBox cb = (c as CheckBox); - RadioButton rb = (c as RadioButton); - Button btn = (c as Button); - Label l = (c as Label); - LinkLabel ll = (c as LinkLabel); - - if(cb != null) - { - WriteCpiParam(sb, cb.AutoSize ? "A" : "F"); - WriteCpiParam(sb, cb.TextAlign.ToString()); - WriteCpiParam(sb, cb.TextImageRelation.ToString()); - WriteCpiParam(sb, cb.Appearance.ToString()); - WriteCpiParam(sb, cb.CheckAlign.ToString()); - } - else if(rb != null) - { - WriteCpiParam(sb, rb.AutoSize ? "A" : "F"); - WriteCpiParam(sb, rb.TextAlign.ToString()); - WriteCpiParam(sb, rb.TextImageRelation.ToString()); - WriteCpiParam(sb, rb.Appearance.ToString()); - WriteCpiParam(sb, rb.CheckAlign.ToString()); - } - else if(btn != null) - { - WriteCpiParam(sb, btn.AutoSize ? "A" : "F"); - WriteCpiParam(sb, btn.TextAlign.ToString()); - WriteCpiParam(sb, btn.TextImageRelation.ToString()); - } - else if(l != null) - { - WriteCpiParam(sb, l.AutoSize ? "A" : "F"); - WriteCpiParam(sb, l.TextAlign.ToString()); - } - else if(ll != null) - { - WriteCpiParam(sb, ll.AutoSize ? "A" : "F"); - WriteCpiParam(sb, ll.TextAlign.ToString()); - } - } - - private static void WriteCpiParam(StringBuilder sb, string strProp) - { - sb.Append('/'); - sb.Append(strProp); - } - - public bool MatchHash(string strHash) - { - if(strHash == null) throw new ArgumentNullException("strHash"); - - // Currently only v1: is supported, see HashControl - return (m_strHash == strHash); - } -#endif - } -} diff --git a/ModernKeePassLib/Translation/KPFormCustomization.cs b/ModernKeePassLib/Translation/KPFormCustomization.cs deleted file mode 100644 index 2f3c5ad..0000000 --- a/ModernKeePassLib/Translation/KPFormCustomization.cs +++ /dev/null @@ -1,108 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using System.Xml.Serialization; - -#if !KeePassUAP -using System.Windows.Forms; -#endif - -namespace ModernKeePassLib.Translation -{ - public sealed class KPFormCustomization - { - private string m_strFQName = string.Empty; - /// - /// The fully qualified name of the form. - /// - [XmlAttribute] - public string FullName - { - get { return m_strFQName; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strFQName = value; - } - } - - private KPControlCustomization m_ccWindow = new KPControlCustomization(); - public KPControlCustomization Window - { - get { return m_ccWindow; } - set { m_ccWindow = value; } - } - - private List m_vControls = - new List(); - [XmlArray("ChildControls")] - [XmlArrayItem("Control")] - public List Controls - { - get { return m_vControls; } - set - { - if(value == null) throw new ArgumentNullException("value"); - - m_vControls = value; - } - } - -#if (!KeePassLibSD && !KeePassUAP) - private Form m_formEnglish = null; - [XmlIgnore] - public Form FormEnglish - { - get { return m_formEnglish; } - set { m_formEnglish = value; } - } - - public void ApplyTo(Form form) - { - Debug.Assert(form != null); if(form == null) throw new ArgumentNullException("form"); - - // Not supported by TrlUtil (preview form): - // Debug.Assert(form.GetType().FullName == m_strFQName); - - m_ccWindow.ApplyTo(form); - - if(m_vControls.Count == 0) return; - foreach(Control c in form.Controls) ApplyToControl(c); - } - - private void ApplyToControl(Control c) - { - foreach(KPControlCustomization cc in m_vControls) - { - if(c.Name == cc.Name) - { - cc.ApplyTo(c); - break; - } - } - - foreach(Control cSub in c.Controls) ApplyToControl(cSub); - } -#endif - } -} diff --git a/ModernKeePassLib/Translation/KPStringTable.cs b/ModernKeePassLib/Translation/KPStringTable.cs deleted file mode 100644 index ed4af18..0000000 --- a/ModernKeePassLib/Translation/KPStringTable.cs +++ /dev/null @@ -1,102 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using System.Xml.Serialization; - -#if !KeePassUAP -using System.Windows.Forms; -#endif - -namespace ModernKeePassLib.Translation -{ - public sealed class KPStringTable - { - private string m_strName = string.Empty; - [XmlAttribute] - public string Name - { - get { return m_strName; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_strName = value; - } - } - - private List m_vItems = new List(); - - [XmlArrayItem("Data")] - public List Strings - { - get { return m_vItems; } - set - { - if(value == null) throw new ArgumentNullException("value"); - m_vItems = value; - } - } - - public Dictionary ToDictionary() - { - Dictionary dict = new Dictionary(); - - foreach(KPStringTableItem kpstItem in m_vItems) - { - if(kpstItem.Value.Length > 0) - dict[kpstItem.Name] = kpstItem.Value; - } - - return dict; - } - -#if (!KeePassLibSD && !KeePassUAP) - public void ApplyTo(ToolStripItemCollection tsic) - { - if(tsic == null) throw new ArgumentNullException("tsic"); - - Dictionary dict = this.ToDictionary(); - if(dict.Count == 0) return; - - this.ApplyTo(tsic, dict); - } - - private void ApplyTo(ToolStripItemCollection tsic, Dictionary dict) - { - if(tsic == null) return; - - foreach(ToolStripItem tsi in tsic) - { - if(tsi.Text.Length == 0) continue; - - string strTrl; - if(dict.TryGetValue(tsi.Name, out strTrl)) - tsi.Text = strTrl; - - ToolStripMenuItem tsmi = tsi as ToolStripMenuItem; - if((tsmi != null) && (tsmi.DropDownItems != null)) - this.ApplyTo(tsmi.DropDownItems); - } - } -#endif - } -} diff --git a/ModernKeePassLib/Translation/KPStringTableItem.cs b/ModernKeePassLib/Translation/KPStringTableItem.cs deleted file mode 100644 index b57ec0b..0000000 --- a/ModernKeePassLib/Translation/KPStringTableItem.cs +++ /dev/null @@ -1,51 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Xml.Serialization; - -namespace ModernKeePassLib.Translation -{ - public sealed class KPStringTableItem - { - private string m_strName = string.Empty; - public string Name - { - get { return m_strName; } - set { m_strName = value; } - } - - private string m_strValue = string.Empty; - public string Value - { - get { return m_strValue; } - set { m_strValue = value; } - } - - private string m_strEnglish = string.Empty; - [XmlIgnore] - public string ValueEnglish - { - get { return m_strEnglish; } - set { m_strEnglish = value; } - } - } -} diff --git a/ModernKeePassLib/Translation/KPTranslation.cs b/ModernKeePassLib/Translation/KPTranslation.cs deleted file mode 100644 index 9678e09..0000000 --- a/ModernKeePassLib/Translation/KPTranslation.cs +++ /dev/null @@ -1,312 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Text; -using System.Xml; -using System.Xml.Serialization; - -#if !KeePassUAP -using System.Drawing; -using System.Windows.Forms; -#endif - -#if KeePassLibSD -using ICSharpCode.SharpZipLib.GZip; -#else -using System.IO.Compression; -#endif - -using ModernKeePassLib.Interfaces; -using ModernKeePassLib.Utility; - -namespace ModernKeePassLib.Translation -{ - [XmlRoot("Translation")] - public sealed class KPTranslation - { - public const string FileExtension = "lngx"; - - private KPTranslationProperties m_props = new KPTranslationProperties(); - public KPTranslationProperties Properties - { - get { return m_props; } - set { m_props = value; } - } - - private List m_vStringTables = new List(); - - [XmlArrayItem("StringTable")] - public List StringTables - { - get { return m_vStringTables; } - set - { - if(value == null) throw new ArgumentNullException("value"); - - m_vStringTables = value; - } - } - - private List m_vForms = new List(); - - [XmlArrayItem("Form")] - public List Forms - { - get { return m_vForms; } - set - { - if(value == null) throw new ArgumentNullException("value"); - - m_vForms = value; - } - } - - private string m_strUnusedText = string.Empty; - [DefaultValue("")] - public string UnusedText - { - get { return m_strUnusedText; } - set - { - if(value == null) throw new ArgumentNullException("value"); - - m_strUnusedText = value; - } - } - - public static void Save(KPTranslation kpTrl, string strFileName, - IXmlSerializerEx xs) - { - using(FileStream fs = new FileStream(strFileName, FileMode.Create, - FileAccess.Write, FileShare.None)) - { - Save(kpTrl, fs, xs); - } - } - - public static void Save(KPTranslation kpTrl, Stream sOut, - IXmlSerializerEx xs) - { - if(xs == null) throw new ArgumentNullException("xs"); - -#if !KeePassLibSD - using(GZipStream gz = new GZipStream(sOut, CompressionMode.Compress)) -#else - using(GZipOutputStream gz = new GZipOutputStream(sOut)) -#endif - { - using(XmlWriter xw = XmlUtilEx.CreateXmlWriter(gz)) - { - xs.Serialize(xw, kpTrl); - } - } - - sOut.Close(); - } - - public static KPTranslation Load(string strFile, IXmlSerializerEx xs) - { - KPTranslation kpTrl = null; - - using(FileStream fs = new FileStream(strFile, FileMode.Open, - FileAccess.Read, FileShare.Read)) - { - kpTrl = Load(fs, xs); - } - - return kpTrl; - } - - public static KPTranslation Load(Stream s, IXmlSerializerEx xs) - { - if(xs == null) throw new ArgumentNullException("xs"); - - KPTranslation kpTrl = null; - -#if !KeePassLibSD - using(GZipStream gz = new GZipStream(s, CompressionMode.Decompress)) -#else - using(GZipInputStream gz = new GZipInputStream(s)) -#endif - { - kpTrl = (xs.Deserialize(gz) as KPTranslation); - } - - s.Close(); - return kpTrl; - } - - public Dictionary SafeGetStringTableDictionary( - string strTableName) - { - foreach(KPStringTable kpst in m_vStringTables) - { - if(kpst.Name == strTableName) return kpst.ToDictionary(); - } - - return new Dictionary(); - } - -#if (!KeePassLibSD && !KeePassRT) - public void ApplyTo(Form form) - { - if(form == null) throw new ArgumentNullException("form"); - - if(m_props.RightToLeft) - { - try - { - form.RightToLeft = RightToLeft.Yes; - form.RightToLeftLayout = true; - } - catch(Exception) { Debug.Assert(false); } - } - - string strTypeName = form.GetType().FullName; - foreach(KPFormCustomization kpfc in m_vForms) - { - if(kpfc.FullName == strTypeName) - { - kpfc.ApplyTo(form); - break; - } - } - - if(m_props.RightToLeft) - { - try { RtlApplyToControls(form.Controls); } - catch(Exception) { Debug.Assert(false); } - } - } - - private static void RtlApplyToControls(Control.ControlCollection cc) - { - foreach(Control c in cc) - { - if(c.Controls.Count > 0) RtlApplyToControls(c.Controls); - - if(c is DateTimePicker) - ((DateTimePicker)c).RightToLeftLayout = true; - else if(c is ListView) - ((ListView)c).RightToLeftLayout = true; - else if(c is MonthCalendar) - ((MonthCalendar)c).RightToLeftLayout = true; - else if(c is ProgressBar) - ((ProgressBar)c).RightToLeftLayout = true; - else if(c is TabControl) - ((TabControl)c).RightToLeftLayout = true; - else if(c is TrackBar) - ((TrackBar)c).RightToLeftLayout = true; - else if(c is TreeView) - ((TreeView)c).RightToLeftLayout = true; - // else if(c is ToolStrip) - // RtlApplyToToolStripItems(((ToolStrip)c).Items); - /* else if(c is Button) // Also see Label - { - Button btn = (c as Button); - Image img = btn.Image; - if(img != null) - { - Image imgNew = (Image)img.Clone(); - imgNew.RotateFlip(RotateFlipType.RotateNoneFlipX); - btn.Image = imgNew; - } - } - else if(c is Label) // Also see Button - { - Label lbl = (c as Label); - Image img = lbl.Image; - if(img != null) - { - Image imgNew = (Image)img.Clone(); - imgNew.RotateFlip(RotateFlipType.RotateNoneFlipX); - lbl.Image = imgNew; - } - } */ - - if(IsRtlMoveChildsRequired(c)) RtlMoveChildControls(c); - } - } - - internal static bool IsRtlMoveChildsRequired(Control c) - { - if(c == null) { Debug.Assert(false); return false; } - - return ((c is GroupBox) || (c is Panel)); - } - - private static void RtlMoveChildControls(Control cParent) - { - int nParentWidth = cParent.Size.Width; - - foreach(Control c in cParent.Controls) - { - DockStyle ds = c.Dock; - if(ds == DockStyle.Left) - c.Dock = DockStyle.Right; - else if(ds == DockStyle.Right) - c.Dock = DockStyle.Left; - else - { - Point ptCur = c.Location; - c.Location = new Point(nParentWidth - c.Size.Width - ptCur.X, ptCur.Y); - } - } - } - - /* private static readonly string[] g_vRtlMirrorItemNames = new string[] { }; - private static void RtlApplyToToolStripItems(ToolStripItemCollection tsic) - { - foreach(ToolStripItem tsi in tsic) - { - if(tsi == null) { Debug.Assert(false); continue; } - - if(Array.IndexOf(g_vRtlMirrorItemNames, tsi.Name) >= 0) - tsi.RightToLeftAutoMirrorImage = true; - - ToolStripDropDownItem tsdd = (tsi as ToolStripDropDownItem); - if(tsdd != null) - RtlApplyToToolStripItems(tsdd.DropDownItems); - } - } */ - - public void ApplyTo(string strTableName, ToolStripItemCollection tsic) - { - if(tsic == null) throw new ArgumentNullException("tsic"); - - KPStringTable kpst = null; - foreach(KPStringTable kpstEnum in m_vStringTables) - { - if(kpstEnum.Name == strTableName) - { - kpst = kpstEnum; - break; - } - } - - if(kpst != null) kpst.ApplyTo(tsic); - } -#endif - } -} diff --git a/ModernKeePassLib/Translation/KPTranslationProperties.cs b/ModernKeePassLib/Translation/KPTranslationProperties.cs deleted file mode 100644 index eb124a2..0000000 --- a/ModernKeePassLib/Translation/KPTranslationProperties.cs +++ /dev/null @@ -1,105 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace ModernKeePassLib.Translation -{ - public sealed class KPTranslationProperties - { - private string m_strApp = string.Empty; - public string Application - { - get { return m_strApp; } - set { m_strApp = value; } - } - - private string m_strForVersion = string.Empty; - public string ApplicationVersion - { - get { return m_strForVersion; } - set { m_strForVersion = value; } - } - - private string m_strNameEnglish = string.Empty; - public string NameEnglish - { - get { return m_strNameEnglish; } - set { m_strNameEnglish = value; } - } - - private string m_strNameNative = string.Empty; - public string NameNative - { - get { return m_strNameNative; } - set { m_strNameNative = value; } - } - - private string m_strIso6391Code = string.Empty; - public string Iso6391Code - { - get { return m_strIso6391Code; } - set { m_strIso6391Code = value; } - } - - private bool m_bRtl = false; - public bool RightToLeft - { - get { return m_bRtl; } - set { m_bRtl = value; } - } - - private string m_strAuthorName = string.Empty; - public string AuthorName - { - get { return m_strAuthorName; } - set { m_strAuthorName = value; } - } - - private string m_strAuthorContact = string.Empty; - public string AuthorContact - { - get { return m_strAuthorContact; } - set { m_strAuthorContact = value; } - } - - private string m_strGen = string.Empty; - public string Generator - { - get { return m_strGen; } - set { m_strGen = value; } - } - - private string m_strUuid = string.Empty; - public string FileUuid - { - get { return m_strUuid; } - set { m_strUuid = value; } - } - - private string m_strLastModified = string.Empty; - public string LastModified - { - get { return m_strLastModified; } - set { m_strLastModified = value; } - } - } -} diff --git a/ModernKeePassLib/Utility/AppLogEx.cs b/ModernKeePassLib/Utility/AppLogEx.cs deleted file mode 100644 index 78eb02b..0000000 --- a/ModernKeePassLib/Utility/AppLogEx.cs +++ /dev/null @@ -1,103 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; - -#if !KeePassLibSD -using System.IO.Compression; -#endif - -namespace ModernKeePassLib.Utility -{ - /// - /// Application-wide logging services. - /// - public static class AppLogEx - { - private static StreamWriter m_swOut = null; - - public static void Open(string strPrefix) - { - // Logging is not enabled in normal builds of KeePass! - /* - AppLogEx.Close(); - - Debug.Assert(strPrefix != null); - if(strPrefix == null) strPrefix = "Log"; - - try - { - string strDirSep = string.Empty; - strDirSep += UrlUtil.LocalDirSepChar; - - string strTemp = UrlUtil.GetTempPath(); - if(!strTemp.EndsWith(strDirSep)) - strTemp += strDirSep; - - string strPath = strTemp + strPrefix + "-"; - Debug.Assert(strPath.IndexOf('/') < 0); - - DateTime dtNow = DateTime.UtcNow; - string strTime = dtNow.ToString("s"); - strTime = strTime.Replace('T', '-'); - strTime = strTime.Replace(':', '-'); - - strPath += strTime + "-" + Environment.TickCount.ToString( - NumberFormatInfo.InvariantInfo) + ".log.gz"; - - FileStream fsOut = new FileStream(strPath, FileMode.Create, - FileAccess.Write, FileShare.None); - GZipStream gz = new GZipStream(fsOut, CompressionMode.Compress); - m_swOut = new StreamWriter(gz); - - AppLogEx.Log("Started logging on " + dtNow.ToString("s") + "."); - } - catch(Exception) { Debug.Assert(false); } - */ - } - - public static void Close() - { - if(m_swOut == null) return; - - m_swOut.Dispose(); - m_swOut = null; - } - - public static void Log(string strText) - { - if(m_swOut == null) return; - - if(strText == null) m_swOut.WriteLine(); - else m_swOut.WriteLine(strText); - } - - public static void Log(Exception ex) - { - if(m_swOut == null) return; - - if(ex == null) m_swOut.WriteLine(); - else m_swOut.WriteLine(ex.ToString()); - } - } -} diff --git a/ModernKeePassLib/Utility/ColorTranslator.cs b/ModernKeePassLib/Utility/ColorTranslator.cs deleted file mode 100644 index 842345c..0000000 --- a/ModernKeePassLib/Utility/ColorTranslator.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Drawing; -using System.Globalization; -using System.Text.RegularExpressions; - -namespace ModernKeePassLib.Utility -{ - /// - /// Replacement for System.Drawing.ColorTranslator. - /// - /// - /// Colors are stored in the kdbx database file in HTML format (#XXXXXX). - /// - public static class ColorTranslator - { - static Regex longForm = new Regex("^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$"); - - /// - /// Converts an HTML color value to a Color. - /// - /// The Color. - /// HTML color code. - /// If htmlColor is null. - /// If htmlColor did not match the pattern "#XXXXXX". - /// - /// Currently only understands "#XXXXXX". "#XXX" or named colors will - /// throw and exception. - /// - public static Color FromHtml(string htmlColor) - { - if (htmlColor == null) - throw new ArgumentNullException("htmlColor"); - Match match = longForm.Match(htmlColor); - if (match.Success) { - var r = int.Parse(match.Groups[1].Value, NumberStyles.HexNumber); - var g = int.Parse(match.Groups[2].Value, NumberStyles.HexNumber); - var b = int.Parse(match.Groups[3].Value, NumberStyles.HexNumber); - return Color.FromArgb(r, g, b); - } - throw new ArgumentException(string.Format("Could not parse HTML color '{0}'.", htmlColor), "htmlColor"); - } - - /// - /// Converts a color to an HTML color code. - /// - /// String containing the color code. - /// The Color to convert - /// - /// The string is in the format "#XXXXXX" - /// - public static string ToHtml(Color htmlColor) - { - return string.Format("#{0:x2}{1:x2}{2:x2}", htmlColor.R, htmlColor.G, htmlColor.B); - } - } -} - diff --git a/ModernKeePassLib/Utility/GfxUtil.PCL.cs b/ModernKeePassLib/Utility/GfxUtil.PCL.cs deleted file mode 100644 index 72f10fc..0000000 --- a/ModernKeePassLib/Utility/GfxUtil.PCL.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.IO; -using Splat; - -namespace ModernKeePassLib.Utility -{ - public class GfxUtil - { - public static IBitmap LoadImage(byte[] pb) - { - return null; - //return ScaleImage(pb, null, null); - } - - public static IBitmap ScaleImage(byte[] pb, int? w, int? h) - { - return null; - /*using (var ms = new MemoryStream(pb, false)) - { - return BitmapLoader.Current.Load(ms, w, h).Result; - }*/ - } - } -} diff --git a/ModernKeePassLib/Utility/GfxUtil.cs b/ModernKeePassLib/Utility/GfxUtil.cs deleted file mode 100644 index d97a799..0000000 --- a/ModernKeePassLib/Utility/GfxUtil.cs +++ /dev/null @@ -1,441 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; - -#if !KeePassUAP -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -#endif - -namespace ModernKeePassLib.Utility -{ - public static class GfxUtil - { -#if (!KeePassLibSD && !KeePassUAP) - private sealed class GfxImage - { - public byte[] Data; - - public int Width; - public int Height; - - public GfxImage(byte[] pbData, int w, int h) - { - this.Data = pbData; - this.Width = w; - this.Height = h; - } - -#if DEBUG - // For debugger display - public override string ToString() - { - return (this.Width.ToString() + "x" + this.Height.ToString()); - } -#endif - } -#endif - -#if KeePassUAP - public static Image LoadImage(byte[] pb) - { - if(pb == null) throw new ArgumentNullException("pb"); - - MemoryStream ms = new MemoryStream(pb, false); - try { return Image.FromStream(ms); } - finally { ms.Close(); } - } -#else - public static Image LoadImage(byte[] pb) - { - if(pb == null) throw new ArgumentNullException("pb"); - -#if !KeePassLibSD - // First try to load the data as ICO and afterwards as - // normal image, because trying to load an ICO using - // the normal image loading methods can result in a - // low resolution image - try - { - Image imgIco = ExtractBestImageFromIco(pb); - if(imgIco != null) return imgIco; - } - catch(Exception) { Debug.Assert(false); } -#endif - - MemoryStream ms = new MemoryStream(pb, false); - try { return LoadImagePriv(ms); } - finally { ms.Close(); } - } - - private static Image LoadImagePriv(Stream s) - { - // Image.FromStream wants the stream to be open during - // the whole lifetime of the image; as we can't guarantee - // this, we make a copy of the image - Image imgSrc = null; - try - { -#if !KeePassLibSD - imgSrc = Image.FromStream(s); - Bitmap bmp = new Bitmap(imgSrc.Width, imgSrc.Height, - PixelFormat.Format32bppArgb); - - try - { - bmp.SetResolution(imgSrc.HorizontalResolution, - imgSrc.VerticalResolution); - Debug.Assert(bmp.Size == imgSrc.Size); - } - catch(Exception) { Debug.Assert(false); } -#else - imgSrc = new Bitmap(s); - Bitmap bmp = new Bitmap(imgSrc.Width, imgSrc.Height); -#endif - - using(Graphics g = Graphics.FromImage(bmp)) - { - g.Clear(Color.Transparent); - -#if !KeePassLibSD - g.DrawImageUnscaled(imgSrc, 0, 0); -#else - g.DrawImage(imgSrc, 0, 0); -#endif - } - - return bmp; - } - finally { if(imgSrc != null) imgSrc.Dispose(); } - } - -#if !KeePassLibSD - private static Image ExtractBestImageFromIco(byte[] pb) - { - List l = UnpackIco(pb); - if((l == null) || (l.Count == 0)) return null; - - long qMax = 0; - foreach(GfxImage gi in l) - { - if(gi.Width == 0) gi.Width = 256; - if(gi.Height == 0) gi.Height = 256; - - qMax = Math.Max(qMax, (long)gi.Width * (long)gi.Height); - } - - byte[] pbHdrPng = new byte[] { - 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A - }; - byte[] pbHdrJpeg = new byte[] { 0xFF, 0xD8, 0xFF }; - - Image imgBest = null; - int bppBest = -1; - - foreach(GfxImage gi in l) - { - if(((long)gi.Width * (long)gi.Height) < qMax) continue; - - byte[] pbImg = gi.Data; - Image img = null; - try - { - if((pbImg.Length > pbHdrPng.Length) && - MemUtil.ArraysEqual(pbHdrPng, - MemUtil.Mid(pbImg, 0, pbHdrPng.Length))) - img = GfxUtil.LoadImage(pbImg); - else if((pbImg.Length > pbHdrJpeg.Length) && - MemUtil.ArraysEqual(pbHdrJpeg, - MemUtil.Mid(pbImg, 0, pbHdrJpeg.Length))) - img = GfxUtil.LoadImage(pbImg); - else - { - using(MemoryStream ms = new MemoryStream(pb, false)) - { - using(Icon ico = new Icon(ms, gi.Width, gi.Height)) - { - img = ico.ToBitmap(); - } - } - } - } - catch(Exception) { Debug.Assert(false); } - - if(img == null) continue; - - if((img.Width < gi.Width) || (img.Height < gi.Height)) - { - Debug.Assert(false); - img.Dispose(); - continue; - } - - int bpp = GetBitsPerPixel(img.PixelFormat); - if(bpp > bppBest) - { - if(imgBest != null) imgBest.Dispose(); - - imgBest = img; - bppBest = bpp; - } - else img.Dispose(); - } - - return imgBest; - } - - private static List UnpackIco(byte[] pb) - { - if(pb == null) { Debug.Assert(false); return null; } - - const int SizeICONDIR = 6; - const int SizeICONDIRENTRY = 16; - - if(pb.Length < SizeICONDIR) return null; - if(MemUtil.BytesToUInt16(pb, 0) != 0) return null; // Reserved, 0 - if(MemUtil.BytesToUInt16(pb, 2) != 1) return null; // ICO type, 1 - - int n = MemUtil.BytesToUInt16(pb, 4); - if(n < 0) { Debug.Assert(false); return null; } - - int cbDir = SizeICONDIR + (n * SizeICONDIRENTRY); - if(pb.Length < cbDir) return null; - - List l = new List(); - int iOffset = SizeICONDIR; - for(int i = 0; i < n; ++i) - { - int w = pb[iOffset]; - int h = pb[iOffset + 1]; - if((w < 0) || (h < 0)) { Debug.Assert(false); return null; } - - int cb = MemUtil.BytesToInt32(pb, iOffset + 8); - if(cb <= 0) return null; // Data must have header (even BMP) - - int p = MemUtil.BytesToInt32(pb, iOffset + 12); - if(p < cbDir) return null; - if((p + cb) > pb.Length) return null; - - try - { - byte[] pbImage = MemUtil.Mid(pb, p, cb); - GfxImage img = new GfxImage(pbImage, w, h); - l.Add(img); - } - catch(Exception) { Debug.Assert(false); return null; } - - iOffset += SizeICONDIRENTRY; - } - - return l; - } - - private static int GetBitsPerPixel(PixelFormat f) - { - int bpp = 0; - switch(f) - { - case PixelFormat.Format1bppIndexed: - bpp = 1; - break; - - case PixelFormat.Format4bppIndexed: - bpp = 4; - break; - - case PixelFormat.Format8bppIndexed: - bpp = 8; - break; - - case PixelFormat.Format16bppArgb1555: - case PixelFormat.Format16bppGrayScale: - case PixelFormat.Format16bppRgb555: - case PixelFormat.Format16bppRgb565: - bpp = 16; - break; - - case PixelFormat.Format24bppRgb: - bpp = 24; - break; - - case PixelFormat.Format32bppArgb: - case PixelFormat.Format32bppPArgb: - case PixelFormat.Format32bppRgb: - bpp = 32; - break; - - case PixelFormat.Format48bppRgb: - bpp = 48; - break; - - case PixelFormat.Format64bppArgb: - case PixelFormat.Format64bppPArgb: - bpp = 64; - break; - - default: - Debug.Assert(false); - break; - } - - return bpp; - } - - public static Image ScaleImage(Image img, int w, int h) - { - return ScaleImage(img, w, h, ScaleTransformFlags.None); - } - - /// - /// Resize an image. - /// - /// Image to resize. - /// Width of the returned image. - /// Height of the returned image. - /// Flags to customize scaling behavior. - /// Resized image. This object is always different - /// from (i.e. they can be - /// disposed separately). - public static Image ScaleImage(Image img, int w, int h, - ScaleTransformFlags f) - { - if(img == null) throw new ArgumentNullException("img"); - if(w < 0) throw new ArgumentOutOfRangeException("w"); - if(h < 0) throw new ArgumentOutOfRangeException("h"); - - bool bUIIcon = ((f & ScaleTransformFlags.UIIcon) != - ScaleTransformFlags.None); - - // We must return a Bitmap object for UIUtil.CreateScaledImage - Bitmap bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb); - using(Graphics g = Graphics.FromImage(bmp)) - { - g.Clear(Color.Transparent); - - g.SmoothingMode = SmoothingMode.HighQuality; - g.CompositingQuality = CompositingQuality.HighQuality; - - int wSrc = img.Width; - int hSrc = img.Height; - - InterpolationMode im = InterpolationMode.HighQualityBicubic; - if((wSrc > 0) && (hSrc > 0)) - { - if(bUIIcon && ((w % wSrc) == 0) && ((h % hSrc) == 0)) - im = InterpolationMode.NearestNeighbor; - // else if((w < wSrc) && (h < hSrc)) - // im = InterpolationMode.HighQualityBilinear; - } - else { Debug.Assert(false); } - g.InterpolationMode = im; - - RectangleF rSource = new RectangleF(0.0f, 0.0f, wSrc, hSrc); - RectangleF rDest = new RectangleF(0.0f, 0.0f, w, h); - AdjustScaleRects(ref rSource, ref rDest); - - g.DrawImage(img, rDest, rSource, GraphicsUnit.Pixel); - } - - return bmp; - } - - internal static void AdjustScaleRects(ref RectangleF rSource, - ref RectangleF rDest) - { - // When enlarging images, apply a -0.5 offset to avoid - // the scaled image being cropped on the top/left side; - // when shrinking images, do not apply a -0.5 offset, - // otherwise the image is cropped on the bottom/right - // side; this applies to all interpolation modes - if(rDest.Width > rSource.Width) - rSource.X = rSource.X - 0.5f; - if(rDest.Height > rSource.Height) - rSource.Y = rSource.Y - 0.5f; - - // When shrinking, apply a +0.5 offset, such that the - // scaled image is less cropped on the bottom/right side - if(rDest.Width < rSource.Width) - rSource.X = rSource.X + 0.5f; - if(rDest.Height < rSource.Height) - rSource.Y = rSource.Y + 0.5f; - } - -#if DEBUG - public static Image ScaleTest(Image[] vIcons) - { - Bitmap bmp = new Bitmap(1024, vIcons.Length * (256 + 12), - PixelFormat.Format32bppArgb); - - using(Graphics g = Graphics.FromImage(bmp)) - { - g.Clear(Color.White); - - int[] v = new int[] { 16, 24, 32, 48, 64, 128, 256 }; - - int x; - int y = 8; - - foreach(Image imgIcon in vIcons) - { - if(imgIcon == null) { Debug.Assert(false); continue; } - - x = 128; - - foreach(int q in v) - { - using(Image img = ScaleImage(imgIcon, q, q, - ScaleTransformFlags.UIIcon)) - { - g.DrawImageUnscaled(img, x, y); - } - - x += q + 8; - } - - y += v[v.Length - 1] + 8; - } - } - - return bmp; - } -#endif // DEBUG -#endif // !KeePassLibSD -#endif // KeePassUAP - - internal static string ImageToDataUri(Image img) - { - if(img == null) { Debug.Assert(false); return string.Empty; } - - byte[] pb = null; - using(MemoryStream ms = new MemoryStream()) - { - img.Save(ms, ImageFormat.Png); - pb = ms.ToArray(); - } - - return StrUtil.DataToDataUri(pb, "image/png"); - } - } -} diff --git a/ModernKeePassLib/Utility/MemUtil.cs b/ModernKeePassLib/Utility/MemUtil.cs deleted file mode 100644 index fc3261b..0000000 --- a/ModernKeePassLib/Utility/MemUtil.cs +++ /dev/null @@ -1,872 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Runtime.CompilerServices; -using System.Text; - -#if KeePassLibSD -using KeePassLibSD; -#else -using System.IO.Compression; -#endif - -namespace ModernKeePassLib.Utility -{ - /// - /// Contains static buffer manipulation and string conversion routines. - /// - public static class MemUtil - { - internal static readonly byte[] EmptyByteArray = new byte[0]; - - internal static readonly ArrayHelperEx ArrayHelperExOfChar = - new ArrayHelperEx(); - - private static readonly uint[] m_vSBox = new uint[256] { - 0xCD2FACB3, 0xE78A7F5C, 0x6F0803FC, 0xBCF6E230, - 0x3A321712, 0x06403DB1, 0xD2F84B95, 0xDF22A6E4, - 0x07CE9E5B, 0x31788A0C, 0xF683F6F4, 0xEA061F49, - 0xFA5C2ACA, 0x4B9E494E, 0xB0AB25BA, 0x767731FC, - 0x261893A7, 0x2B09F2CE, 0x046261E4, 0x41367B4B, - 0x18A7F225, 0x8F923C0E, 0x5EF3A325, 0x28D0435E, - 0x84C22919, 0xED66873C, 0x8CEDE444, 0x7FC47C24, - 0xFCFC6BA3, 0x676F928D, 0xB4147187, 0xD8FB126E, - 0x7D798D17, 0xFF82E424, 0x1712FA5B, 0xABB09DD5, - 0x8156BA63, 0x84E4D969, 0xC937FB9A, 0x2F1E5BFC, - 0x178ECA11, 0x0E71CD5F, 0x52AAC6F4, 0x71EEFC8F, - 0x7090D749, 0x21CACA31, 0x92996378, 0x0939A8A8, - 0xE9EE1934, 0xD2718616, 0xF2500543, 0xB911873C, - 0xD3CB3EEC, 0x2BA0DBEB, 0xB42D0A27, 0xECE67C0F, - 0x302925F0, 0x6114F839, 0xD39E6307, 0xE28970D6, - 0xEB982F99, 0x941B4CDF, 0xC540E550, 0x8124FC45, - 0x98B025C7, 0xE2BF90EA, 0x4F57C976, 0xCF546FE4, - 0x59566DC8, 0xE3F4360D, 0xF5F9D231, 0xD6180B22, - 0xB54E088A, 0xB5DFE6A6, 0x3637A36F, 0x056E9284, - 0xAFF8FBC5, 0x19E01648, 0x8611F043, 0xDAE44337, - 0xF61B6A1C, 0x257ACD9E, 0xDD35F507, 0xEF05CAFA, - 0x05EB4A83, 0xFC25CA92, 0x0A4728E6, 0x9CF150EF, - 0xAEEF67DE, 0xA9472337, 0x57C81EFE, 0x3E5E009F, - 0x02CB03BB, 0x2BA85674, 0xF21DC251, 0x78C34A34, - 0xABB1F5BF, 0xB95A2FBD, 0x1FB47777, 0x9A96E8AC, - 0x5D2D2838, 0x55AAC92A, 0x99EE324E, 0x10F6214B, - 0x58ABDFB1, 0x2008794D, 0xBEC880F0, 0xE75E5341, - 0x88015C34, 0x352D8FBF, 0x622B7F6C, 0xF5C59EA2, - 0x1F759D8E, 0xADE56159, 0xCC7B4C25, 0x5B8BC48C, - 0xB6BD15AF, 0x3C5B5110, 0xE74A7C3D, 0xEE613161, - 0x156A1C67, 0x72C06817, 0xEA0A6F69, 0x4CECF993, - 0xCA9D554C, 0x8E20361F, 0x42D396B9, 0x595DE578, - 0x749D7955, 0xFD1BA5FD, 0x81FC160E, 0xDB97E28C, - 0x7CF148F7, 0x0B0B3CF5, 0x534DE605, 0x46421066, - 0xD4B68DD1, 0x9E479CE6, 0xAE667A9D, 0xBC082082, - 0xB06DD6EF, 0x20F0F23F, 0xB99E1551, 0xF47A2E3A, - 0x71DA50C6, 0x67B65779, 0x2A8CB376, 0x1EA71EEE, - 0x29ABCD50, 0xB6EB0C6B, 0x23C10511, 0x6F3F2144, - 0x6AF23012, 0xF696BD9E, 0xB94099D8, 0xAD5A9C81, - 0x7A0794FA, 0x7EDF59D6, 0x1E72E574, 0x8561913C, - 0x4E4D568F, 0xEECB9928, 0x9C124D2E, 0x0848B82C, - 0xF1CA395F, 0x9DAF43DC, 0xF77EC323, 0x394E9B59, - 0x7E200946, 0x8B811D68, 0x16DA3305, 0xAB8DE2C3, - 0xE6C53B64, 0x98C2D321, 0x88A97D81, 0xA7106419, - 0x8E52F7BF, 0x8ED262AF, 0x7CCA974E, 0xF0933241, - 0x040DD437, 0xE143B3D4, 0x3019F56F, 0xB741521D, - 0xF1745362, 0x4C435F9F, 0xB4214D0D, 0x0B0C348B, - 0x5051D189, 0x4C30447E, 0x7393D722, 0x95CEDD0B, - 0xDD994E80, 0xC3D22ED9, 0x739CD900, 0x131EB9C4, - 0xEF1062B2, 0x4F0DE436, 0x52920073, 0x9A7F3D80, - 0x896E7B1B, 0x2C8BBE5A, 0xBD304F8A, 0xA993E22C, - 0x134C41A0, 0xFA989E00, 0x39CE9726, 0xFB89FCCF, - 0xE8FBAC97, 0xD4063FFC, 0x935A2B5A, 0x44C8EE83, - 0xCB2BC7B6, 0x02989E92, 0x75478BEA, 0x144378D0, - 0xD853C087, 0x8897A34E, 0xDD23629D, 0xBDE2A2A2, - 0x581D8ECC, 0x5DA8AEE8, 0xFF8AAFD0, 0xBA2BCF6E, - 0x4BD98DAC, 0xF2EDB9E4, 0xFA2DC868, 0x47E84661, - 0xECEB1C7D, 0x41705CA4, 0x5982E4D4, 0xEB5204A1, - 0xD196CAFB, 0x6414804D, 0x3ABD4B46, 0x8B494C26, - 0xB432D52B, 0x39C5356B, 0x6EC80BF7, 0x71BE5483, - 0xCEC4A509, 0xE9411D61, 0x52F341E5, 0xD2E6197B, - 0x4F02826C, 0xA9E48838, 0xD1F8F247, 0xE4957FB3, - 0x586CCA99, 0x9A8B6A5B, 0x4998FBEA, 0xF762BE4C, - 0x90DFE33C, 0x9731511E, 0x88C6A82F, 0xDD65A4D4 - }; - - /// - /// Convert a hexadecimal string to a byte array. The input string must be - /// even (i.e. its length is a multiple of 2). - /// - /// String containing hexadecimal characters. - /// Returns a byte array. Returns null if the string parameter - /// was null or is an uneven string (i.e. if its length isn't a - /// multiple of 2). - /// Thrown if - /// is null. - public static byte[] HexStringToByteArray(string strHex) - { - if(strHex == null) { Debug.Assert(false); throw new ArgumentNullException("strHex"); } - - int nStrLen = strHex.Length; - if((nStrLen & 1) != 0) { Debug.Assert(false); return null; } - - byte[] pb = new byte[nStrLen / 2]; - byte bt; - char ch; - - for(int i = 0; i < nStrLen; i += 2) - { - ch = strHex[i]; - - if((ch >= '0') && (ch <= '9')) - bt = (byte)(ch - '0'); - else if((ch >= 'a') && (ch <= 'f')) - bt = (byte)(ch - 'a' + 10); - else if((ch >= 'A') && (ch <= 'F')) - bt = (byte)(ch - 'A' + 10); - else { Debug.Assert(false); bt = 0; } - - bt <<= 4; - - ch = strHex[i + 1]; - if((ch >= '0') && (ch <= '9')) - bt += (byte)(ch - '0'); - else if((ch >= 'a') && (ch <= 'f')) - bt += (byte)(ch - 'a' + 10); - else if((ch >= 'A') && (ch <= 'F')) - bt += (byte)(ch - 'A' + 10); - else { Debug.Assert(false); } - - pb[i >> 1] = bt; - } - - return pb; - } - - /// - /// Convert a byte array to a hexadecimal string. - /// - /// Input byte array. - /// Returns the hexadecimal string representing the byte - /// array. Returns null, if the input byte array was null. Returns - /// an empty string, if the input byte array has length 0. - public static string ByteArrayToHexString(byte[] pbArray) - { - if(pbArray == null) return null; - - int nLen = pbArray.Length; - if(nLen == 0) return string.Empty; - - StringBuilder sb = new StringBuilder(); - - byte bt, btHigh, btLow; - for(int i = 0; i < nLen; ++i) - { - bt = pbArray[i]; - btHigh = bt; btHigh >>= 4; - btLow = (byte)(bt & 0x0F); - - if(btHigh >= 10) sb.Append((char)('A' + btHigh - 10)); - else sb.Append((char)('0' + btHigh)); - - if(btLow >= 10) sb.Append((char)('A' + btLow - 10)); - else sb.Append((char)('0' + btLow)); - } - - return sb.ToString(); - } - - /// - /// Decode Base32 strings according to RFC 4648. - /// - public static byte[] ParseBase32(string str) - { - if((str == null) || ((str.Length % 8) != 0)) - { - Debug.Assert(false); - return null; - } - - ulong uMaxBits = (ulong)str.Length * 5UL; - List l = new List((int)(uMaxBits / 8UL) + 1); - Debug.Assert(l.Count == 0); - - for(int i = 0; i < str.Length; i += 8) - { - ulong u = 0; - int nBits = 0; - - for(int j = 0; j < 8; ++j) - { - char ch = str[i + j]; - if(ch == '=') break; - - ulong uValue; - if((ch >= 'A') && (ch <= 'Z')) - uValue = (ulong)(ch - 'A'); - else if((ch >= 'a') && (ch <= 'z')) - uValue = (ulong)(ch - 'a'); - else if((ch >= '2') && (ch <= '7')) - uValue = (ulong)(ch - '2') + 26UL; - else { Debug.Assert(false); return null; } - - u <<= 5; - u += uValue; - nBits += 5; - } - - int nBitsTooMany = (nBits % 8); - u >>= nBitsTooMany; - nBits -= nBitsTooMany; - Debug.Assert((nBits % 8) == 0); - - int idxNewBytes = l.Count; - while(nBits > 0) - { - l.Add((byte)(u & 0xFF)); - u >>= 8; - nBits -= 8; - } - l.Reverse(idxNewBytes, l.Count - idxNewBytes); - } - - return l.ToArray(); - } - - /// - /// Set all bytes in a byte array to zero. - /// - /// Input array. All bytes of this array - /// will be set to zero. - public static void ZeroByteArray(byte[] pbArray) - { - Debug.Assert(pbArray != null); - if(pbArray == null) throw new ArgumentNullException("pbArray"); - - Array.Clear(pbArray, 0, pbArray.Length); - } - - /// - /// Set all elements of an array to the default value. - /// - /// Input array. -#if KeePassLibSD - [MethodImpl(MethodImplOptions.NoInlining)] -#else - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] -#endif - public static void ZeroArray(T[] v) - { - if(v == null) { Debug.Assert(false); throw new ArgumentNullException("v"); } - - Array.Clear(v, 0, v.Length); - } - - /// - /// Convert 2 bytes to a 16-bit unsigned integer (little-endian). - /// - public static ushort BytesToUInt16(byte[] pb) - { - Debug.Assert((pb != null) && (pb.Length == 2)); - if(pb == null) throw new ArgumentNullException("pb"); - if(pb.Length != 2) throw new ArgumentOutOfRangeException("pb"); - - return (ushort)((ushort)pb[0] | ((ushort)pb[1] << 8)); - } - - /// - /// Convert 2 bytes to a 16-bit unsigned integer (little-endian). - /// - public static ushort BytesToUInt16(byte[] pb, int iOffset) - { - if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } - if((iOffset < 0) || ((iOffset + 1) >= pb.Length)) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("iOffset"); - } - - return (ushort)((ushort)pb[iOffset] | ((ushort)pb[iOffset + 1] << 8)); - } - - /// - /// Convert 4 bytes to a 32-bit unsigned integer (little-endian). - /// - public static uint BytesToUInt32(byte[] pb) - { - Debug.Assert((pb != null) && (pb.Length == 4)); - if(pb == null) throw new ArgumentNullException("pb"); - if(pb.Length != 4) throw new ArgumentOutOfRangeException("pb"); - - return ((uint)pb[0] | ((uint)pb[1] << 8) | ((uint)pb[2] << 16) | - ((uint)pb[3] << 24)); - } - - /// - /// Convert 4 bytes to a 32-bit unsigned integer (little-endian). - /// - public static uint BytesToUInt32(byte[] pb, int iOffset) - { - if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } - if((iOffset < 0) || ((iOffset + 3) >= pb.Length)) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("iOffset"); - } - - return ((uint)pb[iOffset] | ((uint)pb[iOffset + 1] << 8) | - ((uint)pb[iOffset + 2] << 16) | ((uint)pb[iOffset + 3] << 24)); - } - - /// - /// Convert 8 bytes to a 64-bit unsigned integer (little-endian). - /// - public static ulong BytesToUInt64(byte[] pb) - { - Debug.Assert((pb != null) && (pb.Length == 8)); - if(pb == null) throw new ArgumentNullException("pb"); - if(pb.Length != 8) throw new ArgumentOutOfRangeException("pb"); - - return ((ulong)pb[0] | ((ulong)pb[1] << 8) | ((ulong)pb[2] << 16) | - ((ulong)pb[3] << 24) | ((ulong)pb[4] << 32) | ((ulong)pb[5] << 40) | - ((ulong)pb[6] << 48) | ((ulong)pb[7] << 56)); - } - - /// - /// Convert 8 bytes to a 64-bit unsigned integer (little-endian). - /// - public static ulong BytesToUInt64(byte[] pb, int iOffset) - { - if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } - if((iOffset < 0) || ((iOffset + 7) >= pb.Length)) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("iOffset"); - } - - // if(BitConverter.IsLittleEndian) - // return BitConverter.ToUInt64(pb, iOffset); - - return ((ulong)pb[iOffset] | ((ulong)pb[iOffset + 1] << 8) | - ((ulong)pb[iOffset + 2] << 16) | ((ulong)pb[iOffset + 3] << 24) | - ((ulong)pb[iOffset + 4] << 32) | ((ulong)pb[iOffset + 5] << 40) | - ((ulong)pb[iOffset + 6] << 48) | ((ulong)pb[iOffset + 7] << 56)); - } - - public static int BytesToInt32(byte[] pb) - { - return (int)BytesToUInt32(pb); - } - - public static int BytesToInt32(byte[] pb, int iOffset) - { - return (int)BytesToUInt32(pb, iOffset); - } - - public static long BytesToInt64(byte[] pb) - { - return (long)BytesToUInt64(pb); - } - - public static long BytesToInt64(byte[] pb, int iOffset) - { - return (long)BytesToUInt64(pb, iOffset); - } - - /// - /// Convert a 16-bit unsigned integer to 2 bytes (little-endian). - /// - public static byte[] UInt16ToBytes(ushort uValue) - { - byte[] pb = new byte[2]; - - unchecked - { - pb[0] = (byte)uValue; - pb[1] = (byte)(uValue >> 8); - } - - return pb; - } - - /// - /// Convert a 32-bit unsigned integer to 4 bytes (little-endian). - /// - public static byte[] UInt32ToBytes(uint uValue) - { - byte[] pb = new byte[4]; - - unchecked - { - pb[0] = (byte)uValue; - pb[1] = (byte)(uValue >> 8); - pb[2] = (byte)(uValue >> 16); - pb[3] = (byte)(uValue >> 24); - } - - return pb; - } - - /// - /// Convert a 32-bit unsigned integer to 4 bytes (little-endian). - /// - public static void UInt32ToBytesEx(uint uValue, byte[] pb, int iOffset) - { - if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } - if((iOffset < 0) || ((iOffset + 3) >= pb.Length)) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("iOffset"); - } - - unchecked - { - pb[iOffset] = (byte)uValue; - pb[iOffset + 1] = (byte)(uValue >> 8); - pb[iOffset + 2] = (byte)(uValue >> 16); - pb[iOffset + 3] = (byte)(uValue >> 24); - } - } - - /// - /// Convert a 64-bit unsigned integer to 8 bytes (little-endian). - /// - public static byte[] UInt64ToBytes(ulong uValue) - { - byte[] pb = new byte[8]; - - unchecked - { - pb[0] = (byte)uValue; - pb[1] = (byte)(uValue >> 8); - pb[2] = (byte)(uValue >> 16); - pb[3] = (byte)(uValue >> 24); - pb[4] = (byte)(uValue >> 32); - pb[5] = (byte)(uValue >> 40); - pb[6] = (byte)(uValue >> 48); - pb[7] = (byte)(uValue >> 56); - } - - return pb; - } - - /// - /// Convert a 64-bit unsigned integer to 8 bytes (little-endian). - /// - public static void UInt64ToBytesEx(ulong uValue, byte[] pb, int iOffset) - { - if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } - if((iOffset < 0) || ((iOffset + 7) >= pb.Length)) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("iOffset"); - } - - unchecked - { - pb[iOffset] = (byte)uValue; - pb[iOffset + 1] = (byte)(uValue >> 8); - pb[iOffset + 2] = (byte)(uValue >> 16); - pb[iOffset + 3] = (byte)(uValue >> 24); - pb[iOffset + 4] = (byte)(uValue >> 32); - pb[iOffset + 5] = (byte)(uValue >> 40); - pb[iOffset + 6] = (byte)(uValue >> 48); - pb[iOffset + 7] = (byte)(uValue >> 56); - } - } - - public static byte[] Int32ToBytes(int iValue) - { - return UInt32ToBytes((uint)iValue); - } - - public static void Int32ToBytesEx(int iValue, byte[] pb, int iOffset) - { - UInt32ToBytesEx((uint)iValue, pb, iOffset); - } - - public static byte[] Int64ToBytes(long lValue) - { - return UInt64ToBytes((ulong)lValue); - } - - public static void Int64ToBytesEx(long lValue, byte[] pb, int iOffset) - { - UInt64ToBytesEx((ulong)lValue, pb, iOffset); - } - - public static uint RotateLeft32(uint u, int nBits) - { - return ((u << nBits) | (u >> (32 - nBits))); - } - - public static uint RotateRight32(uint u, int nBits) - { - return ((u >> nBits) | (u << (32 - nBits))); - } - - public static ulong RotateLeft64(ulong u, int nBits) - { - return ((u << nBits) | (u >> (64 - nBits))); - } - - public static ulong RotateRight64(ulong u, int nBits) - { - return ((u >> nBits) | (u << (64 - nBits))); - } - - public static bool ArraysEqual(byte[] x, byte[] y) - { - // Return false if one of them is null (not comparable)! - if((x == null) || (y == null)) { Debug.Assert(false); return false; } - - if(x.Length != y.Length) return false; - - for(int i = 0; i < x.Length; ++i) - { - if(x[i] != y[i]) return false; - } - - return true; - } - - public static void XorArray(byte[] pbSource, int iSourceOffset, - byte[] pbBuffer, int iBufferOffset, int cb) - { - if(pbSource == null) throw new ArgumentNullException("pbSource"); - if(iSourceOffset < 0) throw new ArgumentOutOfRangeException("iSourceOffset"); - if(pbBuffer == null) throw new ArgumentNullException("pbBuffer"); - if(iBufferOffset < 0) throw new ArgumentOutOfRangeException("iBufferOffset"); - if(cb < 0) throw new ArgumentOutOfRangeException("cb"); - if(iSourceOffset > (pbSource.Length - cb)) - throw new ArgumentOutOfRangeException("cb"); - if(iBufferOffset > (pbBuffer.Length - cb)) - throw new ArgumentOutOfRangeException("cb"); - - for(int i = 0; i < cb; ++i) - pbBuffer[iBufferOffset + i] ^= pbSource[iSourceOffset + i]; - } - - /// - /// Fast hash that can be used e.g. for hash tables. - /// The algorithm might change in the future; do not store - /// the hashes for later use. - /// - public static uint Hash32(byte[] v, int iStart, int iLength) - { - uint u = 0x326F637B; - - if(v == null) { Debug.Assert(false); return u; } - if(iStart < 0) { Debug.Assert(false); return u; } - if(iLength < 0) { Debug.Assert(false); return u; } - - int m = iStart + iLength; - if(m > v.Length) { Debug.Assert(false); return u; } - - for(int i = iStart; i < m; ++i) - { - u ^= m_vSBox[v[i]]; - u *= 3; - } - - return u; - } - - public static void CopyStream(Stream sSource, Stream sTarget) - { - Debug.Assert((sSource != null) && (sTarget != null)); - if(sSource == null) throw new ArgumentNullException("sSource"); - if(sTarget == null) throw new ArgumentNullException("sTarget"); - - const int nBufSize = 4096; - byte[] pbBuf = new byte[nBufSize]; - - while(true) - { - int nRead = sSource.Read(pbBuf, 0, nBufSize); - if(nRead == 0) break; - - sTarget.Write(pbBuf, 0, nRead); - } - - // Do not close any of the streams - } - - public static byte[] Read(Stream s, int nCount) - { - if(s == null) throw new ArgumentNullException("s"); - if(nCount < 0) throw new ArgumentOutOfRangeException("nCount"); - - byte[] pb = new byte[nCount]; - int iOffset = 0; - while(nCount > 0) - { - int iRead = s.Read(pb, iOffset, nCount); - if(iRead == 0) break; - - iOffset += iRead; - nCount -= iRead; - } - - if(iOffset != pb.Length) - { - byte[] pbPart = new byte[iOffset]; - Array.Copy(pb, pbPart, iOffset); - return pbPart; - } - - return pb; - } - - public static void Write(Stream s, byte[] pbData) - { - if(s == null) { Debug.Assert(false); return; } - if(pbData == null) { Debug.Assert(false); return; } - - Debug.Assert(pbData.Length >= 0); - if(pbData.Length > 0) s.Write(pbData, 0, pbData.Length); - } - - public static byte[] Compress(byte[] pbData) - { - if(pbData == null) throw new ArgumentNullException("pbData"); - if(pbData.Length == 0) return pbData; - - byte[] pbCompressed; - using(MemoryStream msSource = new MemoryStream(pbData, false)) - { - using(MemoryStream msCompressed = new MemoryStream()) - { - using(GZipStream gz = new GZipStream(msCompressed, - CompressionMode.Compress)) - { - MemUtil.CopyStream(msSource, gz); - } - - pbCompressed = msCompressed.ToArray(); - } - } - - return pbCompressed; - } - - public static byte[] Decompress(byte[] pbCompressed) - { - if(pbCompressed == null) throw new ArgumentNullException("pbCompressed"); - if(pbCompressed.Length == 0) return pbCompressed; - - byte[] pbData; - using(MemoryStream msData = new MemoryStream()) - { - using(MemoryStream msCompressed = new MemoryStream(pbCompressed, false)) - { - using(GZipStream gz = new GZipStream(msCompressed, - CompressionMode.Decompress)) - { - MemUtil.CopyStream(gz, msData); - } - } - - pbData = msData.ToArray(); - } - - return pbData; - } - - public static int IndexOf(T[] vHaystack, T[] vNeedle) - where T : IEquatable - { - if(vHaystack == null) throw new ArgumentNullException("vHaystack"); - if(vNeedle == null) throw new ArgumentNullException("vNeedle"); - if(vNeedle.Length == 0) return 0; - - for(int i = 0; i <= (vHaystack.Length - vNeedle.Length); ++i) - { - bool bFound = true; - for(int m = 0; m < vNeedle.Length; ++m) - { - if(!vHaystack[i + m].Equals(vNeedle[m])) - { - bFound = false; - break; - } - } - if(bFound) return i; - } - - return -1; - } - - public static T[] Mid(T[] v, int iOffset, int iLength) - { - if(v == null) throw new ArgumentNullException("v"); - if(iOffset < 0) throw new ArgumentOutOfRangeException("iOffset"); - if(iLength < 0) throw new ArgumentOutOfRangeException("iLength"); - if((iOffset + iLength) > v.Length) throw new ArgumentException(); - - T[] r = new T[iLength]; - Array.Copy(v, iOffset, r, 0, iLength); - return r; - } - - public static IEnumerable Union(IEnumerable a, IEnumerable b, - IEqualityComparer cmp) - { - if(a == null) throw new ArgumentNullException("a"); - if(b == null) throw new ArgumentNullException("b"); - - Dictionary d = ((cmp != null) ? - (new Dictionary(cmp)) : (new Dictionary())); - - foreach(T ta in a) - { - if(d.ContainsKey(ta)) continue; // Prevent duplicates - - d[ta] = true; - yield return ta; - } - - foreach(T tb in b) - { - if(d.ContainsKey(tb)) continue; // Prevent duplicates - - d[tb] = true; - yield return tb; - } - - yield break; - } - - public static IEnumerable Intersect(IEnumerable a, IEnumerable b, - IEqualityComparer cmp) - { - if(a == null) throw new ArgumentNullException("a"); - if(b == null) throw new ArgumentNullException("b"); - - Dictionary d = ((cmp != null) ? - (new Dictionary(cmp)) : (new Dictionary())); - - foreach(T tb in b) { d[tb] = true; } - - foreach(T ta in a) - { - if(d.Remove(ta)) // Prevent duplicates - yield return ta; - } - - yield break; - } - - public static IEnumerable Except(IEnumerable a, IEnumerable b, - IEqualityComparer cmp) - { - if(a == null) throw new ArgumentNullException("a"); - if(b == null) throw new ArgumentNullException("b"); - - Dictionary d = ((cmp != null) ? - (new Dictionary(cmp)) : (new Dictionary())); - - foreach(T tb in b) { d[tb] = true; } - - foreach(T ta in a) - { - if(d.ContainsKey(ta)) continue; - - d[ta] = true; // Prevent duplicates - yield return ta; - } - - yield break; - } - } - - internal sealed class ArrayHelperEx : IEqualityComparer, IComparer - where T : IEquatable, IComparable - { - public int GetHashCode(T[] obj) - { - if(obj == null) throw new ArgumentNullException("obj"); - - uint h = 0xC17962B7U; - unchecked - { - int n = obj.Length; - for(int i = 0; i < n; ++i) - { - h += (uint)obj[i].GetHashCode(); - h = MemUtil.RotateLeft32(h * 0x5FC34C67U, 13); - } - } - - return (int)h; - } - - /* internal ulong GetHashCodeEx(T[] obj) - { - if(obj == null) throw new ArgumentNullException("obj"); - - ulong h = 0x207CAC8E509A3FC9UL; - unchecked - { - int n = obj.Length; - for(int i = 0; i < n; ++i) - { - h += (uint)obj[i].GetHashCode(); - h = MemUtil.RotateLeft64(h * 0x54724D3EA2860CBBUL, 29); - } - } - - return h; - } */ - - public bool Equals(T[] x, T[] y) - { - if(object.ReferenceEquals(x, y)) return true; - if((x == null) || (y == null)) return false; - - int n = x.Length; - if(n != y.Length) return false; - - for(int i = 0; i < n; ++i) - { - if(!x[i].Equals(y[i])) return false; - } - - return true; - } - - public int Compare(T[] x, T[] y) - { - if(object.ReferenceEquals(x, y)) return 0; - if(x == null) return -1; - if(y == null) return 1; - - int n = x.Length, m = y.Length; - if(n != m) return ((n < m) ? -1 : 1); - - for(int i = 0; i < n; ++i) - { - T tX = x[i], tY = y[i]; - if(!tX.Equals(tY)) return tX.CompareTo(tY); - } - - return 0; - } - } -} diff --git a/ModernKeePassLib/Utility/MessageService.cs b/ModernKeePassLib/Utility/MessageService.cs deleted file mode 100644 index a8a0d4c..0000000 --- a/ModernKeePassLib/Utility/MessageService.cs +++ /dev/null @@ -1,459 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Text; - -#if !ModernKeePassLib -using System.Windows.Forms; -#endif - -using ModernKeePassLib.Resources; -using ModernKeePassLib.Serialization; - -namespace ModernKeePassLib.Utility -{ - public sealed class MessageServiceEventArgs : EventArgs - { -#if !ModernKeePassLib - private string m_strTitle = string.Empty; - private string m_strText = string.Empty; - private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK; - private MessageBoxIcon m_msgIcon = MessageBoxIcon.None; - - public string Title { get { return m_strTitle; } } - public string Text { get { return m_strText; } } - public MessageBoxButtons Buttons { get { return m_msgButtons; } } - public MessageBoxIcon Icon { get { return m_msgIcon; } } - - public MessageServiceEventArgs() { } - - public MessageServiceEventArgs(string strTitle, string strText, - MessageBoxButtons msgButtons, MessageBoxIcon msgIcon) - { - m_strTitle = (strTitle ?? string.Empty); - m_strText = (strText ?? string.Empty); - m_msgButtons = msgButtons; - m_msgIcon = msgIcon; - } -#endif - } - - public static class MessageService - { - private static volatile uint m_uCurrentMessageCount = 0; - -#if !ModernKeePassLib -#if !KeePassLibSD - private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Information; - private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Warning; - private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Error; - - private const MessageBoxOptions m_mboRtl = (MessageBoxOptions.RtlReading | - MessageBoxOptions.RightAlign); -#else - private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Asterisk; - private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Exclamation; - private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Hand; -#endif - private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question; -#endif - public static string NewLine - { -#if !KeePassLibSD - get { return Environment.NewLine; } -#else - get { return "\r\n"; } -#endif - } - - public static string NewParagraph - { -#if !KeePassLibSD - get { return Environment.NewLine + Environment.NewLine; } -#else - get { return "\r\n\r\n"; } -#endif - } - - public static uint CurrentMessageCount - { - get { return m_uCurrentMessageCount; } - } - -#if !KeePassUAP - public static event EventHandler MessageShowing; -#endif - - private static string ObjectsToMessage(object[] vLines) - { - return ObjectsToMessage(vLines, false); - } - - private static string ObjectsToMessage(object[] vLines, bool bFullExceptions) - { - if(vLines == null) return string.Empty; - - string strNewPara = Environment.NewLine; - - StringBuilder sbText = new StringBuilder(); - bool bSeparator = false; - - foreach(object obj in vLines) - { - if(obj == null) continue; - - string strAppend = null; - - Exception exObj = (obj as Exception); - string strObj = (obj as string); -#if (!KeePassLibSD && !ModernKeePassLib) - StringCollection scObj = (obj as StringCollection); -#endif - - if(exObj != null) - { - if(bFullExceptions) - strAppend = StrUtil.FormatException(exObj); - else if(!string.IsNullOrEmpty(exObj.Message)) - strAppend = exObj.Message; - } -#if (!KeePassLibSD && !ModernKeePassLib) - else if(scObj != null) - { - StringBuilder sb = new StringBuilder(); - foreach(string strCollLine in scObj) - { - if(sb.Length > 0) sb.AppendLine(); - sb.Append(strCollLine.TrimEnd()); - } - strAppend = sb.ToString(); - } -#endif - else if (strObj != null) - strAppend = strObj; - else - strAppend = obj.ToString(); - - if(!string.IsNullOrEmpty(strAppend)) - { - if(bSeparator) sbText.Append(strNewPara); - else bSeparator = true; - - sbText.Append(strAppend); - } - } - - return sbText.ToString(); - } - -#if (!KeePassLibSD && !ModernKeePassLib) - internal static Form GetTopForm() - { - FormCollection fc = Application.OpenForms; - if((fc == null) || (fc.Count == 0)) return null; - - return fc[fc.Count - 1]; - } -#endif - -#if !ModernKeePassLib - internal static DialogResult SafeShowMessageBox(string strText, string strTitle, - MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb) - { -#if (KeePassLibSD || KeePassRT) - return MessageBox.Show(strText, strTitle, mb, mi, mdb); -#else - IWin32Window wnd = null; - try - { - Form f = GetTopForm(); - if((f != null) && f.InvokeRequired) - return (DialogResult)f.Invoke(new SafeShowMessageBoxInternalDelegate( - SafeShowMessageBoxInternal), f, strText, strTitle, mb, mi, mdb); - else wnd = f; - } - catch(Exception) { Debug.Assert(false); } - - if(wnd == null) - { - if(StrUtil.RightToLeft) - return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl); - return MessageBox.Show(strText, strTitle, mb, mi, mdb); - } - - try - { - if(StrUtil.RightToLeft) - return MessageBox.Show(wnd, strText, strTitle, mb, mi, mdb, m_mboRtl); - return MessageBox.Show(wnd, strText, strTitle, mb, mi, mdb); - } - catch(Exception) { Debug.Assert(false); } - - if(StrUtil.RightToLeft) - return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl); - return MessageBox.Show(strText, strTitle, mb, mi, mdb); -#endif - } - -#if (!KeePassLibSD && !KeePassRT) - internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent, - string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi, - MessageBoxDefaultButton mdb); - - internal static DialogResult SafeShowMessageBoxInternal(IWin32Window iParent, - string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi, - MessageBoxDefaultButton mdb) - { - if(StrUtil.RightToLeft) - return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb, m_mboRtl); - return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb); - } -#endif - - public static void ShowInfo(params object[] vLines) - { - ShowInfoEx(null, vLines); - } - - public static void ShowInfoEx(string strTitle, params object[] vLines) - { - ++m_uCurrentMessageCount; - - strTitle = (strTitle ?? PwDefs.ShortProductName); - string strText = ObjectsToMessage(vLines); - - if(MessageService.MessageShowing != null) - MessageService.MessageShowing(null, new MessageServiceEventArgs( - strTitle, strText, MessageBoxButtons.OK, m_mbiInfo)); - - SafeShowMessageBox(strText, strTitle, MessageBoxButtons.OK, m_mbiInfo, - MessageBoxDefaultButton.Button1); - - --m_uCurrentMessageCount; - } - - public static void ShowWarning(params object[] vLines) - { - ShowWarningPriv(vLines, false); - } - - internal static void ShowWarningExcp(params object[] vLines) - { - ShowWarningPriv(vLines, true); - } - - private static void ShowWarningPriv(object[] vLines, bool bFullExceptions) - { - ++m_uCurrentMessageCount; - - string strTitle = PwDefs.ShortProductName; - string strText = ObjectsToMessage(vLines, bFullExceptions); - - if(MessageService.MessageShowing != null) - MessageService.MessageShowing(null, new MessageServiceEventArgs( - strTitle, strText, MessageBoxButtons.OK, m_mbiWarning)); - - SafeShowMessageBox(strText, strTitle, MessageBoxButtons.OK, m_mbiWarning, - MessageBoxDefaultButton.Button1); - - --m_uCurrentMessageCount; - } - - public static void ShowFatal(params object[] vLines) - { - ++m_uCurrentMessageCount; - - string strTitle = PwDefs.ShortProductName + @" - " + KLRes.FatalError; - string strText = KLRes.FatalErrorText + Environment.NewLine + - KLRes.ErrorInClipboard + Environment.NewLine + - // Please send it to the KeePass developers. - // KLRes.ErrorFeedbackRequest + Environment.NewLine + - ObjectsToMessage(vLines); - - try - { - string strDetails = ObjectsToMessage(vLines, true); - -#if KeePassLibSD - Clipboard.SetDataObject(strDetails); -#else - Clipboard.Clear(); - Clipboard.SetText(strDetails); -#endif - } - catch(Exception) { Debug.Assert(false); } - - if(MessageService.MessageShowing != null) - MessageService.MessageShowing(null, new MessageServiceEventArgs( - strTitle, strText, MessageBoxButtons.OK, m_mbiFatal)); - - SafeShowMessageBox(strText, strTitle, MessageBoxButtons.OK, m_mbiFatal, - MessageBoxDefaultButton.Button1); - - --m_uCurrentMessageCount; - } - - public static DialogResult Ask(string strText, string strTitle, - MessageBoxButtons mbb) - { - ++m_uCurrentMessageCount; - - string strTextEx = (strText ?? string.Empty); - string strTitleEx = (strTitle ?? PwDefs.ShortProductName); - - if(MessageService.MessageShowing != null) - MessageService.MessageShowing(null, new MessageServiceEventArgs( - strTitleEx, strTextEx, mbb, m_mbiQuestion)); - - DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, mbb, - m_mbiQuestion, MessageBoxDefaultButton.Button1); - - --m_uCurrentMessageCount; - return dr; - } - - public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes, - MessageBoxIcon mbi) - { - ++m_uCurrentMessageCount; - - string strTextEx = (strText ?? string.Empty); - string strTitleEx = (strTitle ?? PwDefs.ShortProductName); - - if(MessageService.MessageShowing != null) - MessageService.MessageShowing(null, new MessageServiceEventArgs( - strTitleEx, strTextEx, MessageBoxButtons.YesNo, mbi)); - - DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, - MessageBoxButtons.YesNo, mbi, bDefaultToYes ? - MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2); - - --m_uCurrentMessageCount; - return (dr == DialogResult.Yes); - } - - public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes) - { - return AskYesNo(strText, strTitle, bDefaultToYes, m_mbiQuestion); - } - - public static bool AskYesNo(string strText, string strTitle) - { - return AskYesNo(strText, strTitle, true, m_mbiQuestion); - } - - public static bool AskYesNo(string strText) - { - return AskYesNo(strText, null, true, m_mbiQuestion); - } - - public static void ShowLoadWarning(string strFilePath, Exception ex) - { - ShowLoadWarning(strFilePath, ex, false); - } - - public static void ShowLoadWarning(string strFilePath, Exception ex, - bool bFullException) - { - ShowWarning(GetLoadWarningMessage(strFilePath, ex, bFullException)); - } - - public static void ShowLoadWarning(IOConnectionInfo ioConnection, Exception ex) - { - if(ioConnection != null) - ShowLoadWarning(ioConnection.GetDisplayName(), ex, false); - else ShowWarning(ex); - } - - public static void ShowSaveWarning(string strFilePath, Exception ex, - bool bCorruptionWarning) - { - FileLockException fl = (ex as FileLockException); - if(fl != null) - { - ShowWarning(fl.Message); - return; - } - - string str = GetSaveWarningMessage(strFilePath, ex, bCorruptionWarning); - ShowWarning(str); - } - - public static void ShowSaveWarning(IOConnectionInfo ioConnection, Exception ex, - bool bCorruptionWarning) - { - if(ioConnection != null) - ShowSaveWarning(ioConnection.GetDisplayName(), ex, bCorruptionWarning); - else ShowWarning(ex); - } -#endif // !KeePassUAP - - internal static string GetLoadWarningMessage(string strFilePath, - Exception ex, bool bFullException) - { - string str = string.Empty; - - if(!string.IsNullOrEmpty(strFilePath)) - str += strFilePath + Environment.NewLine; - - str += KLRes.FileLoadFailed; - - if((ex != null) && !string.IsNullOrEmpty(ex.Message)) - { - str += Environment.NewLine; - if(!bFullException) str += ex.Message; - else str += ObjectsToMessage(new object[] { ex }, true); - } - - return str; - } - - internal static string GetSaveWarningMessage(string strFilePath, - Exception ex, bool bCorruptionWarning) - { - string str = string.Empty; - if(!string.IsNullOrEmpty(strFilePath)) - str += strFilePath + Environment.NewLine; - - str += KLRes.FileSaveFailed; - - if((ex != null) && !string.IsNullOrEmpty(ex.Message)) - str += Environment.NewLine + ex.Message; - - if(bCorruptionWarning) - str += Environment.NewLine + KLRes.FileSaveCorruptionWarning; - - return str; - } - - public static void ExternalIncrementMessageCount() - { - ++m_uCurrentMessageCount; - } - - public static void ExternalDecrementMessageCount() - { - --m_uCurrentMessageCount; - } - } -} diff --git a/ModernKeePassLib/Utility/MonoWorkaround.PCL.cs b/ModernKeePassLib/Utility/MonoWorkaround.PCL.cs deleted file mode 100644 index f47b062..0000000 --- a/ModernKeePassLib/Utility/MonoWorkaround.PCL.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ModernKeePassLib.Utility -{ - public static class MonoWorkarounds - { - public static bool IsRequired(int i) - { - return false; - } - } -} diff --git a/ModernKeePassLib/Utility/MonoWorkarounds.cs b/ModernKeePassLib/Utility/MonoWorkarounds.cs deleted file mode 100644 index 97b4dfd..0000000 --- a/ModernKeePassLib/Utility/MonoWorkarounds.cs +++ /dev/null @@ -1,597 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#if DEBUG -// #define DEBUG_BREAKONFAIL -#endif - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Text; -using System.Threading; -using System.Xml; - -#if !KeePassUAP -using System.Windows.Forms; -#endif - -using ModernKeePassLib.Native; - -namespace ModernKeePassLib.Utility -{ - public static class MonoWorkarounds - { - private const string AppXDoTool = "xdotool"; - - private static Dictionary g_dForceReq = new Dictionary(); - private static Thread g_thFixClip = null; - // private static Predicate g_fOwnWindow = null; - -#if DEBUG_BREAKONFAIL - private static DebugBreakTraceListener g_tlBreak = null; -#endif - - private static bool? g_bReq = null; - public static bool IsRequired() - { - if(!g_bReq.HasValue) g_bReq = NativeLib.IsUnix(); - return g_bReq.Value; - } - - // 1219: - // Mono prepends byte order mark (BOM) to StdIn. - // https://sourceforge.net/p/keepass/bugs/1219/ - // 1245: - // Key events not raised while Alt is down, and nav keys out of order. - // https://sourceforge.net/p/keepass/bugs/1245/ - // 1254: - // NumericUpDown bug: text is drawn below up/down buttons. - // https://sourceforge.net/p/keepass/bugs/1254/ - // 1354: - // Finalizer of NotifyIcon throws on Unity. - // See also 1574. - // https://sourceforge.net/p/keepass/bugs/1354/ - // 1358: - // FileDialog crashes when ~/.recently-used is invalid. - // https://sourceforge.net/p/keepass/bugs/1358/ - // 1366: - // Drawing bug when scrolling a RichTextBox. - // https://sourceforge.net/p/keepass/bugs/1366/ - // 1378: - // Mono doesn't implement Microsoft.Win32.SystemEvents events. - // https://sourceforge.net/p/keepass/bugs/1378/ - // https://github.com/mono/mono/blob/master/mcs/class/System/Microsoft.Win32/SystemEvents.cs - // 1418: - // Minimizing a form while loading it doesn't work. - // https://sourceforge.net/p/keepass/bugs/1418/ - // 1468: - // Use LibGCrypt for AES-KDF, because Mono's implementations - // of RijndaelManaged and AesCryptoServiceProvider are slow. - // https://sourceforge.net/p/keepass/bugs/1468/ - // 1527: - // Timer causes 100% CPU load. - // https://sourceforge.net/p/keepass/bugs/1527/ - // 1530: - // Mono's clipboard functions don't work properly. - // https://sourceforge.net/p/keepass/bugs/1530/ - // 1574: - // Finalizer of NotifyIcon throws on Mac OS X. - // See also 1354. - // https://sourceforge.net/p/keepass/bugs/1574/ - // 1632: - // RichTextBox rendering bug for bold/italic text. - // https://sourceforge.net/p/keepass/bugs/1632/ - // 1690: - // Removing items from a list view doesn't work properly. - // https://sourceforge.net/p/keepass/bugs/1690/ - // 1716: - // 'Always on Top' doesn't work properly on the Cinnamon desktop. - // https://sourceforge.net/p/keepass/bugs/1716/ - // 2139: - // Shortcut keys are ignored. - // https://sourceforge.net/p/keepass/feature-requests/2139/ - // 2140: - // Explicit control focusing is ignored. - // https://sourceforge.net/p/keepass/feature-requests/2140/ - // 5795: - // Text in input field is incomplete. - // https://bugzilla.xamarin.com/show_bug.cgi?id=5795 - // https://sourceforge.net/p/keepass/discussion/329220/thread/d23dc88b/ - // 10163: - // WebRequest GetResponse call missing, breaks WebDAV due to no PUT. - // https://bugzilla.xamarin.com/show_bug.cgi?id=10163 - // https://sourceforge.net/p/keepass/bugs/1117/ - // https://sourceforge.net/p/keepass/discussion/329221/thread/9422258c/ - // https://github.com/mono/mono/commit/8e67b8c2fc7cb66bff7816ebf7c1039fb8cfc43b - // https://bugzilla.xamarin.com/show_bug.cgi?id=1512 - // https://sourceforge.net/p/keepass/patches/89/ - // 12525: - // PictureBox not rendered when bitmap height >= control height. - // https://bugzilla.xamarin.com/show_bug.cgi?id=12525 - // https://sourceforge.net/p/keepass/discussion/329220/thread/54f61e9a/ - // 100001: - // Control locations/sizes are invalid/unexpected. - // [NoRef] - // 373134: - // Control.InvokeRequired doesn't always return the correct value. - // https://bugzilla.novell.com/show_bug.cgi?id=373134 - // 586901: - // RichTextBox doesn't handle Unicode string correctly. - // https://bugzilla.novell.com/show_bug.cgi?id=586901 - // 620618: - // ListView column headers not drawn. - // https://bugzilla.novell.com/show_bug.cgi?id=620618 - // 649266: - // Calling Control.Hide doesn't remove the application from taskbar. - // https://bugzilla.novell.com/show_bug.cgi?id=649266 - // 686017: - // Minimum sizes must be enforced. - // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=686017 - // 801414: - // Mono recreates the main window incorrectly. - // https://bugs.launchpad.net/ubuntu/+source/keepass2/+bug/801414 - // 891029: - // Increase tab control height and don't use images on tabs. - // https://sourceforge.net/projects/keepass/forums/forum/329221/topic/4519750 - // https://bugs.launchpad.net/ubuntu/+source/keepass2/+bug/891029 - // https://sourceforge.net/p/keepass/bugs/1256/ - // https://sourceforge.net/p/keepass/bugs/1566/ - // https://sourceforge.net/p/keepass/bugs/1634/ - // 836428016: - // ListView group header selection unsupported. - // https://sourceforge.net/p/keepass/discussion/329221/thread/31dae0f0/ - // 2449941153: - // RichTextBox doesn't properly escape '}' when generating RTF data. - // https://sourceforge.net/p/keepass/discussion/329221/thread/920722a1/ - // 3471228285: - // Mono requires command line arguments to be encoded differently. - // https://sourceforge.net/p/keepass/discussion/329221/thread/cee6bd7d/ - // 3574233558: - // Problems with minimizing windows, no content rendered. - // https://sourceforge.net/p/keepass/discussion/329220/thread/d50a79d6/ - public static bool IsRequired(uint uBugID) - { - if(!MonoWorkarounds.IsRequired()) return false; - - bool bForce; - if(g_dForceReq.TryGetValue(uBugID, out bForce)) return bForce; - - ulong v = NativeLib.MonoVersion; - if(v != 0) - { - if(uBugID == 10163) - return (v >= 0x0002000B00000000UL); // >= 2.11 - } - - return true; - } - - internal static void SetEnabled(string strIDs, bool bEnabled) - { - if(string.IsNullOrEmpty(strIDs)) return; - - string[] vIDs = strIDs.Split(new char[] { ',' }); - foreach(string strID in vIDs) - { - if(string.IsNullOrEmpty(strID)) continue; - - uint uID; - if(StrUtil.TryParseUInt(strID.Trim(), out uID)) - g_dForceReq[uID] = bEnabled; - } - } - - internal static void Initialize() - { - Terminate(); - - // g_fOwnWindow = fOwnWindow; - - if(IsRequired(1530)) - { - try - { - ThreadStart ts = new ThreadStart(MonoWorkarounds.FixClipThread); - g_thFixClip = new Thread(ts); - g_thFixClip.Start(); - } - catch(Exception) { Debug.Assert(false); } - } - -#if DEBUG_BREAKONFAIL - if(IsRequired() && (g_tlBreak == null)) - { - g_tlBreak = new DebugBreakTraceListener(); - Debug.Listeners.Add(g_tlBreak); - } -#endif - } - - internal static void Terminate() - { - if(g_thFixClip != null) - { - try { g_thFixClip.Abort(); } - catch(Exception) { Debug.Assert(false); } - - g_thFixClip = null; - } - } - - private static void FixClipThread() - { - try - { -#if !KeePassUAP - const int msDelay = 250; - - string strTest = ClipboardU.GetText(); - if(strTest == null) return; // No clipboard support - - // Without XDoTool, the workaround would be applied to - // all applications, which may corrupt the clipboard - // when it doesn't contain simple text only; - // https://sourceforge.net/p/keepass/bugs/1603/#a113 - strTest = (NativeLib.RunConsoleApp(AppXDoTool, - "help") ?? string.Empty).Trim(); - if(strTest.Length == 0) return; - - Thread.Sleep(msDelay); - - string strLast = null; - while(true) - { - string str = ClipboardU.GetText(); - if(str == null) { Debug.Assert(false); } - else if(str != strLast) - { - if(NeedClipboardWorkaround()) - ClipboardU.SetText(str, true); - - strLast = str; - } - - Thread.Sleep(msDelay); - } -#endif - } - catch(ThreadAbortException) - { - try { Thread.ResetAbort(); } - catch(Exception) { Debug.Assert(false); } - } - catch(Exception) { Debug.Assert(false); } - finally { g_thFixClip = null; } - } - -#if !KeePassUAP - private static bool NeedClipboardWorkaround() - { - try - { - string strHandle = (NativeLib.RunConsoleApp(AppXDoTool, - "getactivewindow") ?? string.Empty).Trim(); - if(strHandle.Length == 0) { Debug.Assert(false); return false; } - - // IntPtr h = new IntPtr(long.Parse(strHandle)); - long.Parse(strHandle); // Validate - - // Detection of own windows based on Form.Handle - // comparisons doesn't work reliably (Mono's handles - // are usually off by 1) - // Predicate fOwnWindow = g_fOwnWindow; - // if(fOwnWindow != null) - // { - // if(fOwnWindow(h)) return true; - // } - // else { Debug.Assert(false); } - - string strWmClass = (NativeLib.RunConsoleApp("xprop", - "-id " + strHandle + " WM_CLASS") ?? string.Empty); - - if(strWmClass.IndexOf("\"" + PwDefs.ResClass + "\"", - StrUtil.CaseIgnoreCmp) >= 0) return true; - if(strWmClass.IndexOf("\"Remmina\"", - StrUtil.CaseIgnoreCmp) >= 0) return true; - } - catch(ThreadAbortException) { throw; } - catch(Exception) { Debug.Assert(false); } - - return false; - } - - public static void ApplyTo(Form f) - { - if(!MonoWorkarounds.IsRequired()) return; - if(f == null) { Debug.Assert(false); return; } - -#if (!KeePassLibSD && !KeePassRT) - f.HandleCreated += MonoWorkarounds.OnFormHandleCreated; - SetWmClass(f); - - ApplyToControlsRec(f.Controls, f, MonoWorkarounds.ApplyToControl); -#endif - } - - public static void Release(Form f) - { - if(!MonoWorkarounds.IsRequired()) return; - if(f == null) { Debug.Assert(false); return; } - -#if (!KeePassLibSD && !KeePassRT) - f.HandleCreated -= MonoWorkarounds.OnFormHandleCreated; - - ApplyToControlsRec(f.Controls, f, MonoWorkarounds.ReleaseControl); -#endif - } - -#if (!KeePassLibSD && !KeePassRT) - private delegate void MwaControlHandler(Control c, Form fContext); - - private static void ApplyToControlsRec(Control.ControlCollection cc, - Form fContext, MwaControlHandler fn) - { - if(cc == null) { Debug.Assert(false); return; } - - foreach(Control c in cc) - { - fn(c, fContext); - ApplyToControlsRec(c.Controls, fContext, fn); - } - } - - private static void ApplyToControl(Control c, Form fContext) - { - Button btn = (c as Button); - if(btn != null) ApplyToButton(btn, fContext); - - NumericUpDown nc = (c as NumericUpDown); - if((nc != null) && MonoWorkarounds.IsRequired(1254)) - { - if(nc.TextAlign == HorizontalAlignment.Right) - nc.TextAlign = HorizontalAlignment.Left; - } - } - - private sealed class MwaHandlerInfo - { - private readonly Delegate m_fnOrg; // May be null - public Delegate FunctionOriginal - { - get { return m_fnOrg; } - } - - private readonly Delegate m_fnOvr; - public Delegate FunctionOverride - { - get { return m_fnOvr; } - } - - private readonly DialogResult m_dr; - public DialogResult Result - { - get { return m_dr; } - } - - private readonly Form m_fContext; - public Form FormContext - { - get { return m_fContext; } - } - - public MwaHandlerInfo(Delegate fnOrg, Delegate fnOvr, DialogResult dr, - Form fContext) - { - m_fnOrg = fnOrg; - m_fnOvr = fnOvr; - m_dr = dr; - m_fContext = fContext; - } - } - - private static EventHandlerList GetEventHandlers(Component c, - out object objClickEvent) - { - FieldInfo fi = typeof(Control).GetField("ClickEvent", // Mono - BindingFlags.Static | BindingFlags.NonPublic); - if(fi == null) - fi = typeof(Control).GetField("EventClick", // .NET - BindingFlags.Static | BindingFlags.NonPublic); - if(fi == null) { Debug.Assert(false); objClickEvent = null; return null; } - - objClickEvent = fi.GetValue(null); - if(objClickEvent == null) { Debug.Assert(false); return null; } - - PropertyInfo pi = typeof(Component).GetProperty("Events", - BindingFlags.Instance | BindingFlags.NonPublic); - return (pi.GetValue(c, null) as EventHandlerList); - } - - private static Dictionary m_dictHandlers = - new Dictionary(); - private static void ApplyToButton(Button btn, Form fContext) - { - DialogResult dr = btn.DialogResult; - if(dr == DialogResult.None) return; // No workaround required - - object objClickEvent; - EventHandlerList ehl = GetEventHandlers(btn, out objClickEvent); - if(ehl == null) { Debug.Assert(false); return; } - Delegate fnClick = ehl[objClickEvent]; // May be null - - EventHandler fnOvr = new EventHandler(MonoWorkarounds.OnButtonClick); - m_dictHandlers[btn] = new MwaHandlerInfo(fnClick, fnOvr, dr, fContext); - - btn.DialogResult = DialogResult.None; - if(fnClick != null) ehl.RemoveHandler(objClickEvent, fnClick); - ehl[objClickEvent] = fnOvr; - } - - private static void ReleaseControl(Control c, Form fContext) - { - Button btn = (c as Button); - if(btn != null) ReleaseButton(btn, fContext); - } - - private static void ReleaseButton(Button btn, Form fContext) - { - MwaHandlerInfo hi; - m_dictHandlers.TryGetValue(btn, out hi); - if(hi == null) return; - - object objClickEvent; - EventHandlerList ehl = GetEventHandlers(btn, out objClickEvent); - if(ehl == null) { Debug.Assert(false); return; } - - ehl.RemoveHandler(objClickEvent, hi.FunctionOverride); - if(hi.FunctionOriginal != null) - ehl[objClickEvent] = hi.FunctionOriginal; - - btn.DialogResult = hi.Result; - m_dictHandlers.Remove(btn); - } - - private static void OnButtonClick(object sender, EventArgs e) - { - Button btn = (sender as Button); - if(btn == null) { Debug.Assert(false); return; } - - MwaHandlerInfo hi; - m_dictHandlers.TryGetValue(btn, out hi); - if(hi == null) { Debug.Assert(false); return; } - - Form f = hi.FormContext; - - // Set current dialog result by setting the form's private - // variable; the DialogResult property can't be used, - // because it raises close events - FieldInfo fiRes = typeof(Form).GetField("dialog_result", - BindingFlags.Instance | BindingFlags.NonPublic); - if(fiRes == null) { Debug.Assert(false); return; } - if(f != null) fiRes.SetValue(f, hi.Result); - - if(hi.FunctionOriginal != null) - hi.FunctionOriginal.Method.Invoke(hi.FunctionOriginal.Target, - new object[] { btn, e }); - - // Raise close events, if the click event handler hasn't - // reset the dialog result - if((f != null) && (f.DialogResult == hi.Result)) - f.DialogResult = hi.Result; // Raises close events - } - - private static void SetWmClass(Form f) - { - NativeMethods.SetWmClass(f, PwDefs.UnixName, PwDefs.ResClass); - } - - private static void OnFormHandleCreated(object sender, EventArgs e) - { - Form f = (sender as Form); - if(f == null) { Debug.Assert(false); return; } - - if(!f.IsHandleCreated) return; // Prevent infinite loop - - SetWmClass(f); - } - - /// - /// Set the value of the private shown_raised member - /// variable of a form. - /// - /// Previous shown_raised value. - internal static bool ExchangeFormShownRaised(Form f, bool bNewValue) - { - if(f == null) { Debug.Assert(false); return true; } - - try - { - FieldInfo fi = typeof(Form).GetField("shown_raised", - BindingFlags.Instance | BindingFlags.NonPublic); - if(fi == null) { Debug.Assert(false); return true; } - - bool bPrevious = (bool)fi.GetValue(f); - - fi.SetValue(f, bNewValue); - - return bPrevious; - } - catch(Exception) { Debug.Assert(false); } - - return true; - } -#endif - - /// - /// Ensure that the file ~/.recently-used is valid (in order to - /// prevent Mono's FileDialog from crashing). - /// - internal static void EnsureRecentlyUsedValid() - { - if(!MonoWorkarounds.IsRequired(1358)) return; - - try - { - string strFile = Environment.GetFolderPath( - Environment.SpecialFolder.Personal); - strFile = UrlUtil.EnsureTerminatingSeparator(strFile, false); - strFile += ".recently-used"; - - if(File.Exists(strFile)) - { - try - { - // Mono's WriteRecentlyUsedFiles method also loads the - // XML file using XmlDocument - XmlDocument xd = XmlUtilEx.CreateXmlDocument(); - xd.Load(strFile); - } - catch(Exception) // The XML file is invalid - { - File.Delete(strFile); - } - } - } - catch(Exception) { Debug.Assert(false); } - } -#endif // !KeePassUAP - -#if DEBUG_BREAKONFAIL - private sealed class DebugBreakTraceListener : TraceListener - { - public override void Fail(string message) - { - Debugger.Break(); - } - - public override void Fail(string message, string detailMessage) - { - Debugger.Break(); - } - - public override void Write(string message) { } - public override void WriteLine(string message) { } - } -#endif - } -} diff --git a/ModernKeePassLib/Utility/StrUtil.cs b/ModernKeePassLib/Utility/StrUtil.cs deleted file mode 100644 index b40dca0..0000000 --- a/ModernKeePassLib/Utility/StrUtil.cs +++ /dev/null @@ -1,1818 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Text; -using System.Text.RegularExpressions; - -using System.Drawing; -#if ModernKeePassLib -using ModernKeePassLib.Cryptography; -#else -using System.Security.Cryptography; -#endif - -using ModernKeePassLib.Collections; -using ModernKeePassLib.Cryptography.PasswordGenerator; -using ModernKeePassLib.Native; -using ModernKeePassLib.Security; - -namespace ModernKeePassLib.Utility -{ - /// - /// Character stream class. - /// - public sealed class CharStream - { - private string m_strString = string.Empty; - private int m_nPos = 0; - - public CharStream(string str) - { - Debug.Assert(str != null); - if(str == null) throw new ArgumentNullException("str"); - - m_strString = str; - } - - public void Seek(SeekOrigin org, int nSeek) - { - if(org == SeekOrigin.Begin) - m_nPos = nSeek; - else if(org == SeekOrigin.Current) - m_nPos += nSeek; - else if(org == SeekOrigin.End) - m_nPos = m_strString.Length + nSeek; - } - - public char ReadChar() - { - if(m_nPos < 0) return char.MinValue; - if(m_nPos >= m_strString.Length) return char.MinValue; - - char chRet = m_strString[m_nPos]; - ++m_nPos; - return chRet; - } - - public char ReadChar(bool bSkipWhiteSpace) - { - if(bSkipWhiteSpace == false) return ReadChar(); - - while(true) - { - char ch = ReadChar(); - - if((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n')) - return ch; - } - } - - public char PeekChar() - { - if(m_nPos < 0) return char.MinValue; - if(m_nPos >= m_strString.Length) return char.MinValue; - - return m_strString[m_nPos]; - } - - public char PeekChar(bool bSkipWhiteSpace) - { - if(bSkipWhiteSpace == false) return PeekChar(); - - int iIndex = m_nPos; - while(true) - { - if(iIndex < 0) return char.MinValue; - if(iIndex >= m_strString.Length) return char.MinValue; - - char ch = m_strString[iIndex]; - - if((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n')) - return ch; - - ++iIndex; - } - } - } - - public enum StrEncodingType - { - Unknown = 0, - Default, - Ascii, - Utf7, - Utf8, - Utf16LE, - Utf16BE, - Utf32LE, - Utf32BE - } - - public sealed class StrEncodingInfo - { - private readonly StrEncodingType m_type; - public StrEncodingType Type - { - get { return m_type; } - } - - private readonly string m_strName; - public string Name - { - get { return m_strName; } - } - - private readonly Encoding m_enc; - public Encoding Encoding - { - get { return m_enc; } - } - - private readonly uint m_cbCodePoint; - /// - /// Size of a character in bytes. - /// - public uint CodePointSize - { - get { return m_cbCodePoint; } - } - - private readonly byte[] m_vSig; - /// - /// Start signature of the text (byte order mark). - /// May be null or empty, if no signature is known. - /// - public byte[] StartSignature - { - get { return m_vSig; } - } - - public StrEncodingInfo(StrEncodingType t, string strName, Encoding enc, - uint cbCodePoint, byte[] vStartSig) - { - if(strName == null) throw new ArgumentNullException("strName"); - if(enc == null) throw new ArgumentNullException("enc"); - if(cbCodePoint <= 0) throw new ArgumentOutOfRangeException("cbCodePoint"); - - m_type = t; - m_strName = strName; - m_enc = enc; - m_cbCodePoint = cbCodePoint; - m_vSig = vStartSig; - } - } - - /// - /// A class containing various string helper methods. - /// - public static class StrUtil - { - public const StringComparison CaseIgnoreCmp = StringComparison.OrdinalIgnoreCase; - - public static StringComparer CaseIgnoreComparer - { - get { return StringComparer.OrdinalIgnoreCase; } - } - - private static bool m_bRtl = false; - public static bool RightToLeft - { - get { return m_bRtl; } - set { m_bRtl = value; } - } - - private static UTF8Encoding m_encUtf8 = null; - public static UTF8Encoding Utf8 - { - get - { - if(m_encUtf8 == null) m_encUtf8 = new UTF8Encoding(false, false); - return m_encUtf8; - } - } - - private static List m_lEncs = null; - public static IEnumerable Encodings - { - get - { - if(m_lEncs != null) return m_lEncs; - - List l = new List(); - - l.Add(new StrEncodingInfo(StrEncodingType.Default, -#if ModernKeePassLib ||KeePassUAP - "Unicode (UTF-8)", StrUtil.Utf8, 1, new byte[] { 0xEF, 0xBB, 0xBF })); -#else -#if !KeePassLibSD - Encoding.Default.EncodingName, -#else - Encoding.Default.WebName, -#endif - Encoding.Default, - (uint)Encoding.Default.GetBytes("a").Length, null)); -#endif -#if !ModernKeePassLib && !KeePassRT - l.Add(new StrEncodingInfo(StrEncodingType.Ascii, - "ASCII", Encoding.ASCII, 1, null)); - l.Add(new StrEncodingInfo(StrEncodingType.Utf7, - "Unicode (UTF-7)", Encoding.UTF7, 1, null)); -#endif - l.Add(new StrEncodingInfo(StrEncodingType.Utf8, - "Unicode (UTF-8)", StrUtil.Utf8, 1, new byte[] { 0xEF, 0xBB, 0xBF })); - l.Add(new StrEncodingInfo(StrEncodingType.Utf16LE, - "Unicode (UTF-16 LE)", new UnicodeEncoding(false, false), - 2, new byte[] { 0xFF, 0xFE })); - l.Add(new StrEncodingInfo(StrEncodingType.Utf16BE, - "Unicode (UTF-16 BE)", new UnicodeEncoding(true, false), - 2, new byte[] { 0xFE, 0xFF })); -#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT) - l.Add(new StrEncodingInfo(StrEncodingType.Utf32LE, - "Unicode (UTF-32 LE)", new UTF32Encoding(false, false), - 4, new byte[] { 0xFF, 0xFE, 0x0, 0x0 })); - l.Add(new StrEncodingInfo(StrEncodingType.Utf32BE, - "Unicode (UTF-32 BE)", new UTF32Encoding(true, false), - 4, new byte[] { 0x0, 0x0, 0xFE, 0xFF })); -#endif - - m_lEncs = l; - return l; - } - } - - // public static string RtfPar - // { - // // get { return (m_bRtl ? "\\rtlpar " : "\\par "); } - // get { return "\\par "; } - // } - - // /// - // /// Convert a string into a valid RTF string. - // /// - // /// Any string. - // /// RTF-encoded string. - // public static string MakeRtfString(string str) - // { - // Debug.Assert(str != null); if(str == null) throw new ArgumentNullException("str"); - // str = str.Replace("\\", "\\\\"); - // str = str.Replace("\r", string.Empty); - // str = str.Replace("{", "\\{"); - // str = str.Replace("}", "\\}"); - // str = str.Replace("\n", StrUtil.RtfPar); - // StringBuilder sbEncoded = new StringBuilder(); - // for(int i = 0; i < str.Length; ++i) - // { - // char ch = str[i]; - // if((int)ch >= 256) - // sbEncoded.Append(StrUtil.RtfEncodeChar(ch)); - // else sbEncoded.Append(ch); - // } - // return sbEncoded.ToString(); - // } - - public static string RtfEncodeChar(char ch) - { - // Unicode character values must be encoded using - // 16-bit numbers (decimal); Unicode values greater - // than 32767 must be expressed as negative numbers - short sh = (short)ch; - return ("\\u" + sh.ToString(NumberFormatInfo.InvariantInfo) + "?"); - } - - public static string RtfFix(string strRtf) - { - if(strRtf == null) { Debug.Assert(false); return string.Empty; } - - string str = strRtf; - - // Workaround for .NET bug: the Rtf property of a RichTextBox - // can return an RTF text starting with "{\\urtf", but - // setting such an RTF text throws an exception (the setter - // checks for the RTF text to start with "{\\rtf"); - // https://sourceforge.net/p/keepass/discussion/329221/thread/7788872f/ - // https://www.microsoft.com/en-us/download/details.aspx?id=10725 - // https://msdn.microsoft.com/en-us/library/windows/desktop/bb774284.aspx - // https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/RichTextBox.cs - const string p = "{\\urtf"; // Typically "{\\urtf1\\ansi\\ansicpg65001" - if(str.StartsWith(p) && (str.Length > p.Length) && - char.IsDigit(str[p.Length])) - str = str.Remove(2, 1); // Remove the 'u' - - return str; - } - - /// - /// Convert a string to a HTML sequence representing that string. - /// - /// String to convert. - /// String, HTML-encoded. - public static string StringToHtml(string str) - { - return StringToHtml(str, false); - } - - internal static string StringToHtml(string str, bool bNbsp) - { - Debug.Assert(str != null); if(str == null) throw new ArgumentNullException("str"); - - str = str.Replace(@"&", @"&"); // Must be first - str = str.Replace(@"<", @"<"); - str = str.Replace(@">", @">"); - str = str.Replace("\"", @"""); - str = str.Replace("\'", @"'"); - - if(bNbsp) str = str.Replace(" ", @" "); // Before
- - str = NormalizeNewLines(str, false); - str = str.Replace("\n", @"
" + MessageService.NewLine); - - return str; - } - - public static string XmlToString(string str) - { - Debug.Assert(str != null); if(str == null) throw new ArgumentNullException("str"); - - str = str.Replace(@"&", @"&"); - str = str.Replace(@"<", @"<"); - str = str.Replace(@">", @">"); - str = str.Replace(@""", "\""); - str = str.Replace(@"'", "\'"); - - return str; - } - - public static string ReplaceCaseInsensitive(string strString, string strFind, - string strNew) - { - Debug.Assert(strString != null); if(strString == null) return strString; - Debug.Assert(strFind != null); if(strFind == null) return strString; - Debug.Assert(strNew != null); if(strNew == null) return strString; - - string str = strString; - - int nPos = 0; - while(nPos < str.Length) - { - nPos = str.IndexOf(strFind, nPos, StringComparison.OrdinalIgnoreCase); - if(nPos < 0) break; - - str = str.Remove(nPos, strFind.Length); - str = str.Insert(nPos, strNew); - - nPos += strNew.Length; - } - - return str; - } - - /// - /// Split up a command line into application and argument. - /// - /// Command line to split. - /// Application path. - /// Arguments. - public static void SplitCommandLine(string strCmdLine, out string strApp, out string strArgs) - { - Debug.Assert(strCmdLine != null); if(strCmdLine == null) throw new ArgumentNullException("strCmdLine"); - - string str = strCmdLine.Trim(); - - strApp = null; strArgs = null; - - if(str.StartsWith("\"")) - { - int nSecond = str.IndexOf('\"', 1); - if(nSecond >= 1) - { - strApp = str.Substring(1, nSecond - 1).Trim(); - strArgs = str.Remove(0, nSecond + 1).Trim(); - } - } - - if(strApp == null) - { - int nSpace = str.IndexOf(' '); - - if(nSpace >= 0) - { - strApp = str.Substring(0, nSpace); - strArgs = str.Remove(0, nSpace).Trim(); - } - else strApp = strCmdLine; - } - - if(strApp == null) strApp = string.Empty; - if(strArgs == null) strArgs = string.Empty; - } - - // /// - // /// Initialize an RTF document based on given font face and size. - // /// - // /// StringBuilder to put the generated RTF into. - // /// Face name of the font to use. - // /// Size of the font to use. - // public static void InitRtf(StringBuilder sb, string strFontFace, float fFontSize) - // { - // Debug.Assert(sb != null); if(sb == null) throw new ArgumentNullException("sb"); - // Debug.Assert(strFontFace != null); if(strFontFace == null) throw new ArgumentNullException("strFontFace"); - // sb.Append("{\\rtf1"); - // if(m_bRtl) sb.Append("\\fbidis"); - // sb.Append("\\ansi\\ansicpg"); - // sb.Append(Encoding.Default.CodePage); - // sb.Append("\\deff0{\\fonttbl{\\f0\\fswiss MS Sans Serif;}{\\f1\\froman\\fcharset2 Symbol;}{\\f2\\fswiss "); - // sb.Append(strFontFace); - // sb.Append(";}{\\f3\\fswiss Arial;}}"); - // sb.Append("{\\colortbl\\red0\\green0\\blue0;}"); - // if(m_bRtl) sb.Append("\\rtldoc"); - // sb.Append("\\deflang1031\\pard\\plain\\f2\\cf0 "); - // sb.Append("\\fs"); - // sb.Append((int)(fFontSize * 2)); - // if(m_bRtl) sb.Append("\\rtlpar\\qr\\rtlch "); - // } - - // /// - // /// Convert a simple HTML string to an RTF string. - // /// - // /// Input HTML string. - // /// RTF string representing the HTML input string. - // public static string SimpleHtmlToRtf(string strHtmlString) - // { - // StringBuilder sb = new StringBuilder(); - // StrUtil.InitRtf(sb, "Microsoft Sans Serif", 8.25f); - // sb.Append(" "); - // string str = MakeRtfString(strHtmlString); - // str = str.Replace("", "\\b "); - // str = str.Replace("", "\\b0 "); - // str = str.Replace("", "\\i "); - // str = str.Replace("", "\\i0 "); - // str = str.Replace("", "\\ul "); - // str = str.Replace("", "\\ul0 "); - // str = str.Replace("
", StrUtil.RtfPar); - // sb.Append(str); - // return sb.ToString(); - // } - - /// - /// Convert a Color to a HTML color identifier string. - /// - /// Color to convert. - /// If this is true, an empty string - /// is returned if the color is transparent. - /// HTML color identifier string. - public static string ColorToUnnamedHtml(Color color, bool bEmptyIfTransparent) - { - if(bEmptyIfTransparent && (color.A != 255)) - return string.Empty; - - StringBuilder sb = new StringBuilder(); - byte bt; - - sb.Append('#'); - - bt = (byte)(color.R >> 4); - if(bt < 10) sb.Append((char)('0' + bt)); else sb.Append((char)('A' - 10 + bt)); - bt = (byte)(color.R & 0x0F); - if(bt < 10) sb.Append((char)('0' + bt)); else sb.Append((char)('A' - 10 + bt)); - - bt = (byte)(color.G >> 4); - if(bt < 10) sb.Append((char)('0' + bt)); else sb.Append((char)('A' - 10 + bt)); - bt = (byte)(color.G & 0x0F); - if(bt < 10) sb.Append((char)('0' + bt)); else sb.Append((char)('A' - 10 + bt)); - - bt = (byte)(color.B >> 4); - if(bt < 10) sb.Append((char)('0' + bt)); else sb.Append((char)('A' - 10 + bt)); - bt = (byte)(color.B & 0x0F); - if(bt < 10) sb.Append((char)('0' + bt)); else sb.Append((char)('A' - 10 + bt)); - - return sb.ToString(); - } - - /// - /// Format an exception and convert it to a string. - /// - /// Exception to convert/format. - /// String representing the exception. - public static string FormatException(Exception excp) - { - string strText = string.Empty; - - if(!string.IsNullOrEmpty(excp.Message)) - strText += excp.Message + MessageService.NewLine; -#if !KeePassLibSD - if(!string.IsNullOrEmpty(excp.Source)) - strText += excp.Source + MessageService.NewLine; -#endif - if(!string.IsNullOrEmpty(excp.StackTrace)) - strText += excp.StackTrace + MessageService.NewLine; -#if !KeePassLibSD -#if !ModernKeePassLib && !KeePassRT - if(excp.TargetSite != null) - strText += excp.TargetSite.ToString() + MessageService.NewLine; -#endif - - if(excp.Data != null) - { - strText += MessageService.NewLine; - foreach(DictionaryEntry de in excp.Data) - strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" + - MessageService.NewLine; - } -#endif - - if(excp.InnerException != null) - { - strText += MessageService.NewLine + "Inner:" + MessageService.NewLine; - if(!string.IsNullOrEmpty(excp.InnerException.Message)) - strText += excp.InnerException.Message + MessageService.NewLine; -#if !KeePassLibSD - if(!string.IsNullOrEmpty(excp.InnerException.Source)) - strText += excp.InnerException.Source + MessageService.NewLine; -#endif - if(!string.IsNullOrEmpty(excp.InnerException.StackTrace)) - strText += excp.InnerException.StackTrace + MessageService.NewLine; -#if !KeePassLibSD -#if !ModernKeePassLib && !KeePassRT - if(excp.InnerException.TargetSite != null) - strText += excp.InnerException.TargetSite.ToString(); -#endif - - if(excp.InnerException.Data != null) - { - strText += MessageService.NewLine; - foreach(DictionaryEntry de in excp.InnerException.Data) - strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" + - MessageService.NewLine; - } -#endif - } - - return strText; - } - - public static bool TryParseUShort(string str, out ushort u) - { -#if !KeePassLibSD - return ushort.TryParse(str, out u); -#else - try { u = ushort.Parse(str); return true; } - catch(Exception) { u = 0; return false; } -#endif - } - - public static bool TryParseInt(string str, out int n) - { -#if !KeePassLibSD - return int.TryParse(str, out n); -#else - try { n = int.Parse(str); return true; } - catch(Exception) { n = 0; } - return false; -#endif - } - - public static bool TryParseIntInvariant(string str, out int n) - { -#if !KeePassLibSD - return int.TryParse(str, NumberStyles.Integer, - NumberFormatInfo.InvariantInfo, out n); -#else - try - { - n = int.Parse(str, NumberStyles.Integer, - NumberFormatInfo.InvariantInfo); - return true; - } - catch(Exception) { n = 0; } - return false; -#endif - } - - public static bool TryParseUInt(string str, out uint u) - { -#if !KeePassLibSD - return uint.TryParse(str, out u); -#else - try { u = uint.Parse(str); return true; } - catch(Exception) { u = 0; } - return false; -#endif - } - - public static bool TryParseUIntInvariant(string str, out uint u) - { -#if !KeePassLibSD - return uint.TryParse(str, NumberStyles.Integer, - NumberFormatInfo.InvariantInfo, out u); -#else - try - { - u = uint.Parse(str, NumberStyles.Integer, - NumberFormatInfo.InvariantInfo); - return true; - } - catch(Exception) { u = 0; } - return false; -#endif - } - - public static bool TryParseLong(string str, out long n) - { -#if !KeePassLibSD - return long.TryParse(str, out n); -#else - try { n = long.Parse(str); return true; } - catch(Exception) { n = 0; } - return false; -#endif - } - - public static bool TryParseLongInvariant(string str, out long n) - { -#if !KeePassLibSD - return long.TryParse(str, NumberStyles.Integer, - NumberFormatInfo.InvariantInfo, out n); -#else - try - { - n = long.Parse(str, NumberStyles.Integer, - NumberFormatInfo.InvariantInfo); - return true; - } - catch(Exception) { n = 0; } - return false; -#endif - } - - public static bool TryParseULong(string str, out ulong u) - { -#if !KeePassLibSD - return ulong.TryParse(str, out u); -#else - try { u = ulong.Parse(str); return true; } - catch(Exception) { u = 0; } - return false; -#endif - } - - public static bool TryParseULongInvariant(string str, out ulong u) - { -#if !KeePassLibSD - return ulong.TryParse(str, NumberStyles.Integer, - NumberFormatInfo.InvariantInfo, out u); -#else - try - { - u = ulong.Parse(str, NumberStyles.Integer, - NumberFormatInfo.InvariantInfo); - return true; - } - catch(Exception) { u = 0; } - return false; -#endif - } - - public static bool TryParseDateTime(string str, out DateTime dt) - { -#if !KeePassLibSD - return DateTime.TryParse(str, out dt); -#else - try { dt = DateTime.Parse(str); return true; } - catch(Exception) { dt = DateTime.UtcNow; } - return false; -#endif - } - - public static string CompactString3Dots(string strText, int nMaxChars) - { - Debug.Assert(strText != null); - if(strText == null) throw new ArgumentNullException("strText"); - Debug.Assert(nMaxChars >= 0); - if(nMaxChars < 0) throw new ArgumentOutOfRangeException("nMaxChars"); - - if(nMaxChars == 0) return string.Empty; - if(strText.Length <= nMaxChars) return strText; - - if(nMaxChars <= 3) return strText.Substring(0, nMaxChars); - - return strText.Substring(0, nMaxChars - 3) + "..."; - } - - public static string GetStringBetween(string strText, int nStartIndex, - string strStart, string strEnd) - { - int nTemp; - return GetStringBetween(strText, nStartIndex, strStart, strEnd, out nTemp); - } - - public static string GetStringBetween(string strText, int nStartIndex, - string strStart, string strEnd, out int nInnerStartIndex) - { - if(strText == null) throw new ArgumentNullException("strText"); - if(strStart == null) throw new ArgumentNullException("strStart"); - if(strEnd == null) throw new ArgumentNullException("strEnd"); - - nInnerStartIndex = -1; - - int nIndex = strText.IndexOf(strStart, nStartIndex); - if(nIndex < 0) return string.Empty; - - nIndex += strStart.Length; - - int nEndIndex = strText.IndexOf(strEnd, nIndex); - if(nEndIndex < 0) return string.Empty; - - nInnerStartIndex = nIndex; - return strText.Substring(nIndex, nEndIndex - nIndex); - } - - /// - /// Removes all characters that are not valid XML characters, - /// according to https://www.w3.org/TR/xml/#charsets . - /// - /// Source text. - /// Text containing only valid XML characters. - public static string SafeXmlString(string strText) - { - Debug.Assert(strText != null); // No throw - if(string.IsNullOrEmpty(strText)) return strText; - - int nLength = strText.Length; - StringBuilder sb = new StringBuilder(nLength); - - for(int i = 0; i < nLength; ++i) - { - char ch = strText[i]; - - if(((ch >= '\u0020') && (ch <= '\uD7FF')) || - (ch == '\u0009') || (ch == '\u000A') || (ch == '\u000D') || - ((ch >= '\uE000') && (ch <= '\uFFFD'))) - sb.Append(ch); - else if((ch >= '\uD800') && (ch <= '\uDBFF')) // High surrogate - { - if((i + 1) < nLength) - { - char chLow = strText[i + 1]; - if((chLow >= '\uDC00') && (chLow <= '\uDFFF')) // Low sur. - { - sb.Append(ch); - sb.Append(chLow); - ++i; - } - else { Debug.Assert(false); } // Low sur. invalid - } - else { Debug.Assert(false); } // Low sur. missing - } - - Debug.Assert((ch < '\uDC00') || (ch > '\uDFFF')); // Lonely low sur. - } - - return sb.ToString(); - } - - /* private static Regex g_rxNaturalSplit = null; - public static int CompareNaturally(string strX, string strY) - { - Debug.Assert(strX != null); - if(strX == null) throw new ArgumentNullException("strX"); - Debug.Assert(strY != null); - if(strY == null) throw new ArgumentNullException("strY"); - - if(NativeMethods.SupportsStrCmpNaturally) - return NativeMethods.StrCmpNaturally(strX, strY); - - if(g_rxNaturalSplit == null) - g_rxNaturalSplit = new Regex(@"([0-9]+)", RegexOptions.Compiled); - - string[] vPartsX = g_rxNaturalSplit.Split(strX); - string[] vPartsY = g_rxNaturalSplit.Split(strY); - - int n = Math.Min(vPartsX.Length, vPartsY.Length); - for(int i = 0; i < n; ++i) - { - string strPartX = vPartsX[i], strPartY = vPartsY[i]; - int iPartCompare; - -#if KeePassLibSD - try - { - ulong uX = ulong.Parse(strPartX); - ulong uY = ulong.Parse(strPartY); - iPartCompare = uX.CompareTo(uY); - } - catch(Exception) { iPartCompare = string.Compare(strPartX, strPartY, true); } -#else - ulong uX, uY; - if(ulong.TryParse(strPartX, out uX) && ulong.TryParse(strPartY, out uY)) - iPartCompare = uX.CompareTo(uY); - else iPartCompare = string.Compare(strPartX, strPartY, true); -#endif - - if(iPartCompare != 0) return iPartCompare; - } - - if(vPartsX.Length == vPartsY.Length) return 0; - if(vPartsX.Length < vPartsY.Length) return -1; - return 1; - } */ - - public static int CompareNaturally(string strX, string strY) - { - Debug.Assert(strX != null); - if(strX == null) throw new ArgumentNullException("strX"); - Debug.Assert(strY != null); - if(strY == null) throw new ArgumentNullException("strY"); - - if(NativeMethods.SupportsStrCmpNaturally) - return NativeMethods.StrCmpNaturally(strX, strY); - - int cX = strX.Length; - int cY = strY.Length; - if(cX == 0) return ((cY == 0) ? 0 : -1); - if(cY == 0) return 1; - - char chFirstX = strX[0]; - char chFirstY = strY[0]; - bool bExpNum = ((chFirstX >= '0') && (chFirstX <= '9')); - bool bExpNumY = ((chFirstY >= '0') && (chFirstY <= '9')); -#if ModernKeePassLib - if (bExpNum != bExpNumY) return StringComparer.OrdinalIgnoreCase.Compare(strX, strY); -#else - if(bExpNum != bExpNumY) return string.Compare(strX, strY, true); -#endif - - int pX = 0; - int pY = 0; - while((pX < cX) && (pY < cY)) - { - Debug.Assert(((strX[pX] >= '0') && (strX[pX] <= '9')) == bExpNum); - Debug.Assert(((strY[pY] >= '0') && (strY[pY] <= '9')) == bExpNum); - - int pExclX = pX + 1; - while(pExclX < cX) - { - char ch = strX[pExclX]; - bool bChNum = ((ch >= '0') && (ch <= '9')); - if(bChNum != bExpNum) break; - ++pExclX; - } - - int pExclY = pY + 1; - while(pExclY < cY) - { - char ch = strY[pExclY]; - bool bChNum = ((ch >= '0') && (ch <= '9')); - if(bChNum != bExpNum) break; - ++pExclY; - } - - string strPartX = strX.Substring(pX, pExclX - pX); - string strPartY = strY.Substring(pY, pExclY - pY); - - bool bStrCmp = true; - if(bExpNum) - { - // 2^64 - 1 = 18446744073709551615 has length 20 - if((strPartX.Length <= 19) && (strPartY.Length <= 19)) - { - ulong uX, uY; - if(ulong.TryParse(strPartX, out uX) && ulong.TryParse(strPartY, out uY)) - { - if(uX < uY) return -1; - if(uX > uY) return 1; - - bStrCmp = false; - } - else { Debug.Assert(false); } - } - else - { - double dX, dY; - if(double.TryParse(strPartX, out dX) && double.TryParse(strPartY, out dY)) - { - if(dX < dY) return -1; - if(dX > dY) return 1; - - bStrCmp = false; - } - else { Debug.Assert(false); } - } - } - if(bStrCmp) - { -#if ModernKeePassLib - int c = StringComparer.OrdinalIgnoreCase.Compare(strPartX, strPartY); -#else - int c = string.Compare(strPartX, strPartY, true); -#endif - if(c != 0) return c; - } - - bExpNum = !bExpNum; - pX = pExclX; - pY = pExclY; - } - - if(pX >= cX) - { - Debug.Assert(pX == cX); - if(pY >= cY) { Debug.Assert(pY == cY); return 0; } - return -1; - } - - Debug.Assert(pY == cY); - return 1; - } - - public static string RemoveAccelerator(string strMenuText) - { - if(strMenuText == null) throw new ArgumentNullException("strMenuText"); - - string str = strMenuText; - - for(char ch = 'A'; ch <= 'Z'; ++ch) - { - string strEnhAcc = @"(&" + ch.ToString() + @")"; - if(str.IndexOf(strEnhAcc) >= 0) - { - str = str.Replace(@" " + strEnhAcc, string.Empty); - str = str.Replace(strEnhAcc, string.Empty); - } - } - - str = str.Replace(@"&", string.Empty); - - return str; - } - - public static string AddAccelerator(string strMenuText, - List lAvailKeys) - { - if(strMenuText == null) { Debug.Assert(false); return null; } - if(lAvailKeys == null) { Debug.Assert(false); return strMenuText; } - - int xa = -1, xs = 0; - for(int i = 0; i < strMenuText.Length; ++i) - { - char ch = strMenuText[i]; - -#if KeePassLibSD - char chUpper = char.ToUpper(ch); -#else - char chUpper = char.ToUpperInvariant(ch); -#endif - xa = lAvailKeys.IndexOf(chUpper); - if(xa >= 0) { xs = i; break; } - -#if KeePassLibSD - char chLower = char.ToLower(ch); -#else - char chLower = char.ToLowerInvariant(ch); -#endif - xa = lAvailKeys.IndexOf(chLower); - if(xa >= 0) { xs = i; break; } - } - - if(xa < 0) return strMenuText; - - lAvailKeys.RemoveAt(xa); - return strMenuText.Insert(xs, @"&"); - } - - public static string EncodeMenuText(string strText) - { - if(strText == null) throw new ArgumentNullException("strText"); - - return strText.Replace(@"&", @"&&"); - } - - public static string EncodeToolTipText(string strText) - { - if(strText == null) throw new ArgumentNullException("strText"); - - return strText.Replace(@"&", @"&&&"); - } - - public static bool IsHexString(string str, bool bStrict) - { - if(str == null) throw new ArgumentNullException("str"); - - foreach(char ch in str) - { - if((ch >= '0') && (ch <= '9')) continue; - if((ch >= 'a') && (ch <= 'f')) continue; - if((ch >= 'A') && (ch <= 'F')) continue; - - if(bStrict) return false; - - if((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n')) - continue; - - return false; - } - - return true; - } - - public static bool IsHexString(byte[] pbUtf8, bool bStrict) - { - if(pbUtf8 == null) throw new ArgumentNullException("pbUtf8"); - - for(int i = 0; i < pbUtf8.Length; ++i) - { - byte bt = pbUtf8[i]; - if((bt >= (byte)'0') && (bt <= (byte)'9')) continue; - if((bt >= (byte)'a') && (bt <= (byte)'f')) continue; - if((bt >= (byte)'A') && (bt <= (byte)'F')) continue; - - if(bStrict) return false; - - if((bt == (byte)' ') || (bt == (byte)'\t') || - (bt == (byte)'\r') || (bt == (byte)'\n')) - continue; - - return false; - } - - return true; - } - -#if !KeePassLibSD - private static readonly char[] m_vPatternPartsSep = new char[] { '*' }; - public static bool SimplePatternMatch(string strPattern, string strText, - StringComparison sc) - { - if(strPattern == null) throw new ArgumentNullException("strPattern"); - if(strText == null) throw new ArgumentNullException("strText"); - - if(strPattern.IndexOf('*') < 0) return strText.Equals(strPattern, sc); - - string[] vPatternParts = strPattern.Split(m_vPatternPartsSep, - StringSplitOptions.RemoveEmptyEntries); - if(vPatternParts == null) { Debug.Assert(false); return true; } - if(vPatternParts.Length == 0) return true; - - if(strText.Length == 0) return false; - - if(!strPattern.StartsWith(@"*") && !strText.StartsWith(vPatternParts[0], sc)) - { - return false; - } - - if(!strPattern.EndsWith(@"*") && !strText.EndsWith(vPatternParts[ - vPatternParts.Length - 1], sc)) - { - return false; - } - - int iOffset = 0; - for(int i = 0; i < vPatternParts.Length; ++i) - { - string strPart = vPatternParts[i]; - - int iFound = strText.IndexOf(strPart, iOffset, sc); - if(iFound < iOffset) return false; - - iOffset = iFound + strPart.Length; - if(iOffset == strText.Length) return (i == (vPatternParts.Length - 1)); - } - - return true; - } -#endif // !KeePassLibSD - - public static bool StringToBool(string str) - { - if(string.IsNullOrEmpty(str)) return false; // No assert - - string s = str.Trim().ToLower(); - if(s == "true") return true; - if(s == "yes") return true; - if(s == "1") return true; - if(s == "enabled") return true; - if(s == "checked") return true; - - return false; - } - - public static bool? StringToBoolEx(string str) - { - if(string.IsNullOrEmpty(str)) return null; - - string s = str.Trim().ToLower(); - if(s == "true") return true; - if(s == "false") return false; - - return null; - } - - public static string BoolToString(bool bValue) - { - return (bValue ? "true" : "false"); - } - - public static string BoolToStringEx(bool? bValue) - { - if(bValue.HasValue) return BoolToString(bValue.Value); - return "null"; - } - - /// - /// Normalize new line characters in a string. Input strings may - /// contain mixed new line character sequences from all commonly - /// used operating systems (i.e. \r\n from Windows, \n from Unix - /// and \r from Mac OS. - /// - /// String with mixed new line characters. - /// If true, new line characters - /// are normalized for Windows (\r\n); if false, new line - /// characters are normalized for Unix (\n). - /// String with normalized new line characters. - public static string NormalizeNewLines(string str, bool bWindows) - { - if(string.IsNullOrEmpty(str)) return str; - - str = str.Replace("\r\n", "\n"); - str = str.Replace("\r", "\n"); - - if(bWindows) str = str.Replace("\n", "\r\n"); - - return str; - } - - public static void NormalizeNewLines(ProtectedStringDictionary dict, - bool bWindows) - { - if(dict == null) { Debug.Assert(false); return; } - - List lKeys = dict.GetKeys(); - foreach(string strKey in lKeys) - { - ProtectedString ps = dict.Get(strKey); - if(ps == null) { Debug.Assert(false); continue; } - - char[] v = ps.ReadChars(); - if(!IsNewLineNormalized(v, bWindows)) - dict.Set(strKey, new ProtectedString(ps.IsProtected, - NormalizeNewLines(ps.ReadString(), bWindows))); - MemUtil.ZeroArray(v); - } - } - - internal static bool IsNewLineNormalized(char[] v, bool bWindows) - { - if(v == null) { Debug.Assert(false); return true; } - - if(bWindows) - { - int iFreeCr = -2; // Must be < -1 (for test "!= (i - 1)") - - for(int i = 0; i < v.Length; ++i) - { - char ch = v[i]; - - if(ch == '\r') - { - if(iFreeCr >= 0) return false; - iFreeCr = i; - } - else if(ch == '\n') - { - if(iFreeCr != (i - 1)) return false; - iFreeCr = -2; // Consume \r - } - } - - return (iFreeCr < 0); // Ensure no \r at end - } - - return (Array.IndexOf(v, '\r') < 0); - } - - public static string GetNewLineSeq(string str) - { - if(str == null) { Debug.Assert(false); return MessageService.NewLine; } - - int n = str.Length, nLf = 0, nCr = 0, nCrLf = 0; - char chLast = char.MinValue; - for(int i = 0; i < n; ++i) - { - char ch = str[i]; - - if(ch == '\r') ++nCr; - else if(ch == '\n') - { - ++nLf; - if(chLast == '\r') ++nCrLf; - } - - chLast = ch; - } - - nCr -= nCrLf; - nLf -= nCrLf; - - int nMax = Math.Max(nCrLf, Math.Max(nCr, nLf)); - if(nMax == 0) return MessageService.NewLine; - - if(nCrLf == nMax) return "\r\n"; - return ((nLf == nMax) ? "\n" : "\r"); - } - - public static string AlphaNumericOnly(string str) - { - if(string.IsNullOrEmpty(str)) return str; - - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < str.Length; ++i) - { - char ch = str[i]; - if(((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || - ((ch >= '0') && (ch <= '9'))) - sb.Append(ch); - } - - return sb.ToString(); - } - - public static string FormatDataSize(ulong uBytes) - { - const ulong uKB = 1024; - const ulong uMB = uKB * uKB; - const ulong uGB = uMB * uKB; - const ulong uTB = uGB * uKB; - - if(uBytes == 0) return "0 KB"; - if(uBytes <= uKB) return "1 KB"; - if(uBytes <= uMB) return (((uBytes - 1UL) / uKB) + 1UL).ToString() + " KB"; - if(uBytes <= uGB) return (((uBytes - 1UL) / uMB) + 1UL).ToString() + " MB"; - if(uBytes <= uTB) return (((uBytes - 1UL) / uGB) + 1UL).ToString() + " GB"; - - return (((uBytes - 1UL)/ uTB) + 1UL).ToString() + " TB"; - } - - public static string FormatDataSizeKB(ulong uBytes) - { - const ulong uKB = 1024; - - if(uBytes == 0) return "0 KB"; - if(uBytes <= uKB) return "1 KB"; - - return (((uBytes - 1UL) / uKB) + 1UL).ToString() + " KB"; - } - - private static readonly char[] m_vVersionSep = new char[]{ '.', ',' }; - public static ulong ParseVersion(string strVersion) - { - if(strVersion == null) { Debug.Assert(false); return 0; } - - string[] vVer = strVersion.Split(m_vVersionSep); - if((vVer == null) || (vVer.Length == 0)) { Debug.Assert(false); return 0; } - - ushort uPart; - StrUtil.TryParseUShort(vVer[0].Trim(), out uPart); - ulong uVer = ((ulong)uPart << 48); - - if(vVer.Length >= 2) - { - StrUtil.TryParseUShort(vVer[1].Trim(), out uPart); - uVer |= ((ulong)uPart << 32); - } - - if(vVer.Length >= 3) - { - StrUtil.TryParseUShort(vVer[2].Trim(), out uPart); - uVer |= ((ulong)uPart << 16); - } - - if(vVer.Length >= 4) - { - StrUtil.TryParseUShort(vVer[3].Trim(), out uPart); - uVer |= (ulong)uPart; - } - - return uVer; - } - - public static string VersionToString(ulong uVersion) - { - return VersionToString(uVersion, 1U); - } - - [Obsolete] - public static string VersionToString(ulong uVersion, - bool bEnsureAtLeastTwoComp) - { - return VersionToString(uVersion, (bEnsureAtLeastTwoComp ? 2U : 1U)); - } - - public static string VersionToString(ulong uVersion, uint uMinComp) - { - StringBuilder sb = new StringBuilder(); - uint uComp = 0; - - for(int i = 0; i < 4; ++i) - { - if(uVersion == 0UL) break; - - ushort us = (ushort)(uVersion >> 48); - - if(sb.Length > 0) sb.Append('.'); - - sb.Append(us.ToString(NumberFormatInfo.InvariantInfo)); - ++uComp; - - uVersion <<= 16; - } - - while(uComp < uMinComp) - { - if(sb.Length > 0) sb.Append('.'); - - sb.Append('0'); - ++uComp; - } - - return sb.ToString(); - } - - private static readonly byte[] m_pbOptEnt = { 0xA5, 0x74, 0x2E, 0xEC }; - - public static string EncryptString(string strPlainText) - { - if(string.IsNullOrEmpty(strPlainText)) return string.Empty; - - try - { - byte[] pbPlain = StrUtil.Utf8.GetBytes(strPlainText); - byte[] pbEnc = CryptoUtil.ProtectData(pbPlain, m_pbOptEnt, - DataProtectionScope.CurrentUser); - -#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT) - return Convert.ToBase64String(pbEnc, Base64FormattingOptions.None); -#else - return Convert.ToBase64String(pbEnc); -#endif - } - catch(Exception) { Debug.Assert(false); } - - return strPlainText; - } - - public static string DecryptString(string strCipherText) - { - if(string.IsNullOrEmpty(strCipherText)) return string.Empty; - - try - { - byte[] pbEnc = Convert.FromBase64String(strCipherText); - byte[] pbPlain = CryptoUtil.UnprotectData(pbEnc, m_pbOptEnt, - DataProtectionScope.CurrentUser); - - return StrUtil.Utf8.GetString(pbPlain, 0, pbPlain.Length); - } - catch(Exception) { Debug.Assert(false); } - - return strCipherText; - } - - public static string SerializeIntArray(int[] vNumbers) - { - if(vNumbers == null) throw new ArgumentNullException("vNumbers"); - - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < vNumbers.Length; ++i) - { - if(i > 0) sb.Append(' '); - sb.Append(vNumbers[i].ToString(NumberFormatInfo.InvariantInfo)); - } - - return sb.ToString(); - } - - public static int[] DeserializeIntArray(string strSerialized) - { - if(strSerialized == null) throw new ArgumentNullException("strSerialized"); - if(strSerialized.Length == 0) return new int[0]; - - string[] vParts = strSerialized.Split(' '); - int[] v = new int[vParts.Length]; - - for(int i = 0; i < vParts.Length; ++i) - { - int n; - if(!TryParseIntInvariant(vParts[i], out n)) { Debug.Assert(false); } - v[i] = n; - } - - return v; - } - - private static readonly char[] m_vTagSep = new char[] { ',', ';', ':' }; - public static string TagsToString(List vTags, bool bForDisplay) - { - if(vTags == null) throw new ArgumentNullException("vTags"); - - StringBuilder sb = new StringBuilder(); - bool bFirst = true; - - foreach(string strTag in vTags) - { - if(string.IsNullOrEmpty(strTag)) { Debug.Assert(false); continue; } - Debug.Assert(strTag.IndexOfAny(m_vTagSep) < 0); - - if(!bFirst) - { - if(bForDisplay) sb.Append(", "); - else sb.Append(';'); - } - sb.Append(strTag); - - bFirst = false; - } - - return sb.ToString(); - } - - public static List StringToTags(string strTags) - { - if(strTags == null) throw new ArgumentNullException("strTags"); - - List lTags = new List(); - if(strTags.Length == 0) return lTags; - - string[] vTags = strTags.Split(m_vTagSep); - foreach(string strTag in vTags) - { - string strFlt = strTag.Trim(); - if(strFlt.Length > 0) lTags.Add(strFlt); - } - - return lTags; - } - - public static string Obfuscate(string strPlain) - { - if(strPlain == null) { Debug.Assert(false); return string.Empty; } - if(strPlain.Length == 0) return string.Empty; - - byte[] pb = StrUtil.Utf8.GetBytes(strPlain); - - Array.Reverse(pb); - for(int i = 0; i < pb.Length; ++i) pb[i] = (byte)(pb[i] ^ 0x65); - -#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT) - return Convert.ToBase64String(pb, Base64FormattingOptions.None); -#else - return Convert.ToBase64String(pb); -#endif - } - - public static string Deobfuscate(string strObf) - { - if(strObf == null) { Debug.Assert(false); return string.Empty; } - if(strObf.Length == 0) return string.Empty; - - try - { - byte[] pb = Convert.FromBase64String(strObf); - - for(int i = 0; i < pb.Length; ++i) pb[i] = (byte)(pb[i] ^ 0x65); - Array.Reverse(pb); - - return StrUtil.Utf8.GetString(pb, 0, pb.Length); - } - catch(Exception) { Debug.Assert(false); } - - return string.Empty; - } - - /// - /// Split a string and include the separators in the splitted array. - /// - /// String to split. - /// Separators. - /// Specifies whether separators are - /// matched case-sensitively or not. - /// Splitted string including separators. - public static List SplitWithSep(string str, string[] vSeps, - bool bCaseSensitive) - { - if(str == null) throw new ArgumentNullException("str"); - if(vSeps == null) throw new ArgumentNullException("vSeps"); - - List v = new List(); - while(true) - { - int minIndex = int.MaxValue, minSep = -1; - for(int i = 0; i < vSeps.Length; ++i) - { - string strSep = vSeps[i]; - if(string.IsNullOrEmpty(strSep)) { Debug.Assert(false); continue; } - - int iIndex = (bCaseSensitive ? str.IndexOf(strSep) : - str.IndexOf(strSep, StrUtil.CaseIgnoreCmp)); - if((iIndex >= 0) && (iIndex < minIndex)) - { - minIndex = iIndex; - minSep = i; - } - } - - if(minIndex == int.MaxValue) break; - - v.Add(str.Substring(0, minIndex)); - v.Add(vSeps[minSep]); - - str = str.Substring(minIndex + vSeps[minSep].Length); - } - - v.Add(str); - return v; - } - - public static string MultiToSingleLine(string strMulti) - { - if(strMulti == null) { Debug.Assert(false); return string.Empty; } - if(strMulti.Length == 0) return string.Empty; - - string str = strMulti; - str = str.Replace("\r\n", " "); - str = str.Replace("\r", " "); - str = str.Replace("\n", " "); - - return str; - } - - public static List SplitSearchTerms(string strSearch) - { - List l = new List(); - if(strSearch == null) { Debug.Assert(false); return l; } - - StringBuilder sbTerm = new StringBuilder(); - bool bQuoted = false; - - for(int i = 0; i < strSearch.Length; ++i) - { - char ch = strSearch[i]; - - if(((ch == ' ') || (ch == '\t') || (ch == '\r') || - (ch == '\n')) && !bQuoted) - { - if(sbTerm.Length > 0) l.Add(sbTerm.ToString()); - - sbTerm.Remove(0, sbTerm.Length); - } - else if(ch == '\"') bQuoted = !bQuoted; - else sbTerm.Append(ch); - } - if(sbTerm.Length > 0) l.Add(sbTerm.ToString()); - - return l; - } - - public static int CompareLengthGt(string x, string y) - { - if(x.Length == y.Length) return 0; - return ((x.Length > y.Length) ? -1 : 1); - } - - public static bool IsDataUri(string strUri) - { - return IsDataUri(strUri, null); - } - - public static bool IsDataUri(string strUri, string strReqMimeType) - { - if(strUri == null) { Debug.Assert(false); return false; } - // strReqMimeType may be null - - const string strPrefix = "data:"; - if(!strUri.StartsWith(strPrefix, StrUtil.CaseIgnoreCmp)) - return false; - - int iC = strUri.IndexOf(','); - if(iC < 0) return false; - - if(!string.IsNullOrEmpty(strReqMimeType)) - { - int iS = strUri.IndexOf(';', 0, iC); - int iTerm = ((iS >= 0) ? iS : iC); - - string strMime = strUri.Substring(strPrefix.Length, - iTerm - strPrefix.Length); - if(!strMime.Equals(strReqMimeType, StrUtil.CaseIgnoreCmp)) - return false; - } - - return true; - } - - /// - /// Create a data URI (according to RFC 2397). - /// - /// Data to encode. - /// Optional MIME type. If null, - /// an appropriate type is used. - /// Data URI. - public static string DataToDataUri(byte[] pbData, string strMimeType) - { - if(pbData == null) throw new ArgumentNullException("pbData"); - - if(strMimeType == null) strMimeType = "application/octet-stream"; - -#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT) - return ("data:" + strMimeType + ";base64," + Convert.ToBase64String( - pbData, Base64FormattingOptions.None)); -#else - return ("data:" + strMimeType + ";base64," + Convert.ToBase64String( - pbData)); -#endif - } - - /// - /// Convert a data URI (according to RFC 2397) to binary data. - /// - /// Data URI to decode. - /// Decoded binary data. - public static byte[] DataUriToData(string strDataUri) - { - if(strDataUri == null) throw new ArgumentNullException("strDataUri"); - if(!strDataUri.StartsWith("data:", StrUtil.CaseIgnoreCmp)) return null; - - int iSep = strDataUri.IndexOf(','); - if(iSep < 0) return null; - - string strDesc = strDataUri.Substring(5, iSep - 5); - bool bBase64 = strDesc.EndsWith(";base64", StrUtil.CaseIgnoreCmp); - - string strData = strDataUri.Substring(iSep + 1); - - if(bBase64) return Convert.FromBase64String(strData); - - MemoryStream ms = new MemoryStream(); - -#if ModernKeePassLib || KeePassRT - Encoding enc = StrUtil.Utf8; -#else - Encoding enc = Encoding.ASCII; -#endif - - string[] v = strData.Split('%'); - byte[] pb = enc.GetBytes(v[0]); - ms.Write(pb, 0, pb.Length); - for(int i = 1; i < v.Length; ++i) - { - ms.WriteByte(Convert.ToByte(v[i].Substring(0, 2), 16)); - pb = enc.GetBytes(v[i].Substring(2)); - ms.Write(pb, 0, pb.Length); - } - - pb = ms.ToArray(); - ms.Dispose(); - return pb; - } - - /// - /// Remove placeholders from a string (wrapped in '{' and '}'). - /// This doesn't remove environment variables (wrapped in '%'). - /// - public static string RemovePlaceholders(string str) - { - if(str == null) { Debug.Assert(false); return string.Empty; } - - while(true) - { - int iPlhStart = str.IndexOf('{'); - if(iPlhStart < 0) break; - - int iPlhEnd = str.IndexOf('}', iPlhStart); // '{' might be at end - if(iPlhEnd < 0) break; - - str = (str.Substring(0, iPlhStart) + str.Substring(iPlhEnd + 1)); - } - - return str; - } - - public static StrEncodingInfo GetEncoding(StrEncodingType t) - { - foreach(StrEncodingInfo sei in StrUtil.Encodings) - { - if(sei.Type == t) return sei; - } - - return null; - } - - public static StrEncodingInfo GetEncoding(string strName) - { - foreach(StrEncodingInfo sei in StrUtil.Encodings) - { - if(sei.Name == strName) return sei; - } - - return null; - } - - private static string[] m_vPrefSepChars = null; - /// - /// Find a character that does not occur within a given text. - /// - public static char GetUnusedChar(string strText) - { - if(strText == null) { Debug.Assert(false); return '@'; } - - if(m_vPrefSepChars == null) - m_vPrefSepChars = new string[5] { - "@!$%#/\\:;,.*-_?", - PwCharSet.UpperCase, PwCharSet.LowerCase, - PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial - }; - - for(int i = 0; i < m_vPrefSepChars.Length; ++i) - { - foreach(char ch in m_vPrefSepChars[i]) - { - if(strText.IndexOf(ch) < 0) return ch; - } - } - - for(char ch = '\u00C0'; ch < char.MaxValue; ++ch) - { - if(strText.IndexOf(ch) < 0) return ch; - } - - return char.MinValue; - } - - public static char ByteToSafeChar(byte bt) - { - const char chDefault = '.'; - - // 00-1F are C0 control chars - if(bt < 0x20) return chDefault; - - // 20-7F are basic Latin; 7F is DEL - if(bt < 0x7F) return (char)bt; - - // 80-9F are C1 control chars - if(bt < 0xA0) return chDefault; - - // A0-FF are Latin-1 supplement; AD is soft hyphen - if(bt == 0xAD) return '-'; - return (char)bt; - } - - public static int Count(string str, string strNeedle) - { - if(str == null) { Debug.Assert(false); return 0; } - if(string.IsNullOrEmpty(strNeedle)) { Debug.Assert(false); return 0; } - - int iOffset = 0, iCount = 0; - while(iOffset < str.Length) - { - int p = str.IndexOf(strNeedle, iOffset); - if(p < 0) break; - - ++iCount; - iOffset = p + 1; - } - - return iCount; - } - - internal static string ReplaceNulls(string str) - { - if(str == null) { Debug.Assert(false); return null; } - - if(str.IndexOf('\0') < 0) return str; - - // Replacing null characters by spaces is the - // behavior of Notepad (on Windows 10) - return str.Replace('\0', ' '); - } - } -} diff --git a/ModernKeePassLib/Utility/StreamExtensions.cs b/ModernKeePassLib/Utility/StreamExtensions.cs deleted file mode 100644 index 499a4c2..0000000 --- a/ModernKeePassLib/Utility/StreamExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.IO; -using Windows.Storage.Streams; - -namespace ModernKeePassLibPCL.Utility -{ - public static class StreamExtensions - { - public static Stream AsStream(this IRandomAccessStream inputStream) - { - var reader = new DataReader(inputStream.GetInputStreamAt(0)); - var bytes = new byte[inputStream.Size]; - reader.LoadAsync((uint)inputStream.Size).GetResults(); - reader.ReadBytes(bytes); - return new MemoryStream(bytes); - } - } -} diff --git a/ModernKeePassLib/Utility/TimeUtil.cs b/ModernKeePassLib/Utility/TimeUtil.cs deleted file mode 100644 index 54f0e77..0000000 --- a/ModernKeePassLib/Utility/TimeUtil.cs +++ /dev/null @@ -1,482 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Text; - -using ModernKeePassLib.Interfaces; - -namespace ModernKeePassLib.Utility -{ - /// - /// Contains various static time structure manipulation and conversion - /// routines. - /// - public static class TimeUtil - { - /// - /// Length of a compressed PW_TIME structure in bytes. - /// - public const int PwTimeLength = 7; - - public static readonly DateTime SafeMinValueUtc = new DateTime( - DateTime.MinValue.Ticks + TimeSpan.TicksPerDay, DateTimeKind.Utc); - public static readonly DateTime SafeMaxValueUtc = new DateTime( - DateTime.MaxValue.Ticks - TimeSpan.TicksPerDay, DateTimeKind.Utc); - -#if !KeePassLibSD - private static string m_strDtfStd = null; - private static string m_strDtfDate = null; -#endif - - // private static long m_lTicks2PowLess1s = 0; - - private static DateTime? m_odtUnixRoot = null; - public static DateTime UnixRoot - { - get - { - if(m_odtUnixRoot.HasValue) return m_odtUnixRoot.Value; - - DateTime dtRoot = new DateTime(1970, 1, 1, 0, 0, 0, 0, - DateTimeKind.Utc); - - m_odtUnixRoot = dtRoot; - return dtRoot; - } - } - - /// - /// Pack a DateTime object into 5 bytes. Layout: 2 zero bits, - /// year 12 bits, month 4 bits, day 5 bits, hour 5 bits, minute 6 - /// bits, second 6 bits. - /// - [Obsolete] - public static byte[] PackTime(DateTime dt) - { - dt = ToLocal(dt, true); - - byte[] pb = new byte[5]; - - // Pack time to 5 byte structure: - // Byte bits: 11111111 22222222 33333333 44444444 55555555 - // Contents : 00YYYYYY YYYYYYMM MMDDDDDH HHHHMMMM MMSSSSSS - pb[0] = (byte)((dt.Year >> 6) & 0x3F); - pb[1] = (byte)(((dt.Year & 0x3F) << 2) | ((dt.Month >> 2) & 0x03)); - pb[2] = (byte)(((dt.Month & 0x03) << 6) | ((dt.Day & 0x1F) << 1) | - ((dt.Hour >> 4) & 0x01)); - pb[3] = (byte)(((dt.Hour & 0x0F) << 4) | ((dt.Minute >> 2) & 0x0F)); - pb[4] = (byte)(((dt.Minute & 0x03) << 6) | (dt.Second & 0x3F)); - - return pb; - } - - /// - /// Unpack a packed time (5 bytes, packed by the PackTime - /// member function) to a DateTime object. - /// - /// Packed time, 5 bytes. - /// Unpacked DateTime object. - [Obsolete] - public static DateTime UnpackTime(byte[] pb) - { - Debug.Assert((pb != null) && (pb.Length == 5)); - if(pb == null) throw new ArgumentNullException("pb"); - if(pb.Length != 5) throw new ArgumentException(); - - int n1 = pb[0], n2 = pb[1], n3 = pb[2], n4 = pb[3], n5 = pb[4]; - - // Unpack 5 byte structure to date and time - int nYear = (n1 << 6) | (n2 >> 2); - int nMonth = ((n2 & 0x00000003) << 2) | (n3 >> 6); - int nDay = (n3 >> 1) & 0x0000001F; - int nHour = ((n3 & 0x00000001) << 4) | (n4 >> 4); - int nMinute = ((n4 & 0x0000000F) << 2) | (n5 >> 6); - int nSecond = n5 & 0x0000003F; - - return (new DateTime(nYear, nMonth, nDay, nHour, nMinute, - nSecond, DateTimeKind.Local)).ToUniversalTime(); - } - - /// - /// Pack a DateTime object into 7 bytes (PW_TIME). - /// - /// Object to be encoded. - /// Packed time, 7 bytes (PW_TIME). - [Obsolete] - public static byte[] PackPwTime(DateTime dt) - { - Debug.Assert(PwTimeLength == 7); - - dt = ToLocal(dt, true); - - byte[] pb = new byte[7]; - pb[0] = (byte)(dt.Year & 0xFF); - pb[1] = (byte)(dt.Year >> 8); - pb[2] = (byte)dt.Month; - pb[3] = (byte)dt.Day; - pb[4] = (byte)dt.Hour; - pb[5] = (byte)dt.Minute; - pb[6] = (byte)dt.Second; - - return pb; - } - - /// - /// Unpack a packed time (7 bytes, PW_TIME) to a DateTime object. - /// - /// Packed time, 7 bytes. - /// Unpacked DateTime object. - [Obsolete] - public static DateTime UnpackPwTime(byte[] pb) - { - Debug.Assert(PwTimeLength == 7); - - Debug.Assert(pb != null); if(pb == null) throw new ArgumentNullException("pb"); - Debug.Assert(pb.Length == 7); if(pb.Length != 7) throw new ArgumentException(); - - return (new DateTime(((int)pb[1] << 8) | (int)pb[0], (int)pb[2], (int)pb[3], - (int)pb[4], (int)pb[5], (int)pb[6], DateTimeKind.Local)).ToUniversalTime(); - } - - /// - /// Convert a DateTime object to a displayable string. - /// - /// DateTime object to convert to a string. - /// String representing the specified DateTime object. - public static string ToDisplayString(DateTime dt) - { - return ToLocal(dt, true).ToString(); - } - - public static string ToDisplayStringDateOnly(DateTime dt) - { - return ToLocal(dt, true).ToString("d"); - } - - public static DateTime FromDisplayString(string strDisplay) - { - DateTime dt; - if(FromDisplayStringEx(strDisplay, out dt)) return dt; - return DateTime.Now; - } - - public static bool FromDisplayStringEx(string strDisplay, out DateTime dt) - { -#if KeePassLibSD - try { dt = ToLocal(DateTime.Parse(strDisplay), true); return true; } - catch(Exception) { } -#else - if(DateTime.TryParse(strDisplay, out dt)) - { - dt = ToLocal(dt, true); - return true; - } - - // For some custom formats specified using the Control Panel, - // DateTime.ToString returns the correct string, but - // DateTime.TryParse fails (e.g. for "//dd/MMM/yyyy"); - // https://sourceforge.net/p/keepass/discussion/329221/thread/3a225b29/?limit=25&page=1#c6ae - if((m_strDtfStd == null) || (m_strDtfDate == null)) - { - DateTime dtUni = new DateTime(2111, 3, 4, 5, 6, 7, DateTimeKind.Local); - m_strDtfStd = DeriveCustomFormat(ToDisplayString(dtUni), dtUni); - m_strDtfDate = DeriveCustomFormat(ToDisplayStringDateOnly(dtUni), dtUni); - } - const DateTimeStyles dts = DateTimeStyles.AllowWhiteSpaces; - if(DateTime.TryParseExact(strDisplay, m_strDtfStd, null, dts, out dt)) - { - dt = ToLocal(dt, true); - return true; - } - if(DateTime.TryParseExact(strDisplay, m_strDtfDate, null, dts, out dt)) - { - dt = ToLocal(dt, true); - return true; - } -#endif - - Debug.Assert(false); - return false; - } - -#if !KeePassLibSD - private static string DeriveCustomFormat(string strDT, DateTime dt) - { - string[] vPlh = new string[] { - // Names, sorted by length - "MMMM", "dddd", - "MMM", "ddd", - "gg", "g", - - // Numbers, the ones with prefix '0' first - "yyyy", "yyy", "yy", "y", - "MM", "M", - "dd", "d", - "HH", "hh", "H", "h", - "mm", "m", - "ss", "s", - - "tt", "t" - }; - - List lValues = new List(); - foreach(string strPlh in vPlh) - { - string strEval = strPlh; - if(strEval.Length == 1) strEval = @"%" + strPlh; // Make custom - - lValues.Add(dt.ToString(strEval)); - } - - StringBuilder sbAll = new StringBuilder(); - sbAll.Append("dfFghHKmMstyz:/\"\'\\%"); - sbAll.Append(strDT); - foreach(string strVEnum in lValues) { sbAll.Append(strVEnum); } - - List lCodes = new List(); - for(int i = 0; i < vPlh.Length; ++i) - { - char ch = StrUtil.GetUnusedChar(sbAll.ToString()); - lCodes.Add(ch); - sbAll.Append(ch); - } - - string str = strDT; - for(int i = 0; i < vPlh.Length; ++i) - { - string strValue = lValues[i]; - if(string.IsNullOrEmpty(strValue)) continue; - - str = str.Replace(strValue, new string(lCodes[i], 1)); - } - - StringBuilder sbFmt = new StringBuilder(); - bool bInLiteral = false; - foreach(char ch in str) - { - int iCode = lCodes.IndexOf(ch); - - // The escape character doesn't work correctly (e.g. - // "dd\\.MM\\.yyyy\\ HH\\:mm\\:ss" doesn't work, but - // "dd'.'MM'.'yyyy' 'HH':'mm':'ss" does); use '' instead - - // if(iCode >= 0) sbFmt.Append(vPlh[iCode]); - // else // Literal - // { - // sbFmt.Append('\\'); - // sbFmt.Append(ch); - // } - - if(iCode >= 0) - { - if(bInLiteral) { sbFmt.Append('\''); bInLiteral = false; } - sbFmt.Append(vPlh[iCode]); - } - else // Literal - { - if(!bInLiteral) { sbFmt.Append('\''); bInLiteral = true; } - sbFmt.Append(ch); - } - } - if(bInLiteral) sbFmt.Append('\''); - - return sbFmt.ToString(); - } -#endif - - public static string SerializeUtc(DateTime dt) - { - Debug.Assert(dt.Kind != DateTimeKind.Unspecified); - - string str = ToUtc(dt, false).ToString("s"); - if(!str.EndsWith("Z")) str += "Z"; - return str; - } - - public static bool TryDeserializeUtc(string str, out DateTime dt) - { - if(str == null) throw new ArgumentNullException("str"); - - if(str.EndsWith("Z")) str = str.Substring(0, str.Length - 1); - - bool bResult = StrUtil.TryParseDateTime(str, out dt); - if(bResult) dt = ToUtc(dt, true); - return bResult; - } - - public static double SerializeUnix(DateTime dt) - { - return (ToUtc(dt, false) - TimeUtil.UnixRoot).TotalSeconds; - } - - public static DateTime ConvertUnixTime(double dtUnix) - { - try { return TimeUtil.UnixRoot.AddSeconds(dtUnix); } - catch(Exception) { Debug.Assert(false); } - - return DateTime.UtcNow; - } - -#if !KeePassLibSD - [Obsolete] - public static DateTime? ParseUSTextDate(string strDate) - { - return ParseUSTextDate(strDate, DateTimeKind.Unspecified); - } - - private static string[] m_vUSMonths = null; - /// - /// Parse a US textual date string, like e.g. "January 02, 2012". - /// - public static DateTime? ParseUSTextDate(string strDate, DateTimeKind k) - { - if(strDate == null) { Debug.Assert(false); return null; } - - if(m_vUSMonths == null) - m_vUSMonths = new string[] { "January", "February", "March", - "April", "May", "June", "July", "August", "September", - "October", "November", "December" }; - - string str = strDate.Trim(); - for(int i = 0; i < m_vUSMonths.Length; ++i) - { - if(str.StartsWith(m_vUSMonths[i], StrUtil.CaseIgnoreCmp)) - { - str = str.Substring(m_vUSMonths[i].Length); - string[] v = str.Split(new char[] { ',', ';' }); - if((v == null) || (v.Length != 2)) return null; - - string strDay = v[0].Trim().TrimStart('0'); - int iDay, iYear; - if(int.TryParse(strDay, out iDay) && - int.TryParse(v[1].Trim(), out iYear)) - return new DateTime(iYear, i + 1, iDay, 0, 0, 0, k); - else { Debug.Assert(false); return null; } - } - } - - return null; - } -#endif - - private static readonly DateTime m_dtInvMin = - new DateTime(2999, 12, 27, 23, 59, 59, DateTimeKind.Utc); - private static readonly DateTime m_dtInvMax = - new DateTime(2999, 12, 29, 23, 59, 59, DateTimeKind.Utc); - public static int Compare(DateTime dtA, DateTime dtB, bool bUnkIsPast) - { - Debug.Assert(dtA.Kind == dtB.Kind); - - if(bUnkIsPast) - { - // 2999-12-28 23:59:59 in KeePass 1.x means 'unknown'; - // expect time zone corruption (twice) - // bool bInvA = ((dtA.Year == 2999) && (dtA.Month == 12) && - // (dtA.Day >= 27) && (dtA.Day <= 29) && (dtA.Minute == 59) && - // (dtA.Second == 59)); - // bool bInvB = ((dtB.Year == 2999) && (dtB.Month == 12) && - // (dtB.Day >= 27) && (dtB.Day <= 29) && (dtB.Minute == 59) && - // (dtB.Second == 59)); - // Faster due to internal implementation of DateTime: - bool bInvA = ((dtA >= m_dtInvMin) && (dtA <= m_dtInvMax) && - (dtA.Minute == 59) && (dtA.Second == 59)); - bool bInvB = ((dtB >= m_dtInvMin) && (dtB <= m_dtInvMax) && - (dtB.Minute == 59) && (dtB.Second == 59)); - - if(bInvA) return (bInvB ? 0 : -1); - if(bInvB) return 1; - } - - return dtA.CompareTo(dtB); - } - - internal static int CompareLastMod(ITimeLogger tlA, ITimeLogger tlB, - bool bUnkIsPast) - { - if(tlA == null) { Debug.Assert(false); return ((tlB == null) ? 0 : -1); } - if(tlB == null) { Debug.Assert(false); return 1; } - - return Compare(tlA.LastModificationTime, tlB.LastModificationTime, - bUnkIsPast); - } - - public static DateTime ToUtc(DateTime dt, bool bUnspecifiedIsUtc) - { - DateTimeKind k = dt.Kind; - if(k == DateTimeKind.Utc) return dt; - if(k == DateTimeKind.Local) return dt.ToUniversalTime(); - - Debug.Assert(k == DateTimeKind.Unspecified); - if(bUnspecifiedIsUtc) - return new DateTime(dt.Ticks, DateTimeKind.Utc); - return dt.ToUniversalTime(); // Unspecified = local - } - - public static DateTime ToLocal(DateTime dt, bool bUnspecifiedIsLocal) - { - DateTimeKind k = dt.Kind; - if(k == DateTimeKind.Local) return dt; - if(k == DateTimeKind.Utc) return dt.ToLocalTime(); - - Debug.Assert(k == DateTimeKind.Unspecified); - if(bUnspecifiedIsLocal) - return new DateTime(dt.Ticks, DateTimeKind.Local); - return dt.ToLocalTime(); // Unspecified = UTC - } - - /* internal static DateTime RoundToMultOf2PowLess1s(DateTime dt) - { - long l2Pow = m_lTicks2PowLess1s; - if(l2Pow == 0) - { - l2Pow = 1; - while(true) - { - l2Pow <<= 1; - if(l2Pow >= TimeSpan.TicksPerSecond) break; - } - l2Pow >>= 1; - m_lTicks2PowLess1s = l2Pow; - - Debug.Assert(TimeSpan.TicksPerSecond == 10000000L); // .NET - Debug.Assert(l2Pow == (1L << 23)); // .NET - } - - long l = dt.Ticks; - if((l % l2Pow) == 0L) return dt; - - // Round down to full second - l /= TimeSpan.TicksPerSecond; - l *= TimeSpan.TicksPerSecond; - - // Round up to multiple of l2Pow - long l2PowM1 = l2Pow - 1L; - l = (l + l2PowM1) & ~l2PowM1; - DateTime dtRnd = new DateTime(l, dt.Kind); - - Debug.Assert((dtRnd.Ticks % l2Pow) == 0L); - Debug.Assert(dtRnd.ToString("u") == dt.ToString("u")); - return dtRnd; - } */ - } -} diff --git a/ModernKeePassLib/Utility/TypeOverridePool.cs b/ModernKeePassLib/Utility/TypeOverridePool.cs deleted file mode 100644 index 454d5cb..0000000 --- a/ModernKeePassLib/Utility/TypeOverridePool.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -using ModernKeePassLib.Delegates; - -namespace KeePassLib.Utility -{ - public static class TypeOverridePool - { - private static Dictionary> g_d = - new Dictionary>(); - - public static void Register(Type t, GFunc f) - { - if(t == null) throw new ArgumentNullException("t"); - if(f == null) throw new ArgumentNullException("f"); - - g_d[t] = f; - } - - public static void Unregister(Type t) - { - if(t == null) throw new ArgumentNullException("t"); - - g_d.Remove(t); - } - - public static bool IsRegistered(Type t) - { - if(t == null) throw new ArgumentNullException("t"); - - return g_d.ContainsKey(t); - } - - public static T CreateInstance() - where T : new() - { - GFunc f; - if(g_d.TryGetValue(typeof(T), out f)) - return (T)(f()); - - return new T(); - } - } -} diff --git a/ModernKeePassLib/Utility/UrlUtil.cs b/ModernKeePassLib/Utility/UrlUtil.cs deleted file mode 100644 index adeef2e..0000000 --- a/ModernKeePassLib/Utility/UrlUtil.cs +++ /dev/null @@ -1,787 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Text; - -#if ModernKeePassLib -using Windows.Storage; -#endif - -using ModernKeePassLib.Native; - -namespace ModernKeePassLib.Utility -{ - /// - /// A class containing various static path utility helper methods (like - /// stripping extension from a file, etc.). - /// - public static class UrlUtil - { - private static readonly char[] m_vDirSeps = new char[] { - '\\', '/', UrlUtil.LocalDirSepChar }; -#if !ModernKeePassLib - private static readonly char[] m_vPathTrimCharsWs = new char[] { - '\"', ' ', '\t', '\r', '\n' }; -#endif - - public static char LocalDirSepChar - { -#if KeePassRT - get { return '\\'; } -#elif ModernKeePassLib - //get { return PortablePath.DirectorySeparatorChar; } - get { return '\\'; } -#else - get { return Path.DirectorySeparatorChar; } -#endif - } - - /// - /// Get the directory (path) of a file name. The returned string may be - /// terminated by a directory separator character. Example: - /// passing C:\\My Documents\\My File.kdb in - /// and true to - /// would produce this string: C:\\My Documents\\. - /// - /// Full path of a file. - /// Append a terminating directory separator - /// character to the returned path. - /// If true, the returned path - /// is guaranteed to be a valid directory path (for example X:\\ instead - /// of X:, overriding ). - /// This should only be set to true, if the returned path is directly - /// passed to some directory API. - /// Directory of the file. - public static string GetFileDirectory(string strFile, bool bAppendTerminatingChar, - bool bEnsureValidDirSpec) - { - Debug.Assert(strFile != null); - if(strFile == null) throw new ArgumentNullException("strFile"); - - int nLastSep = strFile.LastIndexOfAny(m_vDirSeps); - if(nLastSep < 0) return string.Empty; // No directory - - if(bEnsureValidDirSpec && (nLastSep == 2) && (strFile[1] == ':') && - (strFile[2] == '\\')) // Length >= 3 and Windows root directory - bAppendTerminatingChar = true; - - if(!bAppendTerminatingChar) return strFile.Substring(0, nLastSep); - return EnsureTerminatingSeparator(strFile.Substring(0, nLastSep), - (strFile[nLastSep] == '/')); - } - - /// - /// Gets the file name of the specified file (full path). Example: - /// if is C:\\My Documents\\My File.kdb - /// the returned string is My File.kdb. - /// - /// Full path of a file. - /// File name of the specified file. The return value is - /// an empty string ("") if the input parameter is null. - public static string GetFileName(string strPath) - { - Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath"); - - int nLastSep = strPath.LastIndexOfAny(m_vDirSeps); - - if(nLastSep < 0) return strPath; - if(nLastSep >= (strPath.Length - 1)) return string.Empty; - - return strPath.Substring(nLastSep + 1); - } - - /// - /// Strip the extension of a file. - /// - /// Full path of a file with extension. - /// File name without extension. - public static string StripExtension(string strPath) - { - Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath"); - - int nLastDirSep = strPath.LastIndexOfAny(m_vDirSeps); - int nLastExtDot = strPath.LastIndexOf('.'); - - if(nLastExtDot <= nLastDirSep) return strPath; - - return strPath.Substring(0, nLastExtDot); - } - - /// - /// Get the extension of a file. - /// - /// Full path of a file with extension. - /// Extension without prepending dot. - public static string GetExtension(string strPath) - { - Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath"); - - int nLastDirSep = strPath.LastIndexOfAny(m_vDirSeps); - int nLastExtDot = strPath.LastIndexOf('.'); - - if(nLastExtDot <= nLastDirSep) return string.Empty; - if(nLastExtDot == (strPath.Length - 1)) return string.Empty; - - return strPath.Substring(nLastExtDot + 1); - } - - /// - /// Ensure that a path is terminated with a directory separator character. - /// - /// Input path. - /// If true, a slash (/) is appended to - /// the string if it's not terminated already. If false, the - /// default system directory separator character is used. - /// Path having a directory separator as last character. - public static string EnsureTerminatingSeparator(string strPath, bool bUrl) - { - Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath"); - - int nLength = strPath.Length; - if(nLength <= 0) return string.Empty; - - char chLast = strPath[nLength - 1]; - - for(int i = 0; i < m_vDirSeps.Length; ++i) - { - if(chLast == m_vDirSeps[i]) return strPath; - } - - if(bUrl) return (strPath + '/'); - return (strPath + UrlUtil.LocalDirSepChar); - } - - /* /// - /// File access mode enumeration. Used by the FileAccessible - /// method. - /// - public enum FileAccessMode - { - /// - /// Opening a file in read mode. The specified file must exist. - /// - Read = 0, - - /// - /// Opening a file in create mode. If the file exists already, it - /// will be overwritten. If it doesn't exist, it will be created. - /// The return value is true, if data can be written to the - /// file. - /// - Create - } */ - - /* /// - /// Test if a specified path is accessible, either in read or write mode. - /// - /// Path to test. - /// Requested file access mode. - /// Returns true if the specified path is accessible in - /// the requested mode, otherwise the return value is false. - public static bool FileAccessible(string strFilePath, FileAccessMode fMode) - { - Debug.Assert(strFilePath != null); - if(strFilePath == null) throw new ArgumentNullException("strFilePath"); - - if(fMode == FileAccessMode.Read) - { - FileStream fs; - - try { fs = File.OpenRead(strFilePath); } - catch(Exception) { return false; } - if(fs == null) return false; - - fs.Close(); - return true; - } - else if(fMode == FileAccessMode.Create) - { - FileStream fs; - - try { fs = File.Create(strFilePath); } - catch(Exception) { return false; } - if(fs == null) return false; - - fs.Close(); - return true; - } - - return false; - } */ - - public static string GetQuotedAppPath(string strPath) - { - if(strPath == null) { Debug.Assert(false); return string.Empty; } - - // int nFirst = strPath.IndexOf('\"'); - // int nSecond = strPath.IndexOf('\"', nFirst + 1); - // if((nFirst >= 0) && (nSecond >= 0)) - // return strPath.Substring(nFirst + 1, nSecond - nFirst - 1); - // return strPath; - - string str = strPath.Trim(); - if(str.Length <= 1) return str; - if(str[0] != '\"') return str; - - int iSecond = str.IndexOf('\"', 1); - if(iSecond <= 0) return str; - - return str.Substring(1, iSecond - 1); - } - - public static string FileUrlToPath(string strUrl) - { - Debug.Assert(strUrl != null); - if(strUrl == null) throw new ArgumentNullException("strUrl"); - - string str = strUrl; - if(str.StartsWith(@"file:///", StrUtil.CaseIgnoreCmp)) - str = str.Substring(8, str.Length - 8); - - str = str.Replace('/', UrlUtil.LocalDirSepChar); - - return str; - } - - public static bool UnhideFile(string strFile) - { -#if (ModernKeePassLib || KeePassLibSD || KeePassRT) - return false; -#else - if(strFile == null) throw new ArgumentNullException("strFile"); - - try - { - FileAttributes fa = File.GetAttributes(strFile); - if((long)(fa & FileAttributes.Hidden) == 0) return false; - - return HideFile(strFile, false); - } - catch(Exception) { } - - return false; -#endif - } - - public static bool HideFile(string strFile, bool bHide) - { -#if (ModernKeePassLib || KeePassLibSD || KeePassRT) - return false; -#else - if(strFile == null) throw new ArgumentNullException("strFile"); - - try - { - FileAttributes fa = File.GetAttributes(strFile); - - if(bHide) fa = ((fa & ~FileAttributes.Normal) | FileAttributes.Hidden); - else // Unhide - { - fa &= ~FileAttributes.Hidden; - if((long)fa == 0) fa = FileAttributes.Normal; - } - - File.SetAttributes(strFile, fa); - return true; - } - catch(Exception) { } - - return false; -#endif - } - - public static string MakeRelativePath(string strBaseFile, string strTargetFile) - { - if(strBaseFile == null) throw new ArgumentNullException("strBasePath"); - if(strTargetFile == null) throw new ArgumentNullException("strTargetPath"); - if(strBaseFile.Length == 0) return strTargetFile; - if(strTargetFile.Length == 0) return string.Empty; - - // Test whether on different Windows drives - if((strBaseFile.Length >= 3) && (strTargetFile.Length >= 3)) - { - if((strBaseFile[1] == ':') && (strTargetFile[1] == ':') && - (strBaseFile[2] == '\\') && (strTargetFile[2] == '\\') && - (strBaseFile[0] != strTargetFile[0])) - return strTargetFile; - } - -#if (!KeePassLibSD && !KeePassUAP && !ModernKeePassLib) - if(NativeLib.IsUnix()) - { -#endif - bool bBaseUnc = IsUncPath(strBaseFile); - bool bTargetUnc = IsUncPath(strTargetFile); - if((!bBaseUnc && bTargetUnc) || (bBaseUnc && !bTargetUnc)) - return strTargetFile; - - string strBase = GetShortestAbsolutePath(strBaseFile); - string strTarget = GetShortestAbsolutePath(strTargetFile); - string[] vBase = strBase.Split(m_vDirSeps); - string[] vTarget = strTarget.Split(m_vDirSeps); - - int i = 0; - while((i < (vBase.Length - 1)) && (i < (vTarget.Length - 1)) && - (vBase[i] == vTarget[i])) { ++i; } - - StringBuilder sbRel = new StringBuilder(); - for(int j = i; j < (vBase.Length - 1); ++j) - { - if(sbRel.Length > 0) sbRel.Append(UrlUtil.LocalDirSepChar); - sbRel.Append(".."); - } - for(int k = i; k < vTarget.Length; ++k) - { - if(sbRel.Length > 0) sbRel.Append(UrlUtil.LocalDirSepChar); - sbRel.Append(vTarget[k]); - } - - return sbRel.ToString(); -#if (!KeePassLibSD && !KeePassUAP && !ModernKeePassLib) - } - - try // Windows - { - const int nMaxPath = NativeMethods.MAX_PATH * 2; - StringBuilder sb = new StringBuilder(nMaxPath + 2); - if(NativeMethods.PathRelativePathTo(sb, strBaseFile, 0, - strTargetFile, 0) == false) - return strTargetFile; - - string str = sb.ToString(); - while(str.StartsWith(".\\")) str = str.Substring(2, str.Length - 2); - - return str; - } - catch(Exception) { Debug.Assert(false); } - return strTargetFile; -#endif - } - - public static string MakeAbsolutePath(string strBaseFile, string strTargetFile) - { - if(strBaseFile == null) throw new ArgumentNullException("strBasePath"); - if(strTargetFile == null) throw new ArgumentNullException("strTargetPath"); - if(strBaseFile.Length == 0) return strTargetFile; - if(strTargetFile.Length == 0) return string.Empty; - - if(IsAbsolutePath(strTargetFile)) return strTargetFile; - - string strBaseDir = GetFileDirectory(strBaseFile, true, false); - return GetShortestAbsolutePath(strBaseDir + strTargetFile); - } - - public static bool IsAbsolutePath(string strPath) - { - if(strPath == null) throw new ArgumentNullException("strPath"); - if(strPath.Length == 0) return false; - - if(IsUncPath(strPath)) return true; - - try { return Path.IsPathRooted(strPath); } - catch(Exception) { Debug.Assert(false); } - - return true; - } - - public static string GetShortestAbsolutePath(string strPath) - { - if(strPath == null) throw new ArgumentNullException("strPath"); - if(strPath.Length == 0) return string.Empty; - - // Path.GetFullPath is incompatible with UNC paths traversing over - // different server shares (which are created by PathRelativePathTo); - // we need to build the absolute path on our own... - if(IsUncPath(strPath)) - { - char chSep = strPath[0]; - Debug.Assert(Array.IndexOf(m_vDirSeps, chSep) >= 0); - - List l = new List(); -#if !KeePassLibSD - string[] v = strPath.Split(m_vDirSeps, StringSplitOptions.None); -#else - string[] v = strPath.Split(m_vDirSeps); -#endif - Debug.Assert((v.Length >= 3) && (v[0].Length == 0) && - (v[1].Length == 0)); - - foreach(string strPart in v) - { - if(strPart.Equals(".")) continue; - else if(strPart.Equals("..")) - { - if(l.Count > 0) l.RemoveAt(l.Count - 1); - else { Debug.Assert(false); } - } - else l.Add(strPart); // Do not ignore zero length parts - } - - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < l.Count; ++i) - { - // Don't test length of sb, might be 0 due to initial UNC seps - if(i > 0) sb.Append(chSep); - - sb.Append(l[i]); - } - - return sb.ToString(); - } - - string str; - try - { -#if ModernKeePassLib - var dirT = StorageFolder.GetFolderFromPathAsync( - strPath).GetResults(); - str = dirT.Path; -#else - str = Path.GetFullPath(strPath); -#endif - } - catch(Exception) { Debug.Assert(false); return strPath; } - - Debug.Assert(str.IndexOf("\\..\\") < 0); - foreach(char ch in m_vDirSeps) - { - string strSep = new string(ch, 1); - str = str.Replace(strSep + "." + strSep, strSep); - } - - return str; - } - - public static int GetUrlLength(string strText, int nOffset) - { - if(strText == null) throw new ArgumentNullException("strText"); - if(nOffset > strText.Length) throw new ArgumentException(); // Not >= (0 len) - - int iPosition = nOffset, nLength = 0, nStrLen = strText.Length; - - while(iPosition < nStrLen) - { - char ch = strText[iPosition]; - ++iPosition; - - if((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n')) - break; - - ++nLength; - } - - return nLength; - } - - public static string RemoveScheme(string strUrl) - { - if(string.IsNullOrEmpty(strUrl)) return string.Empty; - - int nNetScheme = strUrl.IndexOf(@"://", StrUtil.CaseIgnoreCmp); - int nShScheme = strUrl.IndexOf(@":/", StrUtil.CaseIgnoreCmp); - int nSmpScheme = strUrl.IndexOf(@":", StrUtil.CaseIgnoreCmp); - - if((nNetScheme < 0) && (nShScheme < 0) && (nSmpScheme < 0)) - return strUrl; // No scheme - - int nMin = Math.Min(Math.Min((nNetScheme >= 0) ? nNetScheme : int.MaxValue, - (nShScheme >= 0) ? nShScheme : int.MaxValue), - (nSmpScheme >= 0) ? nSmpScheme : int.MaxValue); - - if(nMin == nNetScheme) return strUrl.Substring(nMin + 3); - if(nMin == nShScheme) return strUrl.Substring(nMin + 2); - return strUrl.Substring(nMin + 1); - } - - public static string ConvertSeparators(string strPath) - { - return ConvertSeparators(strPath, UrlUtil.LocalDirSepChar); - } - - public static string ConvertSeparators(string strPath, char chSeparator) - { - if(string.IsNullOrEmpty(strPath)) return string.Empty; - - strPath = strPath.Replace('/', chSeparator); - strPath = strPath.Replace('\\', chSeparator); - - return strPath; - } - - public static bool IsUncPath(string strPath) - { - if(strPath == null) throw new ArgumentNullException("strPath"); - - return (strPath.StartsWith("\\\\") || strPath.StartsWith("//")); - } - - public static string FilterFileName(string strName) - { - if(strName == null) { Debug.Assert(false); return string.Empty; } - - string str = strName; - - str = str.Replace('/', '-'); - str = str.Replace('\\', '-'); - str = str.Replace(":", string.Empty); - str = str.Replace("*", string.Empty); - str = str.Replace("?", string.Empty); - str = str.Replace("\"", string.Empty); - str = str.Replace(@"'", string.Empty); - str = str.Replace('<', '('); - str = str.Replace('>', ')'); - str = str.Replace('|', '-'); - - return str; - } - - /// - /// Get the host component of an URL. - /// This method is faster and more fault-tolerant than creating - /// an Uri object and querying its Host - /// property. - /// - /// - /// For the input s://u:p@d.tld:p/p?q#f the return - /// value is d.tld. - /// - public static string GetHost(string strUrl) - { - if(strUrl == null) { Debug.Assert(false); return string.Empty; } - - StringBuilder sb = new StringBuilder(); - bool bInExtHost = false; - for(int i = 0; i < strUrl.Length; ++i) - { - char ch = strUrl[i]; - if(bInExtHost) - { - if(ch == '/') - { - if(sb.Length == 0) { } // Ignore leading '/'s - else break; - } - else sb.Append(ch); - } - else // !bInExtHost - { - if(ch == ':') bInExtHost = true; - } - } - - string str = sb.ToString(); - if(str.Length == 0) str = strUrl; - - // Remove the login part - int nLoginLen = str.IndexOf('@'); - if(nLoginLen >= 0) str = str.Substring(nLoginLen + 1); - - // Remove the port - int iPort = str.LastIndexOf(':'); - if(iPort >= 0) str = str.Substring(0, iPort); - - return str; - } - - public static bool AssemblyEquals(string strExt, string strShort) - { - if((strExt == null) || (strShort == null)) { Debug.Assert(false); return false; } - - if(strExt.Equals(strShort, StrUtil.CaseIgnoreCmp) || - strExt.StartsWith(strShort + ",", StrUtil.CaseIgnoreCmp)) - return true; - - if(!strShort.EndsWith(".dll", StrUtil.CaseIgnoreCmp)) - { - if(strExt.Equals(strShort + ".dll", StrUtil.CaseIgnoreCmp) || - strExt.StartsWith(strShort + ".dll,", StrUtil.CaseIgnoreCmp)) - return true; - } - - if(!strShort.EndsWith(".exe", StrUtil.CaseIgnoreCmp)) - { - if(strExt.Equals(strShort + ".exe", StrUtil.CaseIgnoreCmp) || - strExt.StartsWith(strShort + ".exe,", StrUtil.CaseIgnoreCmp)) - return true; - } - - return false; - } - - public static string GetTempPath() - { - string strDir; - if(NativeLib.IsUnix()) - strDir = NativeMethods.GetUserRuntimeDir(); -#if KeePassUAP || ModernKeePassLib - else strDir = Windows.Storage.ApplicationData.Current.TemporaryFolder.Path; -#else - else strDir = Path.GetTempPath(); - - try - { - if(!Directory.Exists(strDir)) Directory.CreateDirectory(strDir); - } - catch(Exception) { Debug.Assert(false); } - -#endif - return strDir; - } - -#if !ModernKeePassLib && !KeePassLibSD - // Structurally mostly equivalent to UrlUtil.GetFileInfos - public static List GetFilePaths(string strDir, string strPattern, - SearchOption opt) - { - List l = new List(); - if(strDir == null) { Debug.Assert(false); return l; } - if(strPattern == null) { Debug.Assert(false); return l; } - - string[] v = Directory.GetFiles(strDir, strPattern, opt); - if(v == null) { Debug.Assert(false); return l; } - - // Only accept files with the correct extension; GetFiles may - // return additional files, see GetFiles documentation - string strExt = GetExtension(strPattern); - if(!string.IsNullOrEmpty(strExt) && (strExt.IndexOf('*') < 0) && - (strExt.IndexOf('?') < 0)) - { - strExt = "." + strExt; - - foreach(string strPathRaw in v) - { - if(strPathRaw == null) { Debug.Assert(false); continue; } - string strPath = strPathRaw.Trim(m_vPathTrimCharsWs); - if(strPath.Length == 0) { Debug.Assert(false); continue; } - Debug.Assert(strPath == strPathRaw); - - if(strPath.EndsWith(strExt, StrUtil.CaseIgnoreCmp)) - l.Add(strPathRaw); - } - } - else l.AddRange(v); - - return l; - } - - // Structurally mostly equivalent to UrlUtil.GetFilePaths - public static List GetFileInfos(DirectoryInfo di, string strPattern, - SearchOption opt) - { - List l = new List(); - if(di == null) { Debug.Assert(false); return l; } - if(strPattern == null) { Debug.Assert(false); return l; } - - FileInfo[] v = di.GetFiles(strPattern, opt); - if(v == null) { Debug.Assert(false); return l; } - - // Only accept files with the correct extension; GetFiles may - // return additional files, see GetFiles documentation - string strExt = GetExtension(strPattern); - if(!string.IsNullOrEmpty(strExt) && (strExt.IndexOf('*') < 0) && - (strExt.IndexOf('?') < 0)) - { - strExt = "." + strExt; - - foreach(FileInfo fi in v) - { - if(fi == null) { Debug.Assert(false); continue; } - string strPathRaw = fi.FullName; - if(strPathRaw == null) { Debug.Assert(false); continue; } - string strPath = strPathRaw.Trim(m_vPathTrimCharsWs); - if(strPath.Length == 0) { Debug.Assert(false); continue; } - Debug.Assert(strPath == strPathRaw); - - if(strPath.EndsWith(strExt, StrUtil.CaseIgnoreCmp)) - l.Add(fi); - } - } - else l.AddRange(v); - - return l; - } -#endif - - /// - /// Expand shell variables in a string. - /// [0] is the value of %1, etc. - /// - public static string ExpandShellVariables(string strText, string[] vParams) - { - if(strText == null) { Debug.Assert(false); return string.Empty; } - if(vParams == null) { Debug.Assert(false); vParams = new string[0]; } - - string str = strText; - NumberFormatInfo nfi = NumberFormatInfo.InvariantInfo; - - for(int i = 0; i <= 9; ++i) - { - string strPlh = "%" + i.ToString(nfi); - - string strValue = string.Empty; - if((i > 0) && ((i - 1) < vParams.Length)) - strValue = (vParams[i - 1] ?? string.Empty); - - str = str.Replace(strPlh, strValue); - - if(i == 1) - { - // %L is replaced by the long version of %1; e.g. - // HKEY_CLASSES_ROOT\\IE.AssocFile.URL\\Shell\\Open\\Command - str = str.Replace("%L", strValue); - str = str.Replace("%l", strValue); - } - } - - if(str.IndexOf("%*") >= 0) - { - StringBuilder sb = new StringBuilder(); - foreach(string strValue in vParams) - { - if(!string.IsNullOrEmpty(strValue)) - { - if(sb.Length > 0) sb.Append(' '); - sb.Append(strValue); - } - } - - str = str.Replace("%*", sb.ToString()); - } - - return str; - } - - public static char GetDriveLetter(string strPath) - { - if(strPath == null) throw new ArgumentNullException("strPath"); - - Debug.Assert(default(char) == '\0'); - if(strPath.Length < 3) return '\0'; - if((strPath[1] != ':') || (strPath[2] != '\\')) return '\0'; - - char ch = char.ToUpperInvariant(strPath[0]); - return (((ch >= 'A') && (ch <= 'Z')) ? ch : '\0'); - } - } -} diff --git a/ModernKeePassLib/Utility/XmlUtilEx.cs b/ModernKeePassLib/Utility/XmlUtilEx.cs deleted file mode 100644 index cafb410..0000000 --- a/ModernKeePassLib/Utility/XmlUtilEx.cs +++ /dev/null @@ -1,127 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2018 Dominik Reichl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Text; -using System.Xml; -using System.Xml.Serialization; -using Windows.Data.Xml.Dom; - -namespace ModernKeePassLib.Utility -{ - public static class XmlUtilEx - { - public static XmlDocument CreateXmlDocument() - { - XmlDocument d = new XmlDocument(); - - // .NET 4.5.2 and newer do not resolve external XML resources - // by default; for older .NET versions, we explicitly - // prevent resolving -#if !ModernKeePassLib - d.XmlResolver = null; // Default in old .NET: XmlUrlResolver object -#endif - - return d; - } - - public static XmlReaderSettings CreateXmlReaderSettings() - { - XmlReaderSettings xrs = new XmlReaderSettings(); - - xrs.CloseInput = false; - xrs.IgnoreComments = true; - xrs.IgnoreProcessingInstructions = true; - xrs.IgnoreWhitespace = true; - -#if KeePassUAP || ModernKeePassLib - xrs.DtdProcessing = DtdProcessing.Prohibit; -#else - // Also see PrepMonoDev.sh script - xrs.ProhibitDtd = true; // Obsolete in .NET 4, but still there - // xrs.DtdProcessing = DtdProcessing.Prohibit; // .NET 4 only - - xrs.ValidationType = ValidationType.None; - xrs.XmlResolver = null; -#endif - - return xrs; - } - - public static XmlReader CreateXmlReader(Stream s) - { - if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); } - - return XmlReader.Create(s, CreateXmlReaderSettings()); - } - - public static XmlWriterSettings CreateXmlWriterSettings(bool isVersionGreaterThan4 = false) - { - XmlWriterSettings xws = new XmlWriterSettings(); - - xws.CloseOutput = isVersionGreaterThan4; - xws.Encoding = StrUtil.Utf8; - xws.Indent = true; - xws.IndentChars = "\t"; - xws.NewLineOnAttributes = false; -#if ModernKeePassLib - // This is needed for Argon2Kdf write - xws.Async = true; -#endif - - return xws; - } - - public static XmlWriter CreateXmlWriter(Stream s, bool isVersionGreaterThan4 = false) - { - if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); } - - return XmlWriter.Create(s, CreateXmlWriterSettings(isVersionGreaterThan4)); - } - - public static void Serialize(Stream s, T t) - { - if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); } - - XmlSerializer xs = new XmlSerializer(typeof(T)); - using(XmlWriter xw = CreateXmlWriter(s)) - { - xs.Serialize(xw, t); - } - } - - public static T Deserialize(Stream s) - { - if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); } - - XmlSerializer xs = new XmlSerializer(typeof(T)); - - T t = default(T); - using(XmlReader xr = CreateXmlReader(s)) - { - t = (T)xs.Deserialize(xr); - } - - return t; - } - } -} diff --git a/ModernKeePassLib/app.config b/ModernKeePassLib/app.config deleted file mode 100644 index 9cf3b82..0000000 --- a/ModernKeePassLib/app.config +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ModernKeePassLib/project.json b/ModernKeePassLib/project.json deleted file mode 100644 index 5f63232..0000000 --- a/ModernKeePassLib/project.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "supports": {}, - "dependencies": { - "Microsoft.NETCore.Portable.Compatibility": "1.0.2", - "NETStandard.Library": "2.0.3", - "Portable.BouncyCastle": "1.8.2", - "Splat": "3.0.0", - "System.Runtime.WindowsRuntime": "4.3.0", - "System.Xml.ReaderWriter": "4.3.1", - "System.Xml.XmlSerializer": "4.3.0", - "Validation": "2.4.18" - }, - "frameworks": { - "netstandard1.2": {} - } -} \ No newline at end of file