diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 1ff0c42..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,63 +0,0 @@
-###############################################################################
-# Set default behavior to automatically normalize line endings.
-###############################################################################
-* text=auto
-
-###############################################################################
-# Set default behavior for command prompt diff.
-#
-# This is need for earlier builds of msysgit that does not have it on by
-# default for csharp files.
-# Note: This is only used by command line
-###############################################################################
-#*.cs diff=csharp
-
-###############################################################################
-# Set the merge driver for project and solution files
-#
-# Merging from the command prompt will add diff markers to the files if there
-# are conflicts (Merging from VS is not affected by the settings below, in VS
-# the diff markers are never inserted). Diff markers may cause the following
-# file extensions to fail to load in VS. An alternative would be to treat
-# these files as binary and thus will always conflict and require user
-# intervention with every merge. To do so, just uncomment the entries below
-###############################################################################
-#*.sln merge=binary
-#*.csproj merge=binary
-#*.vbproj merge=binary
-#*.vcxproj merge=binary
-#*.vcproj merge=binary
-#*.dbproj merge=binary
-#*.fsproj merge=binary
-#*.lsproj merge=binary
-#*.wixproj merge=binary
-#*.modelproj merge=binary
-#*.sqlproj merge=binary
-#*.wwaproj merge=binary
-
-###############################################################################
-# behavior for image files
-#
-# image files are treated as binary by default.
-###############################################################################
-#*.jpg binary
-#*.png binary
-#*.gif binary
-
-###############################################################################
-# diff behavior for common document formats
-#
-# Convert binary document formats to text before diffing them. This feature
-# is only available from the command line. Turn it on by uncommenting the
-# entries below.
-###############################################################################
-#*.doc diff=astextplain
-#*.DOC diff=astextplain
-#*.docx diff=astextplain
-#*.DOCX diff=astextplain
-#*.dot diff=astextplain
-#*.DOT diff=astextplain
-#*.pdf diff=astextplain
-#*.PDF diff=astextplain
-#*.rtf diff=astextplain
-#*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 1c9a181..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,242 +0,0 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# User-specific files
-*.suo
-*.user
-*.userosscache
-*.sln.docstates
-
-# User-specific files (MonoDevelop/Xamarin Studio)
-*.userprefs
-
-# Build results
-[Dd]ebug/
-[Dd]ebugPublic/
-[Rr]elease/
-[Rr]eleases/
-[Xx]64/
-[Xx]86/
-[Bb]uild/
-bld/
-[Bb]in/
-[Oo]bj/
-
-# Visual Studio 2015 cache/options directory
-.vs/
-# Uncomment if you have tasks that create the project's static files in wwwroot
-#wwwroot/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-# NUNIT
-*.VisualState.xml
-TestResult.xml
-
-# Build Results of an ATL Project
-[Dd]ebugPS/
-[Rr]eleasePS/
-dlldata.c
-
-# DNX
-project.lock.json
-artifacts/
-
-*_i.c
-*_p.c
-*_i.h
-*.ilk
-*.meta
-*.obj
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.svclog
-*.scc
-
-# Chutzpah Test files
-_Chutzpah*
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opendb
-*.opensdf
-*.sdf
-*.cachefile
-*.VC.db
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-*.sap
-
-# TFS 2012 Local Workspace
-$tf/
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-*.DotSettings.user
-
-# JustCode is a .NET coding add-in
-.JustCode
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# NCrunch
-_NCrunch_*
-.*crunch*.local.xml
-nCrunchTemp_*
-
-# MightyMoose
-*.mm.*
-AutoTest.Net/
-
-# Web workbench (sass)
-.sass-cache/
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.[Pp]ublish.xml
-*.azurePubxml
-
-# TODO: Un-comment the next line if you do not want to checkin
-# your web deploy settings because they may include unencrypted
-# passwords
-#*.pubxml
-*.publishproj
-
-# NuGet Packages
-*.nupkg
-# The packages folder can be ignored because of Package Restore
-**/packages/*
-# except build/, which is used as an MSBuild target.
-!**/packages/build/
-# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-# NuGet v3's project.json files produces more ignoreable files
-*.nuget.props
-*.nuget.targets
-
-# Microsoft Azure Build Output
-csx/
-*.build.csdef
-
-# Microsoft Azure Emulator
-ecf/
-rcf/
-
-# Windows Store app package directory
-AppPackages/
-BundleArtifacts/
-
-# Visual Studio cache files
-# files ending in .cache can be ignored
-*.[Cc]ache
-# but keep track of directories ending in .cache
-!*.[Cc]ache/
-
-# Others
-ClientBin/
-[Ss]tyle[Cc]op.*
-~$*
-*~
-*.dbmdl
-*.dbproj.schemaview
-*.pfx
-*.publishsettings
-node_modules/
-orleans.codegen.cs
-
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file
-# to a newer Visual Studio version. Backup files are not needed,
-# because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-
-# SQL Server files
-*.mdf
-*.ldf
-
-# Business Intelligence projects
-*.rdl.data
-*.bim.layout
-*.bim_*.settings
-
-# Microsoft Fakes
-FakesAssemblies/
-
-# GhostDoc plugin setting file
-*.GhostDoc.xml
-
-# Node.js Tools for Visual Studio
-.ntvs_analysis.dat
-
-# Visual Studio 6 build log
-*.plg
-
-# Visual Studio 6 workspace options file
-*.opt
-
-# Visual Studio LightSwitch build output
-**/*.HTMLClient/GeneratedArtifacts
-**/*.DesktopClient/GeneratedArtifacts
-**/*.DesktopClient/ModelManifest.xml
-**/*.Server/GeneratedArtifacts
-**/*.Server/ModelManifest.xml
-_Pvt_Extensions
-
-# LightSwitch generated files
-GeneratedArtifacts/
-ModelManifest.xml
-
-# Paket dependency manager
-.paket/paket.exe
-
-# FAKE - F# Make
-.fake/
diff --git a/.vs/ModernKeePass/v14/.suo b/.vs/ModernKeePass/v14/.suo
new file mode 100644
index 0000000..06f98fe
Binary files /dev/null and b/.vs/ModernKeePass/v14/.suo differ
diff --git a/ModernKeePass.sln b/ModernKeePass.sln
index 3335c3c..02ffe1d 100644
--- a/ModernKeePass.sln
+++ b/ModernKeePass.sln
@@ -3,6 +3,10 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass", "ModernKeePass\ModernKeePass.csproj", "{A0CFC681-769B-405A-8482-0CDEE595A91F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePassLib", "ModernKeePassLib\ModernKeePassLib.csproj", "{A207789D-9020-401B-9D0A-D0D2CFF721BD}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -14,6 +18,48 @@ Global
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|ARM.Build.0 = Debug|ARM
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|ARM.Deploy.0 = Debug|ARM
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|x64.ActiveCfg = Debug|x64
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|x64.Build.0 = Debug|x64
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|x64.Deploy.0 = Debug|x64
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|x86.ActiveCfg = Debug|x86
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|x86.Build.0 = Debug|x86
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Debug|x86.Deploy.0 = Debug|x86
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|ARM.ActiveCfg = Release|ARM
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|ARM.Build.0 = Release|ARM
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|ARM.Deploy.0 = Release|ARM
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|x64.ActiveCfg = Release|x64
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|x64.Build.0 = Release|x64
+ {A0CFC681-769B-405A-8482-0CDEE595A91F}.Release|x64.Deploy.0 = Release|x64
+ {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
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Debug|ARM.Build.0 = Debug|ARM
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Debug|x64.ActiveCfg = Debug|x64
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Debug|x64.Build.0 = Debug|x64
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Debug|x86.ActiveCfg = Debug|x86
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Debug|x86.Build.0 = Debug|x86
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Release|ARM.ActiveCfg = Release|ARM
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Release|ARM.Build.0 = Release|ARM
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Release|x64.ActiveCfg = Release|x64
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Release|x64.Build.0 = Release|x64
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Release|x86.ActiveCfg = Release|x86
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
diff --git a/ModernKeePass/ModernKeePass.Shared/App.xaml b/ModernKeePass/App.xaml
similarity index 100%
rename from ModernKeePass/ModernKeePass.Shared/App.xaml
rename to ModernKeePass/App.xaml
diff --git a/ModernKeePass/App.xaml.cs b/ModernKeePass/App.xaml.cs
new file mode 100644
index 0000000..7d0121f
--- /dev/null
+++ b/ModernKeePass/App.xaml.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.ApplicationModel;
+using Windows.ApplicationModel.Activation;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Navigation;
+
+// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227
+
+namespace ModernKeePass
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ sealed partial class App : Application
+ {
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ this.Suspending += OnSuspending;
+ }
+
+ ///
+ /// Invoked when the application is launched normally by the end user. Other entry points
+ /// will be used such as when the application is launched to open a specific file.
+ ///
+ /// Details about the launch request and process.
+ protected override void OnLaunched(LaunchActivatedEventArgs e)
+ {
+
+#if DEBUG
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ this.DebugSettings.EnableFrameRateCounter = true;
+ }
+#endif
+
+ Frame rootFrame = Window.Current.Content as Frame;
+
+ // Do not repeat app initialization when the Window already has content,
+ // just ensure that the window is active
+ if (rootFrame == null)
+ {
+ // Create a Frame to act as the navigation context and navigate to the first page
+ rootFrame = new Frame();
+ // Set the default language
+ rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
+
+ rootFrame.NavigationFailed += OnNavigationFailed;
+
+ if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
+ {
+ //TODO: Load state from previously suspended application
+ }
+
+ // Place the frame in the current Window
+ Window.Current.Content = rootFrame;
+ }
+
+ if (rootFrame.Content == null)
+ {
+ // When the navigation stack isn't restored navigate to the first page,
+ // configuring the new page by passing required information as a navigation
+ // parameter
+ rootFrame.Navigate(typeof(MainPage), e.Arguments);
+ }
+ // Ensure the current window is active
+ Window.Current.Activate();
+ }
+
+ ///
+ /// Invoked when Navigation to a certain page fails
+ ///
+ /// The Frame which failed navigation
+ /// Details about the navigation failure
+ void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
+ {
+ throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
+ }
+
+ ///
+ /// Invoked when application execution is being suspended. Application state is saved
+ /// without knowing whether the application will be terminated or resumed with the contents
+ /// of memory still intact.
+ ///
+ /// The source of the suspend request.
+ /// Details about the suspend request.
+ private void OnSuspending(object sender, SuspendingEventArgs e)
+ {
+ var deferral = e.SuspendingOperation.GetDeferral();
+ //TODO: Save application state and stop any background activity
+ deferral.Complete();
+ }
+ }
+}
diff --git a/ModernKeePass/ModernKeePass.Windows/Assets/Logo.scale-100.png b/ModernKeePass/Assets/Logo.scale-100.png
similarity index 100%
rename from ModernKeePass/ModernKeePass.Windows/Assets/Logo.scale-100.png
rename to ModernKeePass/Assets/Logo.scale-100.png
diff --git a/ModernKeePass/ModernKeePass.Windows/Assets/SmallLogo.scale-100.png b/ModernKeePass/Assets/SmallLogo.scale-100.png
similarity index 100%
rename from ModernKeePass/ModernKeePass.Windows/Assets/SmallLogo.scale-100.png
rename to ModernKeePass/Assets/SmallLogo.scale-100.png
diff --git a/ModernKeePass/ModernKeePass.Windows/Assets/SplashScreen.scale-100.png b/ModernKeePass/Assets/SplashScreen.scale-100.png
similarity index 100%
rename from ModernKeePass/ModernKeePass.Windows/Assets/SplashScreen.scale-100.png
rename to ModernKeePass/Assets/SplashScreen.scale-100.png
diff --git a/ModernKeePass/ModernKeePass.Windows/Assets/StoreLogo.scale-100.png b/ModernKeePass/Assets/StoreLogo.scale-100.png
similarity index 100%
rename from ModernKeePass/ModernKeePass.Windows/Assets/StoreLogo.scale-100.png
rename to ModernKeePass/Assets/StoreLogo.scale-100.png
diff --git a/ModernKeePass/ModernKeePass.Windows/MainPage.xaml b/ModernKeePass/MainPage.xaml
similarity index 100%
rename from ModernKeePass/ModernKeePass.Windows/MainPage.xaml
rename to ModernKeePass/MainPage.xaml
diff --git a/ModernKeePass/ModernKeePass.Windows/MainPage.xaml.cs b/ModernKeePass/MainPage.xaml.cs
similarity index 73%
rename from ModernKeePass/ModernKeePass.Windows/MainPage.xaml.cs
rename to ModernKeePass/MainPage.xaml.cs
index e297c76..f393f96 100644
--- a/ModernKeePass/ModernKeePass.Windows/MainPage.xaml.cs
+++ b/ModernKeePass/MainPage.xaml.cs
@@ -13,12 +13,12 @@ using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
-// Pour en savoir plus sur le modèle d'élément Page vierge, consultez la page http://go.microsoft.com/fwlink/?LinkId=234238
+// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace ModernKeePass
{
///
- /// Une page vide peut être utilisée seule ou constituer une page de destination au sein d'un frame.
+ /// An empty page that can be used on its own or navigated to within a Frame.
///
public sealed partial class MainPage : Page
{
diff --git a/ModernKeePass/ModernKeePass.Shared/App.xaml.cs b/ModernKeePass/ModernKeePass.Shared/App.xaml.cs
deleted file mode 100644
index 763ef39..0000000
--- a/ModernKeePass/ModernKeePass.Shared/App.xaml.cs
+++ /dev/null
@@ -1,137 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices.WindowsRuntime;
-using Windows.ApplicationModel;
-using Windows.ApplicationModel.Activation;
-using Windows.Foundation;
-using Windows.Foundation.Collections;
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Controls.Primitives;
-using Windows.UI.Xaml.Data;
-using Windows.UI.Xaml.Input;
-using Windows.UI.Xaml.Media;
-using Windows.UI.Xaml.Media.Animation;
-using Windows.UI.Xaml.Navigation;
-
-// Pour plus d'informations sur le modèle Application vide, consultez la page http://go.microsoft.com/fwlink/?LinkId=234227
-
-namespace ModernKeePass
-{
- ///
- /// Fournit un comportement spécifique à l'application afin de compléter la classe Application par défaut.
- ///
- public sealed partial class App : Application
- {
-#if WINDOWS_PHONE_APP
- private TransitionCollection transitions;
-#endif
-
- ///
- /// Initialise l'objet d'application de singleton. Il s'agit de la première ligne du code créé
- /// à être exécutée. Elle correspond donc à l'équivalent logique de main() ou WinMain().
- ///
- public App()
- {
- this.InitializeComponent();
- this.Suspending += this.OnSuspending;
- }
-
- ///
- /// Invoqué lorsque l'application est lancée normalement par l'utilisateur final. D'autres points d'entrée
- /// sont utilisés lorsque l'application est lancée pour ouvrir un fichier spécifique, pour afficher
- /// des résultats de recherche, etc.
- ///
- /// Détails concernant la requête et le processus de lancement.
- protected override void OnLaunched(LaunchActivatedEventArgs e)
- {
-#if DEBUG
- if (System.Diagnostics.Debugger.IsAttached)
- {
- this.DebugSettings.EnableFrameRateCounter = true;
- }
-#endif
-
- Frame rootFrame = Window.Current.Content as Frame;
-
- // Ne répétez pas l'initialisation de l'application lorsque la fenêtre comporte déjà du contenu,
- // assurez-vous juste que la fenêtre est active
- if (rootFrame == null)
- {
- // Créez un Frame utilisable comme contexte de navigation et naviguez jusqu'à la première page
- rootFrame = new Frame();
-
- // TODO: modifier cette valeur à une taille de cache qui contient à votre application
- rootFrame.CacheSize = 1;
-
- if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
- {
- // TODO: chargez l'état de l'application précédemment suspendue
- }
-
- // Placez le frame dans la fenêtre active
- Window.Current.Content = rootFrame;
- }
-
- if (rootFrame.Content == null)
- {
-#if WINDOWS_PHONE_APP
- // Supprime la navigation tourniquet pour le démarrage.
- if (rootFrame.ContentTransitions != null)
- {
- this.transitions = new TransitionCollection();
- foreach (var c in rootFrame.ContentTransitions)
- {
- this.transitions.Add(c);
- }
- }
-
- rootFrame.ContentTransitions = null;
- rootFrame.Navigated += this.RootFrame_FirstNavigated;
-#endif
-
- // Quand la pile de navigation n'est pas restaurée, accédez à la première page,
- // puis configurez la nouvelle page en transmettant les informations requises en tant que
- // paramètre
- if (!rootFrame.Navigate(typeof(MainPage), e.Arguments))
- {
- throw new Exception("Failed to create initial page");
- }
- }
-
- // Vérifiez que la fenêtre actuelle est active
- Window.Current.Activate();
- }
-
-#if WINDOWS_PHONE_APP
- ///
- /// Restaure les transitions de contenu une fois l'application lancée.
- ///
- /// Objet où le gestionnaire est attaché.
- /// Détails sur l'événement de navigation.
- private void RootFrame_FirstNavigated(object sender, NavigationEventArgs e)
- {
- var rootFrame = sender as Frame;
- rootFrame.ContentTransitions = this.transitions ?? new TransitionCollection() { new NavigationThemeTransition() };
- rootFrame.Navigated -= this.RootFrame_FirstNavigated;
- }
-#endif
-
- ///
- /// Appelé lorsque l'exécution de l'application est suspendue. L'état de l'application est enregistré
- /// sans savoir si l'application pourra se fermer ou reprendre sans endommager
- /// le contenu de la mémoire.
- ///
- /// Source de la requête de suspension.
- /// Détails de la requête de suspension.
- private void OnSuspending(object sender, SuspendingEventArgs e)
- {
- var deferral = e.SuspendingOperation.GetDeferral();
-
- // TODO: enregistrez l'état de l'application et arrêtez toute activité en arrière-plan
- deferral.Complete();
- }
- }
-}
\ No newline at end of file
diff --git a/ModernKeePass/ModernKeePass.Shared/ModernKeePass.Shared.projitems b/ModernKeePass/ModernKeePass.Shared/ModernKeePass.Shared.projitems
deleted file mode 100644
index d65c5f2..0000000
--- a/ModernKeePass/ModernKeePass.Shared/ModernKeePass.Shared.projitems
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
- $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
- true
- fde03897-a8b0-4c28-9068-7edbb649e676
-
-
- ModernKeePass
-
-
-
- Designer
-
-
- App.xaml
-
-
-
diff --git a/ModernKeePass/ModernKeePass.Shared/ModernKeePass.Shared.shproj b/ModernKeePass/ModernKeePass.Shared/ModernKeePass.Shared.shproj
deleted file mode 100644
index 048fae7..0000000
--- a/ModernKeePass/ModernKeePass.Shared/ModernKeePass.Shared.shproj
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- fde03897-a8b0-4c28-9068-7edbb649e676
-
-
-
-
-
-
-
-
diff --git a/ModernKeePass/ModernKeePass.Windows/Properties/AssemblyInfo.cs b/ModernKeePass/ModernKeePass.Windows/Properties/AssemblyInfo.cs
deleted file mode 100644
index 14834b6..0000000
--- a/ModernKeePass/ModernKeePass.Windows/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// Les informations générales relatives à un assembly dépendent de
-// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
-// associées à un assembly.
-[assembly: AssemblyTitle("ModernKeePass.Windows")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ModernKeePass.Windows")]
-[assembly: AssemblyCopyright("Copyright © 2017")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
-//
-// Version principale
-// Version secondaire
-// Numéro de build
-// Révision
-//
-// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
-// en utilisant '*', comme indiqué ci-dessous :
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
-[assembly: ComVisible(false)]
\ No newline at end of file
diff --git a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/Logo.scale-240.png b/ModernKeePass/ModernKeePass.WindowsPhone/Assets/Logo.scale-240.png
deleted file mode 100644
index 76921ca..0000000
Binary files a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/Logo.scale-240.png and /dev/null differ
diff --git a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/SmallLogo.scale-240.png b/ModernKeePass/ModernKeePass.WindowsPhone/Assets/SmallLogo.scale-240.png
deleted file mode 100644
index 3166301..0000000
Binary files a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/SmallLogo.scale-240.png and /dev/null differ
diff --git a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/SplashScreen.scale-240.png b/ModernKeePass/ModernKeePass.WindowsPhone/Assets/SplashScreen.scale-240.png
deleted file mode 100644
index 33f26b3..0000000
Binary files a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/SplashScreen.scale-240.png and /dev/null differ
diff --git a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/Square71x71Logo.scale-240.png b/ModernKeePass/ModernKeePass.WindowsPhone/Assets/Square71x71Logo.scale-240.png
deleted file mode 100644
index cfa54be..0000000
Binary files a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/Square71x71Logo.scale-240.png and /dev/null differ
diff --git a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/StoreLogo.scale-240.png b/ModernKeePass/ModernKeePass.WindowsPhone/Assets/StoreLogo.scale-240.png
deleted file mode 100644
index 47e084b..0000000
Binary files a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/StoreLogo.scale-240.png and /dev/null differ
diff --git a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/WideLogo.scale-240.png b/ModernKeePass/ModernKeePass.WindowsPhone/Assets/WideLogo.scale-240.png
deleted file mode 100644
index 6249d29..0000000
Binary files a/ModernKeePass/ModernKeePass.WindowsPhone/Assets/WideLogo.scale-240.png and /dev/null differ
diff --git a/ModernKeePass/ModernKeePass.WindowsPhone/MainPage.xaml b/ModernKeePass/ModernKeePass.WindowsPhone/MainPage.xaml
deleted file mode 100644
index d38f61b..0000000
--- a/ModernKeePass/ModernKeePass.WindowsPhone/MainPage.xaml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ModernKeePass/ModernKeePass.WindowsPhone/MainPage.xaml.cs b/ModernKeePass/ModernKeePass.WindowsPhone/MainPage.xaml.cs
deleted file mode 100644
index 8b8378a..0000000
--- a/ModernKeePass/ModernKeePass.WindowsPhone/MainPage.xaml.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices.WindowsRuntime;
-using Windows.Foundation;
-using Windows.Foundation.Collections;
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Controls.Primitives;
-using Windows.UI.Xaml.Data;
-using Windows.UI.Xaml.Input;
-using Windows.UI.Xaml.Media;
-using Windows.UI.Xaml.Navigation;
-
-// Pour en savoir plus sur le modèle d'élément Page vierge, consultez la page http://go.microsoft.com/fwlink/?LinkId=234238
-
-namespace ModernKeePass
-{
- ///
- /// Une page vide peut être utilisée seule ou constituer une page de destination au sein d'un frame.
- ///
- public sealed partial class MainPage : Page
- {
- public MainPage()
- {
- this.InitializeComponent();
-
- this.NavigationCacheMode = NavigationCacheMode.Required;
- }
-
- ///
- /// Invoqué lorsque cette page est sur le point d'être affichée dans un frame.
- ///
- /// Données d'événement décrivant la manière dont l'utilisateur a accédé à cette page.
- /// Ce paramètre est généralement utilisé pour configurer la page.
- protected override void OnNavigatedTo(NavigationEventArgs e)
- {
- // TODO: préparer la page pour affichage ici.
-
- // TODO: si votre application comporte plusieurs pages, assurez-vous que vous
- // gérez le bouton Retour physique en vous inscrivant à l’événement
- // Événement Windows.Phone.UI.Input.HardwareButtons.BackPressed.
- // Si vous utilisez le NavigationHelper fourni par certains modèles,
- // cet événement est géré automatiquement.
- }
- }
-}
diff --git a/ModernKeePass/ModernKeePass.WindowsPhone/ModernKeePass.WindowsPhone.csproj b/ModernKeePass/ModernKeePass.WindowsPhone/ModernKeePass.WindowsPhone.csproj
deleted file mode 100644
index df6ef3a..0000000
--- a/ModernKeePass/ModernKeePass.WindowsPhone/ModernKeePass.WindowsPhone.csproj
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- efa1e888-6dc2-4b02-ba0b-5fc1acf97cf4
- AppContainerExe
- Properties
- ModernKeePass
- ModernKeePass.WindowsPhone
- fr-FR
- 8.1
- 12
- 512
- {76F1466A-8B6D-4E39-A767-685A06062A39};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- true
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE;NETFX_CORE;WINDOWS_PHONE_APP
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE;NETFX_CORE;WINDOWS_PHONE_APP
- prompt
- 4
-
-
- true
- bin\ARM\Debug\
- DEBUG;TRACE;NETFX_CORE;WINDOWS_PHONE_APP
- ;2008
- full
- ARM
- false
- prompt
- true
-
-
- bin\ARM\Release\
- TRACE;NETFX_CORE;WINDOWS_PHONE_APP
- true
- ;2008
- pdbonly
- ARM
- false
- prompt
- true
-
-
- true
- bin\x86\Debug\
- DEBUG;TRACE;NETFX_CORE;WINDOWS_PHONE_APP
- ;2008
- full
- x86
- false
- prompt
- true
-
-
- bin\x86\Release\
- TRACE;NETFX_CORE;WINDOWS_PHONE_APP
- true
- ;2008
- pdbonly
- x86
- false
- prompt
- true
-
-
-
-
-
-
- MainPage.xaml
-
-
-
-
-
- Designer
-
-
-
-
-
-
-
-
-
-
-
-
- MSBuild:Compile
- Designer
-
-
-
- 12.0
-
-
- WindowsPhoneApp
-
-
-
-
-
\ No newline at end of file
diff --git a/ModernKeePass/ModernKeePass.WindowsPhone/Package.appxmanifest b/ModernKeePass/ModernKeePass.WindowsPhone/Package.appxmanifest
deleted file mode 100644
index 73dde94..0000000
--- a/ModernKeePass/ModernKeePass.WindowsPhone/Package.appxmanifest
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
-
-
- ModernKeePass.WindowsPhone
- BG45
- Assets\StoreLogo.png
-
-
-
- 6.3.1
- 6.3.1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ModernKeePass/ModernKeePass.WindowsPhone/Properties/AssemblyInfo.cs b/ModernKeePass/ModernKeePass.WindowsPhone/Properties/AssemblyInfo.cs
deleted file mode 100644
index e4df05c..0000000
--- a/ModernKeePass/ModernKeePass.WindowsPhone/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// Les informations générales relatives à un assembly dépendent de
-// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
-// associées à un assembly.
-[assembly: AssemblyTitle("ModernKeePass.WindowsPhone")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ModernKeePass.WindowsPhone")]
-[assembly: AssemblyCopyright("Copyright © 2017")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
-//
-// Version principale
-// Version secondaire
-// Numéro de build
-// Révision
-//
-// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
-// en utilisant '*', comme indiqué ci-dessous :
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
-[assembly: ComVisible(false)]
\ No newline at end of file
diff --git a/ModernKeePass/ModernKeePass.Windows/ModernKeePass.Windows.csproj b/ModernKeePass/ModernKeePass.csproj
similarity index 87%
rename from ModernKeePass/ModernKeePass.Windows/ModernKeePass.Windows.csproj
rename to ModernKeePass/ModernKeePass.csproj
index 84af6ca..dfa27e7 100644
--- a/ModernKeePass/ModernKeePass.Windows/ModernKeePass.Windows.csproj
+++ b/ModernKeePass/ModernKeePass.csproj
@@ -1,23 +1,22 @@
-
+
Debug
AnyCPU
- 0ace72f3-93fe-46aa-9c2f-3c1fd500985d
+ {a0cfc681-769b-405a-8482-0cdee595a91f}
AppContainerExe
Properties
ModernKeePass
- ModernKeePass.Windows
- fr-FR
+ ModernKeePass
+ en-US
8.1
12
512
- true
{BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- ModernKeePass.Windows_TemporaryKey.pfx
-
+ ModernKeePass_TemporaryKey.pfx
+
AnyCPU
@@ -108,6 +107,9 @@
+
+ App.xaml
+
MainPage.xaml
@@ -117,26 +119,31 @@
Designer
-
-
-
+
+
+
-
-
-
-
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
MSBuild:Compile
Designer
+
12.0
-
+
-
\ No newline at end of file
+
diff --git a/ModernKeePass/ModernKeePass_TemporaryKey.pfx b/ModernKeePass/ModernKeePass_TemporaryKey.pfx
new file mode 100644
index 0000000..bfe0f25
Binary files /dev/null and b/ModernKeePass/ModernKeePass_TemporaryKey.pfx differ
diff --git a/ModernKeePass/ModernKeePass.Windows/Package.appxmanifest b/ModernKeePass/Package.appxmanifest
similarity index 74%
rename from ModernKeePass/ModernKeePass.Windows/Package.appxmanifest
rename to ModernKeePass/Package.appxmanifest
index 189c765..7814d16 100644
--- a/ModernKeePass/ModernKeePass.Windows/Package.appxmanifest
+++ b/ModernKeePass/Package.appxmanifest
@@ -1,13 +1,13 @@
-
- ModernKeePass.Windows
- BG45
+ ModernKeePass
+ GBE
Assets\StoreLogo.png
@@ -23,12 +23,12 @@
+ EntryPoint="ModernKeePass.App">
diff --git a/ModernKeePass/Properties/AssemblyInfo.cs b/ModernKeePass/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..72c65d3
--- /dev/null
+++ b/ModernKeePass/Properties/AssemblyInfo.cs
@@ -0,0 +1,29 @@
+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")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ModernKeePass")]
+[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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")]
+[assembly: ComVisible(false)]
\ No newline at end of file
diff --git a/ModernKeePass/obj/Debug/App.g.cs b/ModernKeePass/obj/Debug/App.g.cs
new file mode 100644
index 0000000..e69de29
diff --git a/ModernKeePass/obj/Debug/App.g.i.cs b/ModernKeePass/obj/Debug/App.g.i.cs
new file mode 100644
index 0000000..4de8f54
--- /dev/null
+++ b/ModernKeePass/obj/Debug/App.g.i.cs
@@ -0,0 +1,56 @@
+
+
+#pragma checksum "C:\Users\GBE\Source\Repos\ModernKeePass\ModernKeePass\App.xaml" "{406ea660-64cf-4c82-b6f0-42d48172a799}" "B68578AE122A4023FCD4890B9ACAD34D"
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+
+namespace ModernKeePass
+{
+#if !DISABLE_XAML_GENERATED_MAIN
+ public static class Program
+ {
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ static void Main(string[] args)
+ {
+ global::Windows.UI.Xaml.Application.Start((p) => new App());
+ }
+ }
+#endif
+
+ partial class App : global::Windows.UI.Xaml.Application
+ {
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 4.0.0.0")]
+ private bool _contentLoaded;
+
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public void InitializeComponent()
+ {
+ if (_contentLoaded)
+ return;
+
+ _contentLoaded = true;
+#if DEBUG && !DISABLE_XAML_GENERATED_BINDING_DEBUG_OUTPUT
+ DebugSettings.BindingFailed += (sender, args) =>
+ {
+ global::System.Diagnostics.Debug.WriteLine(args.Message);
+ };
+#endif
+#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
+ UnhandledException += (sender, e) =>
+ {
+ if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
+ };
+#endif
+ }
+ }
+}
+
diff --git a/ModernKeePass/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/ModernKeePass/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache
new file mode 100644
index 0000000..c66e947
Binary files /dev/null and b/ModernKeePass/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ
diff --git a/ModernKeePass/obj/Debug/MainPage.g.cs b/ModernKeePass/obj/Debug/MainPage.g.cs
new file mode 100644
index 0000000..e69de29
diff --git a/ModernKeePass/obj/Debug/MainPage.g.i.cs b/ModernKeePass/obj/Debug/MainPage.g.i.cs
new file mode 100644
index 0000000..a94ec6e
--- /dev/null
+++ b/ModernKeePass/obj/Debug/MainPage.g.i.cs
@@ -0,0 +1,35 @@
+
+
+#pragma checksum "C:\Users\GBE\Source\Repos\ModernKeePass\ModernKeePass\MainPage.xaml" "{406ea660-64cf-4c82-b6f0-42d48172a799}" "55D7A50FC62F9EB12C79A3D19681A59A"
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace ModernKeePass
+{
+ partial class MainPage : global::Windows.UI.Xaml.Controls.Page
+ {
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 4.0.0.0")]
+ private bool _contentLoaded;
+
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public void InitializeComponent()
+ {
+ if (_contentLoaded)
+ return;
+
+ _contentLoaded = true;
+ global::Windows.UI.Xaml.Application.LoadComponent(this, new global::System.Uri("ms-appx:///MainPage.xaml"), global::Windows.UI.Xaml.Controls.Primitives.ComponentResourceLocation.Application);
+
+ }
+ }
+}
+
+
+
diff --git a/ModernKeePass/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs b/ModernKeePass/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
new file mode 100644
index 0000000..e69de29
diff --git a/ModernKeePass/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs b/ModernKeePass/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
new file mode 100644
index 0000000..e69de29
diff --git a/ModernKeePass/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs b/ModernKeePass/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
new file mode 100644
index 0000000..e69de29
diff --git a/ModernKeePass/obj/Debug/XamlSaveStateFile.xml b/ModernKeePass/obj/Debug/XamlSaveStateFile.xml
new file mode 100644
index 0000000..1f7227f
--- /dev/null
+++ b/ModernKeePass/obj/Debug/XamlSaveStateFile.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/ModernKeePass/obj/Debug/XamlTypeInfo.g.cs b/ModernKeePass/obj/Debug/XamlTypeInfo.g.cs
new file mode 100644
index 0000000..e69de29
diff --git a/ModernKeePassLib/Collections/AutoTypeConfig.cs b/ModernKeePassLib/Collections/AutoTypeConfig.cs
new file mode 100644
index 0000000..6f45952
--- /dev/null
+++ b/ModernKeePassLib/Collections/AutoTypeConfig.cs
@@ -0,0 +1,220 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 void Add(AutoTypeAssociation a)
+ {
+ Debug.Assert(a != null); if(a == null) throw new ArgumentNullException("a");
+
+ m_lWindowAssocs.Add(a);
+ }
+
+ public AutoTypeAssociation GetAt(int iIndex)
+ {
+ if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count))
+ throw new ArgumentOutOfRangeException("iIndex");
+
+ return m_lWindowAssocs[iIndex];
+ }
+
+ public void RemoveAt(int iIndex)
+ {
+ if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count))
+ throw new ArgumentOutOfRangeException("iIndex");
+
+ m_lWindowAssocs.RemoveAt(iIndex);
+ }
+ }
+}
diff --git a/ModernKeePassLib/Collections/ProtectedBinaryDictionary.cs b/ModernKeePassLib/Collections/ProtectedBinaryDictionary.cs
new file mode 100644
index 0000000..6261682
--- /dev/null
+++ b/ModernKeePassLib/Collections/ProtectedBinaryDictionary.cs
@@ -0,0 +1,173 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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;
+using ModernKeePassLib.Utility;
+
+#if KeePassLibSD
+using ModernKeePassLibSD;
+#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/ProtectedStringDictionary.cs b/ModernKeePassLib/Collections/ProtectedStringDictionary.cs
new file mode 100644
index 0000000..e663f7e
--- /dev/null
+++ b/ModernKeePassLib/Collections/ProtectedStringDictionary.cs
@@ -0,0 +1,306 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 ModernKeePassLibSD;
+#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.ReadString() != kvp.Value.ReadString()) 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()
+ {
+ List v = new List();
+
+ foreach(string strKey in m_vStrings.Keys) v.Add(strKey);
+
+ return v;
+ }
+
+ public void EnableProtection(string strField, bool bProtect)
+ {
+ ProtectedString ps = Get(strField);
+ if(ps == null) return; // Nothing to do, no assert
+
+ if(ps.IsProtected != bProtect)
+ {
+ byte[] pbData = ps.ReadUtf8();
+ Set(strField, new ProtectedString(bProtect, pbData));
+ MemUtil.ZeroByteArray(pbData);
+ }
+ }
+ }
+}
diff --git a/ModernKeePassLib/Collections/PwObjectList.cs b/ModernKeePassLib/Collections/PwObjectList.cs
new file mode 100644
index 0000000..823e59e
--- /dev/null
+++ b/ModernKeePassLib/Collections/PwObjectList.cs
@@ -0,0 +1,303 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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);
+ }
+ }
+
+ ///
+ /// 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);
+ Debug.Assert(nIndex >= 0);
+
+ 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;
+ }
+ }
+
+ ///
+ /// 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 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
new file mode 100644
index 0000000..e67564f
--- /dev/null
+++ b/ModernKeePassLib/Collections/PwObjectPool.cs
@@ -0,0 +1,80 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.Delegates;
+using ModernKeePassLib.Interfaces;
+
+#if KeePassLibSD
+using ModernKeePassLibSD;
+#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[new PwUuidComparable(pgRoot.Uuid)] = pgRoot;
+ GroupHandler gh = delegate(PwGroup pg)
+ {
+ p.m_dict[new PwUuidComparable(pg.Uuid)] = pg;
+ return true;
+ };
+
+ EntryHandler eh = delegate(PwEntry pe)
+ {
+ p.m_dict[new PwUuidComparable(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(new PwUuidComparable(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;
+ }
+ }
+}
diff --git a/ModernKeePassLib/Collections/StringDictionaryEx.cs b/ModernKeePassLib/Collections/StringDictionaryEx.cs
new file mode 100644
index 0000000..a0223fc
--- /dev/null
+++ b/ModernKeePassLib/Collections/StringDictionaryEx.cs
@@ -0,0 +1,116 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 ModernKeePassLibSD;
+#endif
+
+namespace ModernKeePassLib.Collections
+{
+ public sealed class StringDictionaryEx : IDeepCloneable,
+ IEnumerable>
+ {
+ private SortedDictionary m_vDict =
+ new SortedDictionary();
+
+ public int Count
+ {
+ get { return m_vDict.Count; }
+ }
+
+ public StringDictionaryEx()
+ {
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return m_vDict.GetEnumerator();
+ }
+
+ public IEnumerator> GetEnumerator()
+ {
+ return m_vDict.GetEnumerator();
+ }
+
+ public StringDictionaryEx CloneDeep()
+ {
+ StringDictionaryEx plNew = new StringDictionaryEx();
+
+ foreach(KeyValuePair kvpStr in m_vDict)
+ plNew.Set(kvpStr.Key, kvpStr.Value);
+
+ return plNew;
+ }
+
+ public string Get(string strName)
+ {
+ Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
+
+ string s;
+ if(m_vDict.TryGetValue(strName, out s)) return s;
+
+ return null;
+ }
+
+ public bool Exists(string strName)
+ {
+ Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
+
+ return m_vDict.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)
+ {
+ Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField");
+ Debug.Assert(strNewValue != null); if(strNewValue == null) throw new ArgumentNullException("strNewValue");
+
+ m_vDict[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)
+ {
+ Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField");
+
+ return m_vDict.Remove(strField);
+ }
+ }
+}
diff --git a/ModernKeePassLib/Cryptography/Cipher/CipherPool.cs b/ModernKeePassLib/Cryptography/Cipher/CipherPool.cs
new file mode 100644
index 0000000..caef3f3
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/Cipher/CipherPool.cs
@@ -0,0 +1,157 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.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
+ {
+ if(m_poolGlobal != null) return m_poolGlobal;
+
+ m_poolGlobal = new CipherPool();
+ m_poolGlobal.AddCipher(new StandardAesEngine());
+
+ return m_poolGlobal;
+ }
+ }
+
+ ///
+ /// 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.EqualsValue(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.EqualsValue(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.EqualsValue(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/ICipherEngine.cs b/ModernKeePassLib/Cryptography/Cipher/ICipherEngine.cs
new file mode 100644
index 0000000..b26029a
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/Cipher/ICipherEngine.cs
@@ -0,0 +1,66 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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);
+ }
+}
diff --git a/ModernKeePassLib/Cryptography/Cipher/Salsa20Cipher.cs b/ModernKeePassLib/Cryptography/Cipher/Salsa20Cipher.cs
new file mode 100644
index 0000000..99b93b3
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/Cipher/Salsa20Cipher.cs
@@ -0,0 +1,188 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.
+
+using System;
+using System.Diagnostics;
+
+using ModernKeePassLib.Utility;
+
+namespace ModernKeePassLib.Cryptography.Cipher
+{
+ public sealed class Salsa20Cipher
+ {
+ private uint[] m_state = new uint[16];
+ private uint[] m_x = new uint[16]; // Working buffer
+
+ private byte[] m_output = new byte[64];
+ private int m_outputPos = 64;
+
+ private static readonly uint[] m_sigma = new uint[4]{
+ 0x61707865, 0x3320646E, 0x79622D32, 0x6B206574
+ };
+
+ public Salsa20Cipher(byte[] pbKey32, byte[] pbIV8)
+ {
+ KeySetup(pbKey32);
+ IvSetup(pbIV8);
+ }
+
+ ~Salsa20Cipher()
+ {
+ // Clear sensitive data
+ Array.Clear(m_state, 0, m_state.Length);
+ Array.Clear(m_x, 0, m_x.Length);
+ }
+
+ private void NextOutput()
+ {
+ uint[] x = m_x; // Local alias for working buffer
+
+ // Compiler/runtime might remove array bound checks after this
+ if(x.Length < 16) throw new InvalidOperationException();
+
+ Array.Copy(m_state, x, 16);
+
+ unchecked
+ {
+ for(int i = 0; i < 10; ++i) // (int i = 20; i > 0; i -= 2)
+ {
+ x[ 4] ^= Rotl32(x[ 0] + x[12], 7);
+ x[ 8] ^= Rotl32(x[ 4] + x[ 0], 9);
+ x[12] ^= Rotl32(x[ 8] + x[ 4], 13);
+ x[ 0] ^= Rotl32(x[12] + x[ 8], 18);
+ x[ 9] ^= Rotl32(x[ 5] + x[ 1], 7);
+ x[13] ^= Rotl32(x[ 9] + x[ 5], 9);
+ x[ 1] ^= Rotl32(x[13] + x[ 9], 13);
+ x[ 5] ^= Rotl32(x[ 1] + x[13], 18);
+ x[14] ^= Rotl32(x[10] + x[ 6], 7);
+ x[ 2] ^= Rotl32(x[14] + x[10], 9);
+ x[ 6] ^= Rotl32(x[ 2] + x[14], 13);
+ x[10] ^= Rotl32(x[ 6] + x[ 2], 18);
+ x[ 3] ^= Rotl32(x[15] + x[11], 7);
+ x[ 7] ^= Rotl32(x[ 3] + x[15], 9);
+ x[11] ^= Rotl32(x[ 7] + x[ 3], 13);
+ x[15] ^= Rotl32(x[11] + x[ 7], 18);
+ x[ 1] ^= Rotl32(x[ 0] + x[ 3], 7);
+ x[ 2] ^= Rotl32(x[ 1] + x[ 0], 9);
+ x[ 3] ^= Rotl32(x[ 2] + x[ 1], 13);
+ x[ 0] ^= Rotl32(x[ 3] + x[ 2], 18);
+ x[ 6] ^= Rotl32(x[ 5] + x[ 4], 7);
+ x[ 7] ^= Rotl32(x[ 6] + x[ 5], 9);
+ x[ 4] ^= Rotl32(x[ 7] + x[ 6], 13);
+ x[ 5] ^= Rotl32(x[ 4] + x[ 7], 18);
+ x[11] ^= Rotl32(x[10] + x[ 9], 7);
+ x[ 8] ^= Rotl32(x[11] + x[10], 9);
+ x[ 9] ^= Rotl32(x[ 8] + x[11], 13);
+ x[10] ^= Rotl32(x[ 9] + x[ 8], 18);
+ x[12] ^= Rotl32(x[15] + x[14], 7);
+ x[13] ^= Rotl32(x[12] + x[15], 9);
+ x[14] ^= Rotl32(x[13] + x[12], 13);
+ x[15] ^= Rotl32(x[14] + x[13], 18);
+ }
+
+ for(int i = 0; i < 16; ++i)
+ x[i] += m_state[i];
+
+ for(int i = 0; i < 16; ++i)
+ {
+ m_output[i << 2] = (byte)x[i];
+ m_output[(i << 2) + 1] = (byte)(x[i] >> 8);
+ m_output[(i << 2) + 2] = (byte)(x[i] >> 16);
+ m_output[(i << 2) + 3] = (byte)(x[i] >> 24);
+ }
+
+ m_outputPos = 0;
+ ++m_state[8];
+ if(m_state[8] == 0) ++m_state[9];
+ }
+ }
+
+ private static uint Rotl32(uint x, int b)
+ {
+ unchecked
+ {
+ return ((x << b) | (x >> (32 - b)));
+ }
+ }
+
+ private static uint U8To32Little(byte[] pb, int iOffset)
+ {
+ unchecked
+ {
+ return ((uint)pb[iOffset] | ((uint)pb[iOffset + 1] << 8) |
+ ((uint)pb[iOffset + 2] << 16) | ((uint)pb[iOffset + 3] << 24));
+ }
+ }
+
+ private void KeySetup(byte[] k)
+ {
+ if(k == null) throw new ArgumentNullException("k");
+ if(k.Length != 32) throw new ArgumentException();
+
+ m_state[1] = U8To32Little(k, 0);
+ m_state[2] = U8To32Little(k, 4);
+ m_state[3] = U8To32Little(k, 8);
+ m_state[4] = U8To32Little(k, 12);
+ m_state[11] = U8To32Little(k, 16);
+ m_state[12] = U8To32Little(k, 20);
+ m_state[13] = U8To32Little(k, 24);
+ m_state[14] = U8To32Little(k, 28);
+ m_state[0] = m_sigma[0];
+ m_state[5] = m_sigma[1];
+ m_state[10] = m_sigma[2];
+ m_state[15] = m_sigma[3];
+ }
+
+ private void IvSetup(byte[] pbIV)
+ {
+ if(pbIV == null) throw new ArgumentNullException("pbIV");
+ if(pbIV.Length != 8) throw new ArgumentException();
+
+ m_state[6] = U8To32Little(pbIV, 0);
+ m_state[7] = U8To32Little(pbIV, 4);
+ m_state[8] = 0;
+ m_state[9] = 0;
+ }
+
+ public void Encrypt(byte[] m, int nByteCount, bool bXor)
+ {
+ if(m == null) throw new ArgumentNullException("m");
+ if(nByteCount > m.Length) throw new ArgumentException();
+
+ int nBytesRem = nByteCount, nOffset = 0;
+ while(nBytesRem > 0)
+ {
+ Debug.Assert((m_outputPos >= 0) && (m_outputPos <= 64));
+ if(m_outputPos == 64) NextOutput();
+ Debug.Assert(m_outputPos < 64);
+
+ int nCopy = Math.Min(64 - m_outputPos, nBytesRem);
+
+ if(bXor) MemUtil.XorArray(m_output, m_outputPos, m, nOffset, nCopy);
+ else Array.Copy(m_output, m_outputPos, m, nOffset, nCopy);
+
+ m_outputPos += nCopy;
+ nBytesRem -= nCopy;
+ nOffset += nCopy;
+ }
+ }
+ }
+}
diff --git a/ModernKeePassLib/Cryptography/Cipher/StandardAesEngine.cs b/ModernKeePassLib/Cryptography/Cipher/StandardAesEngine.cs
new file mode 100644
index 0000000..ce41e3d
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/Cipher/StandardAesEngine.cs
@@ -0,0 +1,146 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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;
+
+using ModernKeePassLib.Resources;
+using ModernKeePassLib.Serialization;
+
+namespace ModernKeePassLib.Cryptography.Cipher
+{
+ ///
+ /// Standard AES cipher implementation.
+ ///
+ public sealed class StandardAesEngine : ICipherEngine
+ {
+ // private const CipherMode m_rCipherMode = CipherMode.CBC;
+ // private const PaddingMode m_rCipherPadding = PaddingMode.PKCS7;
+
+ private static PwUuid m_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
+ {
+ if(m_uuidAes == null)
+ {
+ m_uuidAes = new PwUuid(new byte[]{
+ 0x31, 0xC1, 0xF2, 0xE6, 0xBF, 0x71, 0x43, 0x50,
+ 0xBE, 0x58, 0x05, 0x21, 0x6A, 0xFC, 0x5A, 0xFF });
+ }
+
+ return m_uuidAes;
+ }
+ }
+
+ ///
+ /// 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 KLRes.EncAlgorithmAes; } }
+
+ 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 == false) throw new ArgumentException("Stream must be writable!");
+ }
+ else // Decrypt
+ {
+ Debug.Assert(stream.CanRead);
+ if(stream.CanRead == false) 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);
+
+ return new CryptoStream( s, "AES_CBC_PKCS7", bEncrypt, pbKey, pbIV);
+
+ }
+#if false
+
+ RijndaelManaged r = new RijndaelManaged();
+
+ if(r.BlockSize != 128) // AES block size
+ {
+ Debug.Assert(false);
+ r.BlockSize = 128;
+ }
+
+ byte[] pbLocalIV = new byte[16];
+ Array.Copy(pbIV, pbLocalIV, 16);
+ r.IV = pbLocalIV;
+
+ byte[] pbLocalKey = new byte[32];
+ Array.Copy(pbKey, pbLocalKey, 32);
+ r.KeySize = 256;
+ r.Key = pbLocalKey;
+
+ r.Mode = m_rCipherMode;
+ r.Padding = m_rCipherPadding;
+
+ ICryptoTransform iTransform = (bEncrypt ? r.CreateEncryptor() : r.CreateDecryptor());
+ Debug.Assert(iTransform != null);
+ if(iTransform == null) throw new SecurityException("Unable to create Rijndael 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
new file mode 100644
index 0000000..12fa42d
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/CryptoRandom.cs
@@ -0,0 +1,331 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 Windows.Security.Cryptography;
+//using System.Windows.Forms;
+//using System.Drawing;
+
+
+namespace ModernKeePassLib.Cryptography
+{
+ ///
+ /// Cryptographically strong 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 uint m_uCounter;
+ //private RNGCryptoServiceProvider m_rng = new RNGCryptoServiceProvider();
+ //private ulong m_uGeneratedBytesCount = 0;
+
+ // private object m_oSyncRoot = new object();
+
+ private static CryptoRandom m_pInstance = null;
+ public static CryptoRandom Instance
+ {
+ get
+ {
+ if(m_pInstance != null) return m_pInstance;
+
+ m_pInstance = new CryptoRandom();
+ return m_pInstance;
+ }
+ }
+
+#if KeePassWinRT
+ private CryptoRandom()
+ {
+ }
+
+ ///
+ /// 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)
+ {
+ // Not used in WinRT version
+ }
+
+
+ ///
+ /// 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 new byte[0]; // Allow zero-length array
+
+ byte[] pbRes;
+
+ Windows.Storage.Streams.IBuffer buffer = CryptographicBuffer.GenerateRandom(uRequestedBytes);
+ CryptographicBuffer.CopyToByteArray(buffer, out pbRes);
+ return pbRes;
+
+ }
+
+#else
+ ///
+ /// 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 r = new Random();
+ m_uCounter = (uint)r.Next();
+
+ AddEntropy(GetSystemData(r));
+ 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
+ SHA512Managed shaNew = new SHA512Managed();
+#else
+ SHA256Managed shaNew = new SHA256Managed();
+#endif
+ pbNewData = shaNew.ComputeHash(pbEntropy);
+ }
+
+ MemoryStream ms = new MemoryStream();
+ lock(m_oSyncRoot)
+ {
+ ms.Write(m_pbEntropyPool, 0, m_pbEntropyPool.Length);
+ ms.Write(pbNewData, 0, pbNewData.Length);
+
+ byte[] pbFinal = ms.ToArray();
+#if !KeePassLibSD
+ Debug.Assert(pbFinal.Length == (64 + pbNewData.Length));
+ SHA512Managed shaPool = new SHA512Managed();
+#else
+ SHA256Managed shaPool = new SHA256Managed();
+#endif
+ m_pbEntropyPool = shaPool.ComputeHash(pbFinal);
+ }
+ ms.Close();
+
+ }
+
+
+
+ private static byte[] GetSystemData(Random rWeak)
+ {
+
+ MemoryStream ms = new MemoryStream();
+ byte[] pb;
+
+ pb = MemUtil.UInt32ToBytes((uint)Environment.TickCount);
+ ms.Write(pb, 0, pb.Length);
+
+ pb = TimeUtil.PackTime(DateTime.Now);
+ ms.Write(pb, 0, pb.Length);
+
+#if !KeePassLibSD
+ Point pt = Cursor.Position;
+ pb = MemUtil.UInt32ToBytes((uint)pt.X);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt32ToBytes((uint)pt.Y);
+ ms.Write(pb, 0, pb.Length);
+#endif
+
+ pb = MemUtil.UInt32ToBytes((uint)rWeak.Next());
+ ms.Write(pb, 0, pb.Length);
+
+ pb = MemUtil.UInt32ToBytes((uint)NativeLib.GetPlatformID());
+ ms.Write(pb, 0, pb.Length);
+
+#if !KeePassLibSD
+ try
+ {
+ pb = MemUtil.UInt32ToBytes((uint)Environment.ProcessorCount);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt64ToBytes((ulong)Environment.WorkingSet);
+ ms.Write(pb, 0, pb.Length);
+
+ Version v = Environment.OSVersion.Version;
+ int nv = (v.Major << 28) + (v.MajorRevision << 24) +
+ (v.Minor << 20) + (v.MinorRevision << 16) +
+ (v.Revision << 12) + v.Build;
+ pb = MemUtil.UInt32ToBytes((uint)nv);
+ ms.Write(pb, 0, pb.Length);
+
+ Process p = Process.GetCurrentProcess();
+ pb = MemUtil.UInt64ToBytes((ulong)p.Handle.ToInt64());
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt32ToBytes((uint)p.HandleCount);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt32ToBytes((uint)p.Id);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt64ToBytes((ulong)p.NonpagedSystemMemorySize64);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt64ToBytes((ulong)p.PagedMemorySize64);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt64ToBytes((ulong)p.PagedSystemMemorySize64);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt64ToBytes((ulong)p.PeakPagedMemorySize64);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt64ToBytes((ulong)p.PeakVirtualMemorySize64);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt64ToBytes((ulong)p.PeakWorkingSet64);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt64ToBytes((ulong)p.PrivateMemorySize64);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt64ToBytes((ulong)p.StartTime.ToBinary());
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt64ToBytes((ulong)p.VirtualMemorySize64);
+ ms.Write(pb, 0, pb.Length);
+ pb = MemUtil.UInt64ToBytes((ulong)p.WorkingSet64);
+ ms.Write(pb, 0, pb.Length);
+
+ // Not supported in Mono 1.2.6:
+ // pb = MemUtil.UInt32ToBytes((uint)p.SessionId);
+ // ms.Write(pb, 0, pb.Length);
+ }
+ catch(Exception) { }
+#endif
+
+ pb = Guid.NewGuid().ToByteArray();
+ ms.Write(pb, 0, pb.Length);
+
+ byte[] pbAll = ms.ToArray();
+ ms.Close();
+ return pbAll;
+
+ }
+
+
+ private byte[] GetCspData()
+ {
+ uint length = 32;
+ byte[] pbCspRandom = new byte[length];
+
+ Windows.Storage.Streams.IBuffer buffer = CryptographicBuffer.GenerateRandom(length);
+
+ CryptographicBuffer.CopyToByteArray(buffer, pbCspRandom);
+ //m_rng.GetBytes(pbCspRandom);
+ return pbCspRandom;
+ }
+
+ private byte[] GenerateRandom256()
+ {
+
+ if(this.GenerateRandom256Pre != null)
+ this.GenerateRandom256Pre(this, EventArgs.Empty);
+
+ byte[] pbFinal;
+ lock(m_oSyncRoot)
+ {
+ unchecked { m_uCounter += 386047; } // Prime number
+ byte[] pbCounter = MemUtil.UInt32ToBytes(m_uCounter);
+
+ byte[] pbCspRandom = GetCspData();
+
+ MemoryStream ms = new MemoryStream();
+ ms.Write(m_pbEntropyPool, 0, m_pbEntropyPool.Length);
+ ms.Write(pbCounter, 0, pbCounter.Length);
+ ms.Write(pbCspRandom, 0, pbCspRandom.Length);
+ pbFinal = ms.ToArray();
+ Debug.Assert(pbFinal.Length == (m_pbEntropyPool.Length +
+ pbCounter.Length + pbCspRandom.Length));
+ ms.Close();
+
+ m_uGeneratedBytesCount += 32;
+ }
+
+ SHA256Managed sha256 = new SHA256Managed();
+ return sha256.ComputeHash(pbFinal);
+ }
+
+
+ ///
+ /// 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 new byte[0]; // Allow zero-length array
+
+ byte[] pbRes = new byte[uRequestedBytes];
+ long lPos = 0;
+
+ while(uRequestedBytes != 0)
+ {
+ byte[] pbRandom256 = GenerateRandom256();
+ Debug.Assert(pbRandom256.Length == 32);
+
+ long lCopy = (long)((uRequestedBytes < 32) ? uRequestedBytes : 32);
+
+#if !KeePassLibSD
+ Array.Copy(pbRandom256, 0, pbRes, lPos, lCopy);
+#else
+ Array.Copy(pbRandom256, 0, pbRes, (int)lPos, (int)lCopy);
+#endif
+
+ lPos += lCopy;
+ uRequestedBytes -= (uint)lCopy;
+ }
+
+ Debug.Assert((int)lPos == pbRes.Length);
+ return pbRes;
+ }
+
+#endif // !KeePassWinRT
+
+ }
+}
diff --git a/ModernKeePassLib/Cryptography/CryptoRandomStream.cs b/ModernKeePassLib/Cryptography/CryptoRandomStream.cs
new file mode 100644
index 0000000..8d585d4
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/CryptoRandomStream.cs
@@ -0,0 +1,208 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.Cryptography.Cipher;
+
+namespace ModernKeePassLib.Cryptography
+{
+ ///
+ /// Algorithms supported by CryptoRandomStream.
+ ///
+ public enum CrsAlgorithm
+ {
+ ///
+ /// Not supported.
+ ///
+ Null = 0,
+
+ ///
+ /// A variant of the ARCFour algorithm (RC4 incompatible).
+ ///
+ ArcFourVariant = 1,
+
+ ///
+ /// Salsa20 stream cipher algorithm.
+ ///
+ Salsa20 = 2,
+
+ Count = 3
+ }
+
+ ///
+ /// 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
+ {
+ private CrsAlgorithm m_crsAlgorithm;
+
+ private byte[] m_pbState = null;
+ private byte m_i = 0;
+ private byte m_j = 0;
+
+ private Salsa20Cipher m_salsa20 = 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.
+ /// Thrown if the
+ /// parameter is null.
+ /// Thrown if the
+ /// parameter contains no bytes or the
+ /// algorithm is unknown.
+ public CryptoRandomStream(CrsAlgorithm genAlgorithm, byte[] pbKey)
+ {
+ m_crsAlgorithm = genAlgorithm;
+
+ Debug.Assert(pbKey != null); if(pbKey == null) throw new ArgumentNullException("pbKey");
+
+ uint uKeyLen = (uint)pbKey.Length;
+ Debug.Assert(uKeyLen != 0); if(uKeyLen == 0) throw new ArgumentException();
+
+ if(genAlgorithm == CrsAlgorithm.ArcFourVariant)
+ {
+ // Fill the state linearly
+ m_pbState = new byte[256];
+ for(uint w = 0; w < 256; ++w) m_pbState[w] = (byte)w;
+
+ unchecked
+ {
+ byte j = 0, t;
+ uint inxKey = 0;
+ for(uint 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 >= uKeyLen) inxKey = 0;
+ }
+ }
+
+ GetRandomBytes(512); // Increases security, see cryptanalysis
+ }
+ else if(genAlgorithm == CrsAlgorithm.Salsa20)
+ {
+ byte[] pbKey32 = SHA256Managed.Instance.ComputeHash(pbKey);
+
+ byte[] pbIV = new byte[]{ 0xE8, 0x30, 0x09, 0x4B,
+ 0x97, 0x20, 0x5D, 0x2A }; // Unique constant
+
+ m_salsa20 = new Salsa20Cipher(pbKey32, pbIV);
+
+ }
+ else // Unknown algorithm
+ {
+ Debug.Assert(false);
+ throw new ArgumentException();
+ }
+ }
+
+ ///
+ /// Get random bytes.
+ ///
+ /// Number of random bytes to retrieve.
+ /// Returns random bytes.
+ public byte[] GetRandomBytes(uint uRequestedCount)
+ {
+ if(uRequestedCount == 0) return new byte[0];
+
+ byte[] pbRet = new byte[uRequestedCount];
+
+ if(m_crsAlgorithm == CrsAlgorithm.ArcFourVariant)
+ {
+ unchecked
+ {
+ for(uint w = 0; w < uRequestedCount; ++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 if(m_crsAlgorithm == CrsAlgorithm.Salsa20)
+ m_salsa20.Encrypt(pbRet, pbRet.Length, false);
+ else { Debug.Assert(false); }
+
+ return pbRet;
+ }
+
+ public ulong GetRandomUInt64()
+ {
+ byte[] pb = GetRandomBytes(8);
+
+ unchecked
+ {
+ 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);
+ }
+ }
+
+#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)
+ {
+ CryptoRandomStream c = new CryptoRandomStream(cra, pbKey);
+ c.GetRandomBytes((uint)nDataSize);
+ }
+ int nEnd = Environment.TickCount;
+
+ return (nEnd - nStart);
+ }
+#endif
+ }
+}
diff --git a/ModernKeePassLib/Cryptography/HashingStreamEx.cs b/ModernKeePassLib/Cryptography/HashingStreamEx.cs
new file mode 100644
index 0000000..7ee615e
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/HashingStreamEx.cs
@@ -0,0 +1,207 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 Windows.Security.Cryptography.Core;
+
+namespace ModernKeePassLib.Cryptography
+{
+ public sealed class HashingStreamEx : Stream
+ {
+ private Stream m_sBaseStream;
+ private bool m_bWriting;
+ private Queue m_DataToHash;
+
+ public byte[] Hash
+ {
+ get
+ {
+ int len = 0;
+ foreach (byte[] block in m_DataToHash)
+ {
+ len += block.Length;
+ }
+ byte[] dataToHash = new byte[len];
+ int pos = 0;
+ while(m_DataToHash.Count > 0)
+ {
+ byte[] block = m_DataToHash.Dequeue();
+ Array.Copy(block, 0, dataToHash, pos, block.Length);
+ pos += block.Length;
+ }
+
+ byte[] hash = SHA256Managed.Instance.ComputeHash(dataToHash);
+ return hash;
+ }
+ }
+
+ 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 { throw new NotSupportedException(); }
+ }
+
+ public HashingStreamEx(Stream sBaseStream, bool bWriting, CryptographicHash hashAlgorithm)
+ {
+ if (sBaseStream == null) throw new ArgumentNullException("sBaseStream");
+
+ m_sBaseStream = sBaseStream;
+ m_bWriting = bWriting;
+
+#if KeePassWinRT
+
+ m_DataToHash = new Queue();
+
+
+#else
+#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
+#endif // KeePassWinRT
+
+
+#if TODO
+ // Bert TODO: For the time being, only built-in Hash algorithm are supported.
+ if (m_hash == null) { Debug.Assert(false); return; }
+ // Validate hash algorithm
+ if((!m_hash.CanReuseTransform) || (!m_hash.CanTransformMultipleBlocks) ||
+ (m_hash.InputBlockSize != 1) || (m_hash.OutputBlockSize != 1))
+ {
+#if DEBUG
+ MessageService.ShowWarning("Broken HashAlgorithm object in HashingStreamEx.");
+#endif
+ m_hash = null;
+ }
+#endif
+ }
+
+ public override void Flush()
+ {
+ m_sBaseStream.Flush();
+ }
+
+#if TODO
+ public override void Close()
+ {
+
+ if(m_hash != null)
+ {
+ try
+ {
+ m_hash.TransformFinalBlock(new byte[0], 0, 0);
+
+ m_pbFinalHash = m_hash.Hash;
+ }
+ catch(Exception) { Debug.Assert(false); }
+
+ m_hash = null;
+ }
+
+ m_sBaseStream.Close();
+
+ }
+#endif
+
+ 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);
+
+ // Mono bug workaround (LaunchPad 798910)
+ int nPartialRead = nRead;
+ while ((nRead < nCount) && (nPartialRead != 0))
+ {
+ nPartialRead = m_sBaseStream.Read(pbBuffer, nOffset + nRead,
+ nCount - nRead);
+ nRead += nPartialRead;
+ }
+
+ byte[] pbOrg = new byte[nRead];
+ Array.Copy(pbBuffer, pbOrg, nRead);
+ m_DataToHash.Enqueue(pbOrg);
+
+ return nRead;
+ }
+
+ public override void Write(byte[] pbBuffer, int nOffset, int nCount)
+ {
+ // BERT TODO: Not implemented.
+ Debug.Assert(false);
+#if TODO
+ 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);
+
+#endif // TODO
+ }
+ }
+}
diff --git a/ModernKeePassLib/Cryptography/HmacOtp.cs b/ModernKeePassLib/Cryptography/HmacOtp.cs
new file mode 100644
index 0000000..3b7458a
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/HmacOtp.cs
@@ -0,0 +1,89 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 !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)
+ {
+ Debug.Assert(false, "Not yet implemented");
+ return null;
+#if TODO
+ byte[] pbText = MemUtil.UInt64ToBytes(uFactor);
+ Array.Reverse(pbText); // 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().PadLeft((int)uDigits, '0');
+#endif
+ }
+
+ 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/PasswordGenerator/CharSetBasedGenerator.cs b/ModernKeePassLib/Cryptography/PasswordGenerator/CharSetBasedGenerator.cs
new file mode 100644
index 0000000..7c8f93b
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/PasswordGenerator/CharSetBasedGenerator.cs
@@ -0,0 +1,65 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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)
+ {
+ Array.Clear(vGenerated, 0, vGenerated.Length);
+ return PwgError.TooFewCharacters;
+ }
+
+ vGenerated[nIndex] = ch;
+ }
+
+ byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vGenerated);
+ psOut = new ProtectedString(true, pbUtf8);
+ MemUtil.ZeroByteArray(pbUtf8);
+ Array.Clear(vGenerated, 0, vGenerated.Length);
+
+ return PwgError.Success;
+ }
+ }
+}
diff --git a/ModernKeePassLib/Cryptography/PasswordGenerator/CustomPwGenerator.cs b/ModernKeePassLib/Cryptography/PasswordGenerator/CustomPwGenerator.cs
new file mode 100644
index 0000000..bc8fd6e
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/PasswordGenerator/CustomPwGenerator.cs
@@ -0,0 +1,66 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
new file mode 100644
index 0000000..b026c28
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/PasswordGenerator/CustomPwGeneratorPool.cs
@@ -0,0 +1,110 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.EqualsValue(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.EqualsValue(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
new file mode 100644
index 0000000..cdd1598
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/PasswordGenerator/PatternBasedGenerator.cs
@@ -0,0 +1,173 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 == '[')
+ {
+ 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);
+ Array.Clear(vArray, 0, vArray.Length);
+ 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
new file mode 100644
index 0000000..a1273ef
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/PasswordGenerator/PwCharSet.cs
@@ -0,0 +1,318 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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|";
+
+ private const int CharTabSize = (0x10000 / 8);
+
+ private List m_vChars = new List();
+ private byte[] m_vTab = new byte[CharTabSize];
+
+ private string m_strHighAnsi = string.Empty;
+ private string m_strSpecial = string.Empty;
+
+ ///
+ /// Create a new, empty character set collection object.
+ ///
+ public PwCharSet()
+ {
+ this.Initialize(true);
+ }
+
+ public PwCharSet(string strCharSet)
+ {
+ this.Initialize(true);
+ this.Add(strCharSet);
+ }
+
+ private PwCharSet(bool bFullInitialize)
+ {
+ this.Initialize(bFullInitialize);
+ }
+
+ private void Initialize(bool bFullInitialize)
+ {
+ this.Clear();
+
+ if(bFullInitialize == false) return;
+
+ StringBuilder sbHighAnsi = new StringBuilder();
+ for(char ch = '~'; ch < 255; ++ch)
+ sbHighAnsi.Append(ch);
+ m_strHighAnsi = sbHighAnsi.ToString();
+
+ PwCharSet pcs = new PwCharSet(false);
+ pcs.AddRange('!', '/');
+ pcs.AddRange(':', '@');
+ pcs.AddRange('[', '`');
+ 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];
+ }
+ }
+
+ public string SpecialChars { get { return m_strSpecial; } }
+ public string HighAnsiChars { get { return m_strHighAnsi; } }
+
+ ///
+ /// 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(this.Contains(ch) == false) 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(this.Contains(ch) == false)
+ {
+ 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)
+ this.Add(ch);
+ }
+
+ public void Add(string strCharSet1, string strCharSet2)
+ {
+ this.Add(strCharSet1);
+ this.Add(strCharSet2);
+ }
+
+ public void Add(string strCharSet1, string strCharSet2, string strCharSet3)
+ {
+ this.Add(strCharSet1);
+ this.Add(strCharSet2);
+ this.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)
+ this.Add(ch);
+
+ this.Add(chMax);
+ }
+
+ public bool AddCharSet(char chCharSetIdentifier)
+ {
+ bool bResult = true;
+
+ switch(chCharSetIdentifier)
+ {
+ case 'a': this.Add(PwCharSet.LowerCase, PwCharSet.Digits); break;
+ case 'A': this.Add(PwCharSet.LowerCase, PwCharSet.UpperCase,
+ PwCharSet.Digits); break;
+ case 'U': this.Add(PwCharSet.UpperCase, PwCharSet.Digits); break;
+ case 'c': this.Add(PwCharSet.LowerConsonants); break;
+ case 'C': this.Add(PwCharSet.LowerConsonants,
+ PwCharSet.UpperConsonants); break;
+ case 'z': this.Add(PwCharSet.UpperConsonants); break;
+ case 'd': this.Add(PwCharSet.Digits); break; // Digit
+ case 'h': this.Add(PwCharSet.LowerHex); break;
+ case 'H': this.Add(PwCharSet.UpperHex); break;
+ case 'l': this.Add(PwCharSet.LowerCase); break;
+ case 'L': this.Add(PwCharSet.LowerCase, PwCharSet.UpperCase); break;
+ case 'u': this.Add(PwCharSet.UpperCase); break;
+ case 'p': this.Add(PwCharSet.Punctuation); break;
+ case 'b': this.Add(PwCharSet.Brackets); break;
+ case 's': this.Add(PwCharSet.PrintableAsciiSpecial); break;
+ case 'S': this.Add(PwCharSet.UpperCase, PwCharSet.LowerCase);
+ this.Add(PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial); break;
+ case 'v': this.Add(PwCharSet.LowerVowels); break;
+ case 'V': this.Add(PwCharSet.LowerVowels, PwCharSet.UpperVowels); break;
+ case 'Z': this.Add(PwCharSet.UpperVowels); break;
+ case 'x': this.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(this.Contains(strCharacters) == false)
+ return false;
+
+ return this.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(this.RemoveIfAllExist(PwCharSet.UpperCase) ? 'U' : '_');
+ sb.Append(this.RemoveIfAllExist(PwCharSet.LowerCase) ? 'L' : '_');
+ sb.Append(this.RemoveIfAllExist(PwCharSet.Digits) ? 'D' : '_');
+ sb.Append(this.RemoveIfAllExist(m_strSpecial) ? 'S' : '_');
+ sb.Append(this.RemoveIfAllExist(PwCharSet.Punctuation) ? 'P' : '_');
+ sb.Append(this.RemoveIfAllExist(@"-") ? 'm' : '_');
+ sb.Append(this.RemoveIfAllExist(@"_") ? 'u' : '_');
+ sb.Append(this.RemoveIfAllExist(@" ") ? 's' : '_');
+ sb.Append(this.RemoveIfAllExist(PwCharSet.Brackets) ? 'B' : '_');
+ sb.Append(this.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] != '_') this.Add(PwCharSet.UpperCase);
+ if(strRanges[1] != '_') this.Add(PwCharSet.LowerCase);
+ if(strRanges[2] != '_') this.Add(PwCharSet.Digits);
+ if(strRanges[3] != '_') this.Add(m_strSpecial);
+ if(strRanges[4] != '_') this.Add(PwCharSet.Punctuation);
+ if(strRanges[5] != '_') this.Add('-');
+ if(strRanges[6] != '_') this.Add('_');
+ if(strRanges[7] != '_') this.Add(' ');
+ if(strRanges[8] != '_') this.Add(PwCharSet.Brackets);
+ if(strRanges[9] != '_') this.Add(m_strHighAnsi);
+ }
+ }
+}
diff --git a/ModernKeePassLib/Cryptography/PasswordGenerator/PwGenerator.cs b/ModernKeePassLib/Cryptography/PasswordGenerator/PwGenerator.cs
new file mode 100644
index 0000000..dfcb0fd
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/PasswordGenerator/PwGenerator.cs
@@ -0,0 +1,146 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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;
+
+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");
+
+ CryptoRandomStream crs = CreateCryptoStream(pbUserEntropy);
+ PwgError e = PwgError.Unknown;
+
+ 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; }
+
+ return e;
+ }
+
+ private static CryptoRandomStream CreateCryptoStream(byte[] pbAdditionalEntropy)
+ {
+ byte[] pbKey = CryptoRandom.Instance.GetRandomBytes(256);
+
+ // Mix in additional entropy
+ if((pbAdditionalEntropy != null) && (pbAdditionalEntropy.Length > 0))
+ {
+ for(int nKeyPos = 0; nKeyPos < pbKey.Length; ++nKeyPos)
+ pbKey[nKeyPos] ^= pbAdditionalEntropy[nKeyPos % pbAdditionalEntropy.Length];
+ }
+
+ return new CryptoRandomStream(CrsAlgorithm.Salsa20, 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
new file mode 100644
index 0000000..69e736b
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/PasswordGenerator/PwProfile.cs
@@ -0,0 +1,274 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.ComponentModel;
+using System.Xml.Serialization;
+
+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;
+
+ byte[] pbUtf8 = psPassword.ReadUtf8();
+ char[] vChars = StrUtil.Utf8.GetChars(pbUtf8);
+
+ 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((@"!#$%&'*+,./:;=?@^").IndexOf(ch) >= 0) pcs.Add(pcs.SpecialChars);
+ else if(ch == ' ') pcs.Add(' ');
+ else if(ch == '-') pcs.Add('-');
+ else if(ch == '_') pcs.Add('_');
+ else if(ch == '\"') pcs.Add(pcs.SpecialChars);
+ else if(ch == '\\') pcs.Add(pcs.SpecialChars);
+ else if((@"()[]{}<>").IndexOf(ch) >= 0) pcs.Add(PwCharSet.Brackets);
+ else if((ch >= '~') && (ch <= 255)) pcs.Add(pcs.HighAnsiChars);
+ else pcs.Add(ch);
+ }
+
+ Array.Clear(vChars, 0, vChars.Length);
+ MemUtil.ZeroByteArray(pbUtf8);
+ 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
new file mode 100644
index 0000000..bb58461
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/PopularPasswords.cs
@@ -0,0 +1,539 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.Utility;
+
+#if !KeePassLibSD
+namespace ModernKeePassLib.Cryptography
+{
+ ///
+ /// Bloom filter-based popular password checking.
+ ///
+ public static class PopularPasswords
+ {
+ private const int PpcTableSize = 8192 * 8; // Bits, multiple of 64
+
+ // Bits set: 32433 of 65536
+ // Hash functions: 32
+ // Phi (bits unset ratio) estimation: 0.505455388896019
+ // Exact Phi: 0.505111694335938
+ // False positives ratio: 1.67583063859565E-10
+ private static readonly ulong[] PpcTable = {
+ 0x60383D3A85560B9BUL, 0x2578CE9D37C6AEB7UL, 0xF509A5743FD03228UL,
+ 0x19B7455E8933EE56UL, 0x5EA419ADCFD9C20EUL, 0xEA618EFC0B37A162UL,
+ 0xE0FD4D1FFF1CE415UL, 0x7A649E0301BB6060UL, 0x80D9CD9F9EEB603DUL,
+ 0x47D6010D0D6E6CDEUL, 0x2552708C589EB554UL, 0x073F1A3DB3267502UL,
+ 0x3313FEC2A2FEA475UL, 0x4593665C44934FEBUL, 0x410A301A23660395UL,
+ 0x6AD06DA533FF5659UL, 0x423DAF86F3E41F4AUL, 0x82F035A971C6FD18UL,
+ 0xB5E9139F28C93223UL, 0x1D07C3F4160585CAUL, 0x24B01EDB6B23E2C5UL,
+ 0xD52F25B724F936C9UL, 0x8018392517836928UL, 0x3AA4C0F8E181EDA2UL,
+ 0x8D93683EF7D52529UL, 0x6164BB6208114460UL, 0x737A04D8FEF3D88FUL,
+ 0x3400097098D5C2CBUL, 0x3C2B9ABE5C455B2EUL, 0x3A3819973AB32DA2UL,
+ 0x38ACB428510AF40BUL, 0x83320D5114B74771UL, 0xC25BEC333B90DCD1UL,
+ 0x0E9F412FBA3813D1UL, 0x047E31E3098EB2B8UL, 0xBB686AC643F1741FUL,
+ 0x0BE22E9C0EF0E8F2UL, 0x65AA9504E5F40D31UL, 0xE018DF5D64C62AC7UL,
+ 0x17020E9A7EFA12EDUL, 0xFC12A7C16006DE82UL, 0x8DE4747E3745346DUL,
+ 0x31D8C051A43CECAFUL, 0xBE9AFBEF127C1B12UL, 0xAEE94B4B808BBEE2UL,
+ 0x3A0099CA32835B41UL, 0x59EB3173468D8C49UL, 0x6F89DB1E6DAAE9E1UL,
+ 0x4C1ADAA837E968E4UL, 0x6E3593A56C682769UL, 0x022AD591689B5B82UL,
+ 0x4AC33861ED978032UL, 0xF6F476E4E6A1318DUL, 0x2DA690A11AA05A23UL,
+ 0x916FC56378C29D77UL, 0xAB3238BE22294659UL, 0x2D73A29019B28C77UL,
+ 0xAAF26C12EC9C3C42UL, 0x058A278A24B334F9UL, 0x033BD18FB8D9BACDUL,
+ 0x8B3833596008B07CUL, 0x280B6D093333E5E5UL, 0x2128DBE126CA3E1EUL,
+ 0xCCF09769382472D8UL, 0x0CB6E495BD90CED6UL, 0x1303A37577C01C5AUL,
+ 0xC8BBF4734FC34C53UL, 0x1B38B72B10F86CD5UL, 0x5098E2D6C1892E51UL,
+ 0x2DD8065B79DB5380UL, 0x5B9A1A6D6A2292B7UL, 0xC70F751604D0497CUL,
+ 0x911E08D7363B5213UL, 0x9F2E245273308D2EUL, 0x64D354827957F50EUL,
+ 0x09856750F560342CUL, 0xDE091F26603F0E70UL, 0xDDE6B4E76173E3B1UL,
+ 0xC1584AE1B26FA08EUL, 0x1EA29887837838D2UL, 0x6D7643FC67B15C54UL,
+ 0x921E60571ED103EAUL, 0x63EB1EB33E7AFFF1UL, 0x80BA4D1F95BFD615UL,
+ 0xEC8A1D4FC1A6B8E0UL, 0x2C46861B6DB17D1AUL, 0x01F05D06927E443BUL,
+ 0x6172EC2EABEAD454UL, 0x21B8726C6F7C4102UL, 0x3C016CD9945C72ECUL,
+ 0x708F77B2C0E8B665UL, 0xFC35BE2BB88974DAUL, 0x805897A33702BD61UL,
+ 0x9A93367A6041226CUL, 0xFDAB188B6158F6BEUL, 0x5F21014A065E918CUL,
+ 0xF4381DD77772D19CUL, 0xC664B6358AA85011UL, 0xF2639D7B3E2307E6UL,
+ 0x3FA000D4A5A9C37AUL, 0x8F45D116ED8DC70FUL, 0x8CB8758E45C140D0UL,
+ 0x49832B46D716236DUL, 0xCC8E4961A93065B8UL, 0x8A996533EDACEB0EUL,
+ 0x15B35155EC56FAC1UL, 0xE7E0C6C05A9F1885UL, 0x05914F9A1D1C79F9UL,
+ 0x730000A30B6725F0UL, 0xC95E671F8E543780UL, 0x47D68382400AF94EUL,
+ 0x1A27F2734FE2249AUL, 0x828079C332D9C0ABUL, 0x2E9BC798EA09170EUL,
+ 0x6B7CDAC829018C91UL, 0x7B89604901736993UL, 0xABE4EB26F47608F0UL,
+ 0x70D5FDC88A0FF1B1UL, 0x5A1F0BAB9AB8A158UL, 0xDC89AE0A735C51A4UL,
+ 0x36C1EA01E9C89B84UL, 0x3A9757AF204096DBUL, 0x1D56C8328540F963UL,
+ 0x910A8694692472FAUL, 0x697192C9DF145604UL, 0xB20F7A4438712AA2UL,
+ 0xE8C99185243F4896UL, 0xFBC8970EDBC39CA7UL, 0x33485403868C3761UL,
+ 0xAFA97DDEDB1D6AD8UL, 0x54A1A6F24476A3BBUL, 0xFE4E078B184BDB7FUL,
+ 0x5ED1543919754CD8UL, 0x86F8C775160FC08CUL, 0x9B4098F57019040DUL,
+ 0x039518BBE841327BUL, 0x111D0D420A3F5F6AUL, 0x0666067346AF34ACUL,
+ 0xD43F1D14EB239B9BUL, 0xA6BB91FEB5618F5BUL, 0xA2B5218B202409ADUL,
+ 0xC004FA688C3AC25EUL, 0xF0E2D9EA2935E1DCUL, 0x380B31CFA2F2AF43UL,
+ 0x50E050AE426250EAUL, 0x628ED94D1AA8F55BUL, 0xF8EB0654F0166311UL,
+ 0x1F8858D26DDA5CC5UL, 0x931425D11CB1EFEBUL, 0xF661D461DC1A05D3UL,
+ 0x7B75ED7EC6936DA8UL, 0x8713C59690985202UL, 0xF61D6F93F07C0E85UL,
+ 0xFD1771F6711D6F4FUL, 0x5835A67E1B11419FUL, 0x33EF08ABD56A1050UL,
+ 0x55B5D0043FA2C01CUL, 0x53316ED963B92D9DUL, 0x6A8C93744E521EDBUL,
+ 0x083E948062EB9543UL, 0x1C15289B3189AFB1UL, 0xA6A0A5053AE2212DUL,
+ 0x6573AF7F01FAFF3BUL, 0x58B6F034CFCFE843UL, 0xEB2837CA5AEA6AEDUL,
+ 0x633E7897097AC328UL, 0x7FA91789B6CCEE82UL, 0xBEE2402F4E7D65EEUL,
+ 0x616A103EC8FB0DBEUL, 0x65991F9FB25E13FCUL, 0x54EA8A3FADEC1F4BUL,
+ 0x6D497C5ACDEA0E7AUL, 0x5865045E8CA18527UL, 0xA406C09215ABD61FUL,
+ 0x68F81F5745FC9875UL, 0xE496D850CEFF3FA9UL, 0xD225C88D63212CB1UL,
+ 0x37676390525116D2UL, 0x415614AB14188A7DUL, 0xABE58EBC1F6DDC63UL,
+ 0xDE10312B2C25D28CUL, 0x86C86D7A0B847635UL, 0x408B511D584DC3DCUL,
+ 0x6711FCC14B303FEDUL, 0x1284DF9CC6972023UL, 0xC3CE0B33141BFA8FUL,
+ 0x0F3F58367D4A1819UL, 0x9313F83058FBE6D0UL, 0x6FCA5EF39B8E2F47UL,
+ 0xA90F5C95D887756DUL, 0x96C4E2AD85D5AF6EUL, 0x0ED68A81F526F0A0UL,
+ 0x53E4472DB4255A35UL, 0xAC581015134D58A6UL, 0x12C000D85C644FC7UL,
+ 0x124D489B2C0FE6E4UL, 0x8FF83531C6F5D61AUL, 0x132BD6488304F73BUL,
+ 0x110E99BC59604CB9UL, 0xC28186ACBC940C9BUL, 0x2094C07F48141230UL,
+ 0x65FB9881A5053589UL, 0x940A3E6D72F09D69UL, 0x972A922CB14BA66EUL,
+ 0x8D07E59C6DDD4327UL, 0xCB67F993F820157CUL, 0x65B7A54E5FB2ED6CUL,
+ 0xC235828849576653UL, 0xA695F85479467538UL, 0x9E2BA885E63C4243UL,
+ 0xDE64A6A5EF84C222UL, 0xC2AB9AF302080621UL, 0x88DBA09B87FA0734UL,
+ 0xDF002765B44D02E1UL, 0xD50D8D90587CD820UL, 0x1B68B70ED179EFE1UL,
+ 0xD6E77F8EC26AE95CUL, 0xEE57EB7C45051872UL, 0x4D2B445F36A7F9FDUL,
+ 0x5502ABB8BB14D7F1UL, 0xAF2C0DF0406FA901UL, 0x6522833444BF4A83UL,
+ 0xD7CB2E3FC691BE8DUL, 0x4F36F70D2E80D19AUL, 0xF6945FE911D4923BUL,
+ 0xE3C6FE1EA47399C1UL, 0xF09EA1B2F837702CUL, 0x5122537CF97B5CB5UL,
+ 0x0C8202B70E9BF154UL, 0x68B554AB58EB5E68UL, 0x7BF9B8052C9BEADEUL,
+ 0x33612BFCD303810DUL, 0x03E38CF67B37DC53UL, 0x2BFDFF8691F37D5CUL,
+ 0x4AB483D1CB1D07F6UL, 0xF071A58640639A5CUL, 0x9D6B98169B745CE1UL,
+ 0x5F42D3E870FDCD93UL, 0x4EDF04404F258238UL, 0x2EAB6E10D65C9BB3UL,
+ 0x5BB71411EF78DAD2UL, 0x0DE8128636A5D689UL, 0x18FDD1F484DC9365UL,
+ 0x9896B8896941DA5BUL, 0x8BEF8E3BA4448E5FUL, 0x963A1E977CB1D2CAUL,
+ 0x02BCF5F068D52851UL, 0x0CD783F09BFBE381UL, 0x350DA833D8C5DB47UL,
+ 0x8D444C914D795C43UL, 0x8A00B4DFC44D9476UL, 0x4B36CBEC089E55FDUL,
+ 0xD9D2FA1B0AC66211UL, 0x6C7FC30FA31A8B60UL, 0x9EF4504CC985AD6BUL,
+ 0x8F2E7E5E0C00EE73UL, 0x819131CFEEBEA069UL, 0xB1E406A863E7A1B4UL,
+ 0x501F072FF1F2AB67UL, 0xDE578BFC5ADBC264UL, 0xCDD66A09C8E13881UL,
+ 0x4D443460CE52957FUL, 0x3B198C267976ECFAUL, 0x6B98323D8BD26522UL,
+ 0x80161F6A489E4BF8UL, 0xE03A8AFCC7AE6872UL, 0x2484BD95A305AB27UL,
+ 0x6ADDAA46BF25DD0EUL, 0xA429D8B00100477CUL, 0x55AEDB88A074BF2CUL,
+ 0x63D9F9021AB8F5F3UL, 0x37858538A10C265CUL, 0xEF54C2CE9D063149UL,
+ 0xFA5CE5AF33E2C136UL, 0xE601A559D0C391D7UL, 0x7C4ED29BBF57DC7EUL,
+ 0x8FD0D4146DE9E900UL, 0xB58ABFA6CE6C0733UL, 0xF8D7F7743B33EAFFUL,
+ 0x453FA782F454643CUL, 0xD01752C21AF21E66UL, 0xA50BB7913EAF05DFUL,
+ 0x966D5B140B2F4189UL, 0x956F5638AFF3D148UL, 0x93FAA838420E8AB3UL,
+ 0x715E26043071EABDUL, 0x01E7B458B5FD3A41UL, 0x5CFA99C4CC0492AAUL,
+ 0x761FD391C3623044UL, 0xD39E44E9DB96B5BCUL, 0x8806C544F0534A07UL,
+ 0x9B225CAFE97EAAC1UL, 0xEAE5E18583492767UL, 0x6B4E51E4C297F096UL,
+ 0xFC512662EF47E41DUL, 0xB6AC60427DB46F8BUL, 0x8F137F3DB4429C9DUL,
+ 0x04C65FBEAE9FD8D0UL, 0xEB72305958AE5022UL, 0xAA93AA14BCA2961EUL,
+ 0x6C7547F9456CA37AUL, 0xEE6094871615BA34UL, 0x489BC8EDE0940402UL,
+ 0x1108AEFAAD892229UL, 0x673B8B1CF6BED23EUL, 0xFDB781A75FD94DEAUL,
+ 0x11D9E0F5D914A7BEUL, 0x02830D07F018143DUL, 0x9B3163B8188FD2BAUL,
+ 0x32C1BEC97D06117EUL, 0x697268B761240CFFUL, 0xBD89CE3037C2E7A9UL,
+ 0xF21C158125B19600UL, 0x632CB1931601B70AUL, 0x7BB3FB131338085CUL,
+ 0xA9C06689B8138384UL, 0x161CCBF83EBDC2A1UL, 0x2CF83C01A80B7935UL,
+ 0x9E51FE393B8E2FF0UL, 0xFE96E52B1606C1A7UL, 0x5E20DFB87F81ACCEUL,
+ 0xF95DB9602CDAE467UL, 0xDEA155CD35555FEBUL, 0xF0669B810F70CDC6UL,
+ 0xD36C2FBEB6A449ACUL, 0xCE500C6621C0A445UL, 0x41308909E366460AUL,
+ 0xAC4D8178DA0CEC24UL, 0xC69049179ED09F7DUL, 0x36B608A0BA2FD848UL,
+ 0xDF511894DD9568B4UL, 0xB3BFDF78EC861A6CUL, 0xCD50F39D19848153UL,
+ 0xD2C1BC57E78A408CUL, 0x1E6613EFBB11B5EBUL, 0xF58E30D2D90F73D3UL,
+ 0xCCB5E2F5E168D742UL, 0xEE97259469BDB672UL, 0x6784D35AF65935A8UL,
+ 0x71032765ADED1FE8UL, 0x4BBF2FE54D9B72E3UL, 0x5A1BB7831E876A05UL,
+ 0x12A8FC949EE91686UL, 0x8296F8FA83BD112CUL, 0xAAA7E3BFF64D34D5UL,
+ 0x0301655E1794EE4BUL, 0x1E547C011BBF30E1UL, 0x39D74FEC536F31D6UL,
+ 0x3C31A7478B1815BAUL, 0x525C774F82D5836EUL, 0xECF7186DC612FD8CUL,
+ 0x96B7C4EDD1F3536FUL, 0x7E8C21F19C08541CUL, 0xEE92DB0CF91E4B09UL,
+ 0xF666190D1591AE5DUL, 0x5E9B45102C895361UL, 0x9A95597AAE5C905DUL,
+ 0x6E1272E5BB93F93FUL, 0x0E39E612402BFCF8UL, 0x576C9E8CA2A3B35EUL,
+ 0x7E2E629996D0C35FUL, 0xC95DFF54E3524FCCUL, 0x260F9DEBDEB0E5CBUL,
+ 0x577B6C6640BAF1ABUL, 0xCA76677779CA358EUL, 0x9E2714BEBCFDB144UL,
+ 0xD660595CE30FD3EEUL, 0x72DE172D55A5706EUL, 0xB4C84D564489D420UL,
+ 0x160AA2B9399D5A9DUL, 0x2906ECE619DAC4D2UL, 0x12CE8E8E68A4C317UL,
+ 0x6BE2DFE89901CAA1UL, 0xEE1D68158102EB77UL, 0x64EB75E45BDA1AC5UL,
+ 0xEFECF9F98720B55DUL, 0x41CDF813931315BFUL, 0x5F1E4F50CF98FFD4UL,
+ 0xE69E09EED12E173BUL, 0x89A3707F0396FF65UL, 0x81E36B9DF4FFB492UL,
+ 0x58C32E883D4DE6DDUL, 0x2D4725C2A5F0B469UL, 0x6B2B9C27CC421CACUL,
+ 0x3C30F2AD966800C7UL, 0xFF74938BB76B8A7CUL, 0x52B5C99114FD93FAUL,
+ 0x51647EDCA6C104DAUL, 0xEB47684CF796DF4EUL, 0x376D74A5AB14BD71UL,
+ 0xF0871FEF8E9DAA3EUL, 0x1D65B134B2E045B6UL, 0x9DC8C0D8623BBA48UL,
+ 0xAD6FC3C59DBDADF4UL, 0x66F6EBA55488B569UL, 0xB00D53E0E2D38F0AUL,
+ 0x43A4212CEAD34593UL, 0x44724185FF7019FFUL, 0x50F46061432B3635UL,
+ 0x880AA4C24E6B320BUL, 0xCAFCB3409A0DB43FUL, 0xA7F1A13DEF47514BUL,
+ 0x3DC8A385A698220CUL, 0xFA17F82E30B85580UL, 0x430E7F0E88655F47UL,
+ 0x45A1566013837B47UL, 0x84B2306D2292804EUL, 0xE7A3AF21D074E419UL,
+ 0x09D08E2C5E569D4DUL, 0x84228F8908383FA2UL, 0xC34079610C8D3E82UL,
+ 0x66C96426C54A5453UL, 0xD41F164117D32C93UL, 0x7829A66BF1FEC186UL,
+ 0x4BB6846694BDFC18UL, 0x857D1C1C01352C01UL, 0xAB8E68BA85402A45UL,
+ 0x74B3C4F101FE76C8UL, 0x6CF482CFAFB29FFEUL, 0x28B174A18F4DC3D1UL,
+ 0x833C3425B2AA3755UL, 0x8AA58A32747F4432UL, 0xFE7B9FB4BCE3CD58UL,
+ 0xB0836B2C16FA5553UL, 0x1D08EE6861BF3F23UL, 0x0FAE41E914562DF3UL,
+ 0xB10A2E041937FC57UL, 0xDA60BB363415BF4CUL, 0xEEC67DBAB4CF4F0AUL,
+ 0x9A6ED59FCC923B5CUL, 0x9A913C01A8EC7A83UL, 0xAD4779F2F9C7721FUL,
+ 0x2BF0B7D105BE7459UL, 0x189EFA9AD5195EC6UL, 0xB5C9A2DD64B2A903UL,
+ 0x5BCD642B2C2FD32CUL, 0xFED3FBF78CB0891FUL, 0x1ED958EE3C36DD3FUL,
+ 0x030F5DE9CA65E97CUL, 0xBB5BCF8C931B85FEUL, 0xFD128759EA1D8061UL,
+ 0x2C0238AC416BE6BCUL, 0xBB018584EEACFA27UL, 0xCEA7288C1964DE15UL,
+ 0x7EA5C3840F29AA4DUL, 0x5DA841BA609E4A50UL, 0xE53AF84845985EB1UL,
+ 0x93264DA9487183E4UL, 0xC3A4E367AF6D8D15UL, 0xDD4EB6450577BAF8UL,
+ 0x2AA3093EE2C658ACUL, 0x3D036EC45055C580UL, 0xDDEDB34341C5B7DFUL,
+ 0x524FFBDC4A1FAC90UL, 0x1B9D63DE13D82907UL, 0x69F9BAF0E868B640UL,
+ 0xFC1A453A9253013CUL, 0x08B900DECAA77377UL, 0xFF24C72324153C59UL,
+ 0x6182C1285C507A9BUL, 0x4E6680A54A03CCC8UL, 0x7165680200B67F1FUL,
+ 0xC3290B26A07DCE5BUL, 0x2AD16584AA5BECE9UL, 0x5F10DF677C91B05EUL,
+ 0x4BE1B0E2334B198AUL, 0xEA2466E4F4E4406DUL, 0x6ECAA92FF91E6F1DUL,
+ 0x0267738EFA75CADDUL, 0x4282ED10A0EBFCF2UL, 0xD3F84CE8E1685271UL,
+ 0xB667ED35716CA215UL, 0x97B4623D70DB7FA8UL, 0xB7BA3AA5E6C2E7CBUL,
+ 0x8942B2F97118255BUL, 0x009050F842FB52ADUL, 0x114F5511999F5BD5UL,
+ 0x70C1CAAF1E83F00AUL, 0xAC8EE25D462BB1AAUL, 0x63EEF42AD4E1BED9UL,
+ 0x58DFBB3D22D3D1A5UL, 0x82B0027C0C63D816UL, 0x48D038F08F3D848BUL,
+ 0xCE262D5F9A12610EUL, 0xA54BF51C21BD0167UL, 0xF3645F6FB948397DUL,
+ 0x9188AE58532DA501UL, 0xEC90B0E1479DB767UL, 0x37F4886B83724F80UL,
+ 0x232B8FF20ACD95AFUL, 0x88A228285D6BCDF0UL, 0x321FB91600259AEEUL,
+ 0xA1F875F161D18E5EUL, 0x5B6087CDA21AEA0CUL, 0x0156923ED1A3D5F1UL,
+ 0xC2892C8A6133B5D3UL, 0x015CA4DF0EA6354DUL, 0x5E25EB261B69A7D4UL,
+ 0xAAA8CF0C012EFBA7UL, 0xCF3466248C37868BUL, 0x0D744514BD1D82C0UL,
+ 0xB00FF1431EDDF490UL, 0xC79B86A0E3A8AB08UL, 0xFC361529BC9F1252UL,
+ 0x869285653FB82865UL, 0x9F1C7A17546339ABUL, 0xE31AA66DBD5C4760UL,
+ 0x51B9D2A765E0FC31UL, 0x31F39528C4CD13D8UL, 0x16C6C35B0D3A341DUL,
+ 0x90296B1B0F28E2CDUL, 0x36338472A8DB5830UL, 0xA648E6D44DF14F87UL,
+ 0x93E231E65EB1823FUL, 0x95AA7B9D08E2B627UL, 0x7932D149374700C7UL,
+ 0x09EFE0A8BF245193UL, 0x742AA63BCEAFD6D8UL, 0x82D4BC5FEDF158B7UL,
+ 0x02CDEA673CFF150DUL, 0xD8D7B5813B602D15UL, 0xA5A7B670EF15A5EDUL,
+ 0x4C08E580A1D46AF2UL, 0xC3CA9B905D035647UL, 0x6A39ABB02F6F1B83UL,
+ 0xD2EC2169F4D02436UL, 0x8E6AEA4DF8515AF2UL, 0x7B3DD4A8693CA2DAUL,
+ 0xC2ABF17A50AEC383UL, 0xD4FB84F8B6D4F709UL, 0x2839A3EAA2E4C8A7UL,
+ 0x5D5FD278FE10E1E9UL, 0x5610DDF74125D5A7UL, 0xA484B0B83461DCEAUL,
+ 0xA511920C0A502369UL, 0xC53F30C6A5394CA4UL, 0x528799285D304DD4UL,
+ 0xF6D7914CB252BB48UL, 0x892129CB52E65D15UL, 0x15A81B70519ACE6FUL,
+ 0x5CFBFFD7A2A1C630UL, 0x3B900509C82DF46DUL, 0x19C3CE05D66D5FFCUL,
+ 0x937D521A4A4799A0UL, 0xD0AE34A6EAD7207DUL, 0x3258A69F1D1A1B38UL,
+ 0xB173E3255723CC02UL, 0xD7E48FEF7F414F1BUL, 0xDCEBA75F5C761ABEUL,
+ 0x6DA10C618DEA0D17UL, 0x423FA8B05954FBD1UL, 0x7E73C2E7D923F3C9UL,
+ 0xC22E21C927C684D1UL, 0x756BAA758764685FUL, 0x8C90B4C4E741D880UL,
+ 0x1B658C9F4B41D846UL, 0x5D80C14094366707UL, 0xB55FED3E03C00F2DUL,
+ 0x9B69EB7964C69C83UL, 0x356ED81C9494DADDUL, 0x7599AFF0B2A339D6UL,
+ 0xA5EBFD25C9B5816BUL, 0xA481DC1C8995E1EFUL, 0xE42C63DF0D402397UL,
+ 0x3B497B4C30873BAAUL, 0xA950B78BA8772C96UL, 0xD46308D4C76F115DUL,
+ 0x73714A4ACA76A857UL, 0x0DA86B958FF8CB7DUL, 0xEB61F617B90E0A75UL,
+ 0xD6106C9B39F51F55UL, 0xB179F73A6BD23B59UL, 0xE7F056E50104A460UL,
+ 0xBC5B5387634A8642UL, 0xE1678D8752996AF4UL, 0xB508F3D394664A4BUL,
+ 0xC88536DC4A219B0FUL, 0x39964CBB8CE367B1UL, 0xD51E211D5E9E1417UL,
+ 0x6821B97B496870F2UL, 0xA596257350CA0A99UL, 0x6D051EE2C49D4D1DUL,
+ 0xCB426AD61AA8D9B5UL, 0x5FFD3A4062B06D22UL, 0xDAD37BF2A4C594EBUL,
+ 0x6B9CC848E2B0C686UL, 0x19B4232F3BC622AEUL, 0x70C13C7E5950B702UL,
+ 0x383318CA622101ACUL, 0xD9647C028CD1C4DFUL, 0x006D123BC553B93CUL,
+ 0x2CA9D7D896EAE722UL, 0xF19872AC8A0BD5A8UL, 0x59838578EB9E8E5CUL,
+ 0xB948621EE99B27D4UL, 0x2B470E6036E0E387UL, 0xD0A7E8F0C8A32A84UL,
+ 0xCBF869271A8E0914UL, 0x705F76A5EA4437CFUL, 0xBAD2BF4933215152UL,
+ 0xE52EDE847038EA23UL, 0xB8A3EFD3D58D7607UL, 0x748472F5AD330239UL,
+ 0xCC079CFD428690F6UL, 0x3687450CB7534DACUL, 0x0FEF82D5CC8ACE2AUL,
+ 0x214653D5C552CA9AUL, 0x9FCA4E87BF6A04FDUL, 0x78D4B114D234A0D7UL,
+ 0x22840422BD6A5BB5UL, 0x5B9ABE0DE1B4410FUL, 0xB3B50007963FDD6BUL,
+ 0x53A8A46793B68E35UL, 0x8CDD8E8D188B6033UL, 0x5DD22B6E3ED49572UL,
+ 0xE561F5D27F5302D6UL, 0xDF89CEC3322E56CDUL, 0x87167F503D600F90UL,
+ 0x1698BB71C8201862UL, 0xF7BF5DFDB023108EUL, 0xA17FB15B66ACFB5FUL,
+ 0x2DD771987768073BUL, 0x19299D2D86E0EB29UL, 0x8B537B7F206EED29UL,
+ 0xE536DA153325ABFCUL, 0x30A69976796DB3B9UL, 0x8E65A2C94E2D4981UL,
+ 0xC301D53553BD6514UL, 0x46DF3639B9E43790UL, 0x3004CD0E5AFD0463UL,
+ 0x46E460B0F6ACA1A0UL, 0xCBA210E7372D9BD5UL, 0x45064274A74CA582UL,
+ 0xFDD57EA43CE631AEUL, 0xF2BA08FFA4A683D0UL, 0x8DA658C4DAD42999UL,
+ 0x7418042943E88040UL, 0x96000F72E9371FEFUL, 0xE9F1212DC8F47302UL,
+ 0x2AFB565ECC3553EDUL, 0xCD3D55137EFF7FD6UL, 0xD36F11059388E442UL,
+ 0xC4B47515DB5709DDUL, 0x5C363EFBF0BAAB67UL, 0x28C63B5A31650BBBUL,
+ 0x6AE54E5068061C81UL, 0xDEE62000F4E0AA21UL, 0xE8238672FE088A8BUL,
+ 0x9869CB6370F075B9UL, 0xBA376E2FC7DB330FUL, 0xB0F73E208487CDEEUL,
+ 0x359D5017BE37FE97UL, 0x684D828C7F95E2DCUL, 0x9985ECA20E46AE1FUL,
+ 0x8030A5137D1A21C4UL, 0xF78CDC00FC37AC39UL, 0x41CDDC8E61D9C644UL,
+ 0xB6F3CD1D833BAD1DUL, 0x301D0D858A23DE22UL, 0xA51FCA12AD849BC8UL,
+ 0x9F55E615986AB10EUL, 0x904AAA59854F2215UL, 0x12ECEA4AB40F51A7UL,
+ 0xB4EDF5807735E23BUL, 0x6190200F1C589478UL, 0xA3CA57F321909A5AUL,
+ 0x0BFAEE04B7325B63UL, 0x10C393E7FBCF826DUL, 0x4050A2CA53FDA708UL,
+ 0xF31114A9B462B680UL, 0x6FB9A6F121BA2006UL, 0x04550CF09389D602UL,
+ 0xB8C7D6D8CA8942F7UL, 0x71BB430C6436E9D1UL, 0xD9070DD5FAA0A10AUL,
+ 0x8FD6827757D07E5BUL, 0xD04E6C313F8FD974UL, 0x2CFDEA1187909B9AUL,
+ 0xC7A8E758C115F593UL, 0xA79A17663009ACC2UL, 0x8091A6B5372B141DUL,
+ 0xEB33B08767F5BA73UL, 0xDAC1F6823B6111C7UL, 0x697DF90C3515611BUL,
+ 0xCC1005F198761F48UL, 0x5067E4F5303B45A1UL, 0x04816D292A2D9AC2UL,
+ 0x2949C7A0874DD5E9UL, 0x25DB2547804CEE5EUL, 0x7EDC3A8946D6F229UL,
+ 0x00B586F67FD0C622UL, 0x3CAE5798E40324E0UL, 0x0A4F1437DE637164UL,
+ 0x5F59B2B715871981UL, 0x5D68FF31051E48FBUL, 0x0F2C369D73A2AA46UL,
+ 0xB009C6B53DD23399UL, 0xC366A81277084988UL, 0x5AF0E0CA0711E730UL,
+ 0x7AD831A9E9E854BAUL, 0x1DD5EDB0CA4E85AEUL, 0x54651209D259E9DDUL,
+ 0x3EBB1D9DAB237EADUL, 0xDA96989317AC464CUL, 0xBFCB0F8FBC52C74EUL,
+ 0x9597ACB9E27B692EUL, 0x6F436B1643C95B23UL, 0xB81A1253E1C3CD9DUL,
+ 0x7B35F37E905EC67EUL, 0x29CE62666EDA76DDUL, 0xFF2490DC1EC4014DUL,
+ 0x2D4FF9124DD6B5C4UL, 0xB9510FEC23E0E9D1UL, 0x8BCDBC56541ED071UL,
+ 0x5414E097C1B0CCB2UL, 0x82BEF8213076F5C7UL, 0xE9FC9A71BD512615UL,
+ 0xCF15ECC39490DF5AUL, 0x49FA9328D8EE97DBUL, 0x5F80FF0153BC2145UL,
+ 0xF63BA156B55BCB02UL, 0x0E3B9113109FDF36UL, 0x8FCD6528F54EDE69UL,
+ 0x5D6AE9C000054763UL, 0x326D873633431FBBUL, 0x380E07FFCEF7A978UL,
+ 0xDCAA09874A1DF230UL, 0x601494F49F6D261EUL, 0x856159486C9B60E3UL,
+ 0x85C7F822D07089A5UL, 0xAFFB99CF5AB836C2UL, 0x241AD414FBBB956BUL,
+ 0x0CFC042822831692UL, 0x382B16D049727FF2UL, 0x784F9997633C819AUL,
+ 0x5C40ED725F6C390AUL, 0x2CE78B7A3331BA9CUL, 0x9C80636639963B41UL,
+ 0x1B2D41C968355018UL, 0xD189B57691FB60E4UL, 0x3BD599A9DD85CE31UL,
+ 0x46FC8E2EF0B9A77CUL, 0x1A389E07D0075EA4UL, 0x1622CA52401DF2ACUL,
+ 0x528F3FF9B7993BFAUL, 0xF16C176CCA292DDBUL, 0x6C154010961EF542UL,
+ 0x04B78E92BF6C82DFUL, 0x7D9AFEA6ABB46072UL, 0x3BC573291CBFFC2EUL,
+ 0x277FFF096D567AF3UL, 0x1CBEB86841A6F757UL, 0xD0BCD49E76CA20A7UL,
+ 0x25B6024756B1FE90UL, 0xE685C04EF84881FBUL, 0xDCAB14B352FC442EUL,
+ 0x4FF80A521719953DUL, 0xD10425E411DBE94BUL, 0x60998D0507D6E38DUL,
+ 0x146AA432C981BD5EUL, 0x1729A596282AAA41UL, 0x152BE1A263BAF963UL,
+ 0x15278DF497D254CAUL, 0xE4B5E9891E88A5DAUL, 0x087FA3472067D0ACUL,
+ 0xD99C2899A0AD9158UL, 0x5040F234DC531236UL, 0x9D7E1531259EEE90UL,
+ 0x29AFB8B49391036EUL, 0x84B619599642D68EUL, 0xE838AAE0F249545CUL,
+ 0x42D524BA8BB96959UL, 0x9A5B3E817A20EE59UL, 0x584F0530EC4C566BUL,
+ 0xD6544FD14B47F945UL, 0x3613FB3B553A7CDEUL, 0x284E92B56831AA56UL,
+ 0xCEE89BA10E951A22UL, 0x476806FA1A8A44E0UL, 0xC84CEF151885C1DFUL,
+ 0x3DB1D5C1B0B73936UL, 0x45D2D90FDF452388UL, 0x038A7DD71BC5DD21UL,
+ 0x2AC90C7422C56819UL, 0x4742046638ECE0FBUL, 0x553B44360FC8495DUL,
+ 0xC8DBA1CF3F9A6E97UL, 0xF85919F494CAB021UL, 0x1479455C2FF236AFUL,
+ 0x29BCAD159F7D018DUL, 0x016DFF51CBA3BCC5UL, 0x234BF8A77F6B1CF5UL,
+ 0x20564C6F44F9E641UL, 0x063A550C5AA50FA8UL, 0xB063D0AAAA96DFECUL,
+ 0x3EC659DF42C092F8UL, 0x29D4A76A5A5F7E09UL, 0x65EFF3EE6E691D1EUL,
+ 0xBD1634F5721CF799UL, 0xE85BD016723B43FFUL, 0x5233E9E7AEA11022UL,
+ 0x8C68852EA9039B4CUL, 0x2C978ADBE885BC15UL, 0x726615ED9D497550UL,
+ 0x7C1E145EB8D2BD96UL, 0xC2FEFB25935A5D71UL, 0x9EE9C3E1C3DE416FUL,
+ 0xFFD568A03E20E0B3UL, 0xF53649AD90156F2AUL, 0x0331B91DCE54E7EDUL,
+ 0x67CED5A86E99392FUL, 0x16FC0A5815500B05UL, 0x030392E8D24A7C00UL,
+ 0x232E5E31DF32A7B5UL, 0xCC8BF22B1947DF21UL, 0x4EC2C72D9C1EEABDUL,
+ 0x0B1B79F45220E668UL, 0xCC3CF0EE9C4A899BUL, 0xFC260A60592EBC80UL,
+ 0xC1989A0382CB03EDUL, 0x35FE679A6CD800B2UL, 0x8A6B1ADE4FBB162FUL,
+ 0xB0FD284563625295UL, 0xCDCC1C7B2181D024UL, 0x5B8BA0C895C0BB23UL,
+ 0xA681FEA9ADCD43DBUL, 0x0FE30FB6876DE718UL, 0x6DDD1E27B769C494UL,
+ 0x83A1E58460FFE8BBUL, 0x8FAD6FD2DC90FF65UL, 0x41BB28B81201CB24UL,
+ 0xA148CE79B2597204UL, 0x7CB87DF97BB477A6UL, 0x9F79E6DED87DC688UL,
+ 0xE044D84A6C758171UL, 0x1A29E750D9EC4097UL, 0x8445FC2B80C4A0F5UL,
+ 0x5EFD9784AFED4ED2UL, 0x344C252BD90EB0E4UL, 0xEAD18D2E4418E5B5UL,
+ 0x207EF4FFC260BD24UL, 0xD2E5C3AE534EC538UL, 0x2F5A59BF3D10E7E1UL,
+ 0x9528E29266C2924CUL, 0x0121B6BDAB45D138UL, 0xADD0256ACBC771DDUL,
+ 0x7301769600C6C50DUL, 0x3E7404EA8231D497UL, 0xB39B3840B8D03117UL,
+ 0x56EFCEDDEF5B6634UL, 0xE6BE2C0D73B72098UL, 0x5A2841A21A5E4959UL,
+ 0xCFEB3586156DF6E0UL, 0xD84F58901E2D65B8UL, 0x79796786CCC59703UL,
+ 0x13BFA9A94DD07696UL, 0x7B63116A6B5458B6UL, 0x1406628176C932E0UL,
+ 0xDD7ACC4E97F91B1AUL, 0xC82B8F84A56BDBE8UL, 0x325D87D08ED8B0B0UL,
+ 0x3F7847B1E82002DDUL, 0x4662900D2ADAF6BFUL, 0x12AE9F58561DB1D7UL,
+ 0xA896E956A95CC074UL, 0xAA4FA3A2F8BA4084UL, 0x1D577E35F5DCA67FUL,
+ 0x796FF2D75469DEC2UL, 0xBD3F3F87E4DE894EUL, 0x3666B2262DEBFB6BUL,
+ 0x1E26D7AEEF976C2EUL, 0x6BC3854F867AC4A0UL, 0x743DBF8C2E95A821UL,
+ 0xA62A76B9AE2E645AUL, 0xB4D76561F40187C1UL, 0xD3E5F23F9FA5DB25UL,
+ 0x34B1F6B39E6A87E2UL, 0x7DA5C3DFF7BE72CFUL, 0xFDF46B1BE80AD4F9UL,
+ 0x0B21121CA9653B8AUL, 0x1199CA9D0A90F21AUL, 0x6021EA302D01E0BAUL,
+ 0x8101D063C05CF5D4UL, 0xE2652410DFE78F23UL, 0x84095ACF47C21A25UL,
+ 0xD7E29A4DB2FD3A99UL, 0x7793C0CB57959F93UL, 0x94C605308B9E5AA7UL,
+ 0x943DB1AC54165B8FUL, 0xC1391A544C07447CUL, 0x3FEF1A61F785D97BUL,
+ 0x6DFCC3152478BDE4UL, 0x312AFB0E1982933AUL, 0xB8069C2605631ED3UL,
+ 0x5A6076423430BED2UL, 0x34E379F09E2D4F42UL, 0x9167F5E4019573E3UL,
+ 0x18F81157828D2A49UL, 0xF4A8723B4955EAB8UL, 0x0BE6C0ABFEA9E8A6UL,
+ 0xC63ADCF2CEF25556UL, 0xC5EBD3BEAE9F364FUL, 0xA301D60CF5B6F2FCUL,
+ 0x8C606CA881D27A00UL, 0x826FEE13B554C18AUL, 0x8DF251716F10B776UL,
+ 0xB2573A33AC7D94FFUL, 0xC0E771248CB7ABB9UL, 0x753DD605DB38F4EAUL,
+ 0x21901664C3D92114UL, 0xA408FCB7A1892612UL, 0x3084FC64A03D6722UL,
+ 0xC8C9D9569AD42A34UL, 0x1FBFBAFC1694B383UL, 0x1894280CC3F94ABEUL,
+ 0xE14C38A7BBB54651UL, 0x23A48CC84A6EB704UL, 0xD034ADC45AABEDBDUL,
+ 0xC93F2C21C973C766UL, 0x66A8AEC11D743CC6UL, 0xB4F72AA52E37C145UL,
+ 0xB02834DF0D9266B4UL, 0xDB8E724EA1FF402FUL, 0x531E9C058112E352UL,
+ 0xC2F692531DB317D2UL, 0xEFC9586498D263A7UL, 0x84F2C524D2F3ADB9UL,
+ 0xAFAF02C27CF25D08UL, 0x385873595F9CFC09UL, 0x36DDA10D1A152B7AUL,
+ 0x9F9B997A0DACFB55UL, 0x10AB5EB5C4714882UL, 0x7BA4E8703E22B7EEUL,
+ 0x0A2BFD558607BCC8UL, 0x201D3706F74F8BA1UL, 0x3DBD573B1358F02EUL,
+ 0x5B37645FA93BCEBCUL, 0xC0166864BC1A7544UL, 0x45C7AA5559FC65D7UL,
+ 0xEFEA04AA83349B78UL, 0x607859194F9E9FD8UL, 0xA6B9AE5B53CF7710UL,
+ 0x73B9142ACBC50821UL, 0x8B7D67495887E65CUL, 0x39B6C4FB2B232E56UL,
+ 0xD212DB10E31D2A68UL, 0x629AC0A3D263DC6EUL, 0x6BC2E7FF912050BAUL,
+ 0xE0AD5A8FDB183F62UL, 0xF05648134F0C6F0FUL, 0x31E146F4AF980FDAUL,
+ 0x7FAF0078D84D62CCUL, 0xE13F044C2830D21EUL, 0x49A047AD204B4C4BUL,
+ 0xF3AFBE2237351A74UL, 0x32826C9217BB07EDUL, 0xD4C3AEB099319B5CUL,
+ 0x49CE5BD05B2B0F61UL, 0x75DD36984DCBD0A2UL, 0x84EC5D7C2F0AAC6CUL,
+ 0x8E59CC9B9942EDDFUL, 0x89FF85DCDF9AE895UL, 0x6F9EE0D8D9E8D414UL,
+ 0x10E01A59058D3904UL, 0x1DFAF567BFF55D2EUL, 0x8DD6A18C03382CD4UL,
+ 0xE12FD89A0CF58553UL, 0xE245DA902C0C4F5CUL, 0x8BE7566B9987520DUL,
+ 0x4CA1C0A4B38A3098UL, 0x81E45015BE618A72UL, 0xA80E0344FF27EFDFUL,
+ 0xC98DAEC6DC5005BAUL, 0xF56873F3A958AE5EUL, 0xDB88604670C794ACUL,
+ 0x4F68E448DDF6535FUL, 0x3443DBF1CA6031A8UL, 0x73DFA5DEEF409A41UL,
+ 0xA7C556941F6643B2UL, 0x424BC40D8C83D962UL, 0x6F292A325B99B726UL,
+ 0x6EECB1009717D65EUL, 0x899BE4CE7BB2D8EEUL, 0x25285FED3E59781DUL,
+ 0x14C5AEDD76E092D3UL, 0x9BB5EE10567640AEUL, 0xCD62A1D43558FD06UL,
+ 0x70A7B09FC5F39447UL, 0xF10064AE92EFFB99UL, 0xD55FA1A918A23082UL,
+ 0xD03F28AD25C73A78UL, 0x76CFFFEE094D8B0EUL, 0x4FD5A46AD5A4B4CFUL,
+ 0x8F3A36F9D7BF87E3UL, 0x64224315210625BEUL, 0x749A131B71B64350UL,
+ 0x9034FF9DAC089F48UL, 0xB58D3017E7321217UL, 0x549D818937D5CE90UL,
+ 0x903CE1452419E99CUL, 0xFD052F0388DB2E76UL, 0x7390051E3972480EUL,
+ 0x5E5F6EC3F27B3679UL, 0x3E3637D4D4EE917DUL, 0x4FE04068CA2A4309UL,
+ 0x98C9C17454AAE42DUL, 0x659AE0BDB113BC21UL, 0x4C0BDECB1511AF4CUL,
+ 0x17048BFAEAC0006DUL, 0x68F106AADAA64912UL, 0x2286234ECEB7EAF0UL,
+ 0x350CD42CAF697E51UL, 0x8DCDE6D1FAC19A9FUL, 0xF97E55A245A8A8A2UL,
+ 0xAAE86B2092DA90A3UL, 0x5123E878AA8AEF76UL, 0x022B88B9694A55F6UL,
+ 0xC4C1A9B1C0221985UL, 0x20056D91DD5E0FFEUL, 0xF5BF61EC225C9843UL,
+ 0x1A315A05BDCF4A31UL, 0x5710A21A8DF4F15FUL, 0x99BD1A0AF97AD027UL,
+ 0x7602C5997AD4E12CUL
+ };
+
+ public static bool IsPopularPassword(char[] vPassword)
+ {
+ Debug.Assert(PpcTable.Length == (PpcTableSize / 64));
+
+ if(vPassword == null) throw new ArgumentNullException("vPassword");
+ if(vPassword.Length == 0) return false;
+
+ foreach(char ch in vPassword)
+ {
+ if(!IsPopularChar(ch)) return false;
+ }
+
+ byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vPassword);
+
+ int[] vIndices = GetTableIndices(pbUtf8, PpcTableSize);
+ Array.Clear(pbUtf8, 0, pbUtf8.Length);
+
+ foreach(int iIndex in vIndices)
+ {
+ if(!GetTableBit(PpcTable, iIndex)) return false;
+ }
+
+ return true;
+ }
+
+ private static bool IsPopularChar(char ch)
+ {
+ return (((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) ||
+ ((ch >= '0') && (ch <= '9')) || (ch == '_') || (ch == '!'));
+ }
+
+ private static int[] GetTableIndices(byte[] pbPasswordUtf8, int nTableSize)
+ {
+ Debug.Assert(false, "not yet implemented");
+ return null;
+#if TODO
+ Debug.Assert((nTableSize >= 2) && (nTableSize <= 0x10000));
+ Debug.Assert((nTableSize % 64) == 0);
+
+ SHA512Managed sha = new SHA512Managed();
+ byte[] pbHash = sha.ComputeHash(pbPasswordUtf8);
+
+ int[] vIndices = new int[pbHash.Length / 2];
+ for(int i = 0; i < vIndices.Length; ++i)
+ vIndices[i] = ((((int)pbHash[i * 2] << 8) |
+ (int)pbHash[i * 2 + 1]) % nTableSize);
+
+ return vIndices;
+#endif
+ }
+
+ private static bool GetTableBit(ulong[] vTable, int iBit)
+ {
+ return ((vTable[iBit >> 6] & (1UL << (iBit & 0x3F))) != 0UL);
+ }
+
+#if (DEBUG && !KeePassLibSD && TODO)
+ private static bool SetTableBit(ulong[] vTable, int iBit)
+ {
+ if(GetTableBit(vTable, iBit)) return false;
+
+ vTable[iBit >> 6] = (vTable[iBit >> 6] | (1UL << (iBit & 0x3F)));
+ return true;
+ }
+
+ public static void MakeList()
+ {
+
+ string strData = File.ReadAllText("MostPopularPasswords.txt", StrUtil.Utf8);
+ strData += " ";
+ CharStream cs = new CharStream(strData);
+
+ List vPasswords = new List();
+ StringBuilder sbPassword = new StringBuilder();
+ while(true)
+ {
+ char ch = cs.ReadChar();
+ if(ch == char.MinValue) break;
+
+ if(char.IsWhiteSpace(ch))
+ {
+ string strPassword = sbPassword.ToString();
+ strPassword = strPassword.ToLower();
+
+ if(strPassword.Length > 3)
+ {
+ if(vPasswords.IndexOf(strPassword) < 0)
+ vPasswords.Add(strPassword);
+ }
+
+ sbPassword = new StringBuilder();
+ }
+ else
+ {
+ Debug.Assert(!char.IsControl(ch) && !char.IsHighSurrogate(ch) &&
+ !char.IsLowSurrogate(ch) && !char.IsSurrogate(ch));
+ Debug.Assert(IsPopularChar(ch));
+ sbPassword.Append(ch);
+ }
+ }
+
+ ulong[] vTable = new ulong[PpcTableSize / 64];
+ Array.Clear(vTable, 0, vTable.Length);
+
+ long lBitsInTable = 0;
+ foreach(string strPassword in vPasswords)
+ {
+ byte[] pbUtf8 = StrUtil.Utf8.GetBytes(strPassword);
+ int[] vIndices = GetTableIndices(pbUtf8, PpcTableSize);
+
+ foreach(int i in vIndices)
+ {
+ if(SetTableBit(vTable, i)) ++lBitsInTable;
+ }
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.Append("\t\t\t");
+ for(int i = 0; i < vTable.Length; ++i)
+ {
+ if(i > 0)
+ {
+ if((i % 3) == 0)
+ {
+ sb.AppendLine(",");
+ sb.Append("\t\t\t");
+ }
+ else sb.Append(", ");
+ }
+
+ sb.Append("0x");
+ sb.Append(vTable[i].ToString("X16"));
+ sb.Append("UL");
+ }
+
+ sb.AppendLine();
+ sb.AppendLine();
+ sb.AppendLine("Bits set: " + lBitsInTable.ToString() + " of " +
+ PpcTableSize.ToString());
+ int cHashFn = GetTableIndices(StrUtil.Utf8.GetBytes("Dummy"), PpcTableSize).Length;
+ sb.AppendLine("Hash functions: " + cHashFn.ToString());
+ double dblPhi = Math.Pow(1.0 - ((double)cHashFn / PpcTableSize),
+ (double)vPasswords.Count);
+ sb.AppendLine("Phi (bits unset ratio) estimation: " +
+ dblPhi.ToString(CultureInfo.InvariantCulture));
+ dblPhi = ((double)(PpcTableSize - lBitsInTable) / (double)PpcTableSize);
+ sb.AppendLine("Exact Phi: " + dblPhi.ToString(CultureInfo.InvariantCulture));
+ sb.AppendLine("False positives ratio: " + Math.Pow(1.0 - dblPhi,
+ (double)cHashFn).ToString(CultureInfo.InvariantCulture));
+
+ File.WriteAllText("Table.txt", sb.ToString());
+ }
+#endif
+ }
+}
+#endif
diff --git a/ModernKeePassLib/Cryptography/QualityEstimation.cs b/ModernKeePassLib/Cryptography/QualityEstimation.cs
new file mode 100644
index 0000000..b39b1af
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/QualityEstimation.cs
@@ -0,0 +1,145 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
+{
+ ///
+ /// A class that offers static functions to estimate the quality of
+ /// passwords.
+ ///
+ public static class QualityEstimation
+ {
+ private enum CharSpaceBits : uint
+ {
+ Control = 32,
+ Alpha = 26,
+ Number = 10,
+ Special = 33,
+ High = 112
+ }
+
+ ///
+ /// Estimate the quality of a password.
+ ///
+ /// Password to check.
+ /// Estimated bit-strength of the password.
+ /// Thrown if the input
+ /// parameter is null.
+ public static uint EstimatePasswordBits(char[] vPasswordChars)
+ {
+ Debug.Assert(vPasswordChars != null);
+ if(vPasswordChars == null) throw new ArgumentNullException("vPasswordChars");
+
+ bool bChLower = false, bChUpper = false, bChNumber = false;
+ bool bChSpecial = false, bChHigh = false, bChControl = false;
+ Dictionary vCharCounts = new Dictionary();
+ Dictionary vDifferences = new Dictionary();
+ double dblEffectiveLength = 0.0;
+
+ for(int i = 0; i < vPasswordChars.Length; ++i) // Get character types
+ {
+ char tch = vPasswordChars[i];
+
+ if(tch < ' ') bChControl = true;
+ else if((tch >= 'A') && (tch <= 'Z')) bChUpper = true;
+ else if((tch >= 'a') && (tch <= 'z')) bChLower = true;
+ else if((tch >= '0') && (tch <= '9')) bChNumber = true;
+ else if((tch >= ' ') && (tch <= '/')) bChSpecial = true;
+ else if((tch >= ':') && (tch <= '@')) bChSpecial = true;
+ else if((tch >= '[') && (tch <= '`')) bChSpecial = true;
+ else if((tch >= '{') && (tch <= '~')) bChSpecial = true;
+ else if(tch > '~') bChHigh = true;
+
+ double dblDiffFactor = 1.0;
+ if(i >= 1)
+ {
+ int iDiff = (int)tch - (int)vPasswordChars[i - 1];
+
+ uint uDiffCount;
+ if(vDifferences.TryGetValue(iDiff, out uDiffCount))
+ {
+ ++uDiffCount;
+ vDifferences[iDiff] = uDiffCount;
+ dblDiffFactor /= (double)uDiffCount;
+ }
+ else vDifferences.Add(iDiff, 1);
+ }
+
+ uint uCharCount;
+ if(vCharCounts.TryGetValue(tch, out uCharCount))
+ {
+ ++uCharCount;
+ vCharCounts[tch] = uCharCount;
+ dblEffectiveLength += dblDiffFactor * (1.0 / (double)uCharCount);
+ }
+ else
+ {
+ vCharCounts.Add(tch, 1);
+ dblEffectiveLength += dblDiffFactor;
+ }
+ }
+
+ uint uCharSpace = 0;
+ if(bChControl) uCharSpace += (uint)CharSpaceBits.Control;
+ if(bChUpper) uCharSpace += (uint)CharSpaceBits.Alpha;
+ if(bChLower) uCharSpace += (uint)CharSpaceBits.Alpha;
+ if(bChNumber) uCharSpace += (uint)CharSpaceBits.Number;
+ if(bChSpecial) uCharSpace += (uint)CharSpaceBits.Special;
+ if(bChHigh) uCharSpace += (uint)CharSpaceBits.High;
+
+ if(uCharSpace == 0) return 0;
+
+ double dblBitsPerChar = Math.Log((double)uCharSpace) / Math.Log(2.0);
+ double dblRating = dblBitsPerChar * dblEffectiveLength;
+
+#if !KeePassLibSD
+ char[] vLowerCopy = new char[vPasswordChars.Length];
+ for(int ilc = 0; ilc < vLowerCopy.Length; ++ilc)
+ vLowerCopy[ilc] = char.ToLower(vPasswordChars[ilc]);
+ if(PopularPasswords.IsPopularPassword(vLowerCopy)) dblRating /= 8.0;
+ Array.Clear(vLowerCopy, 0, vLowerCopy.Length);
+#endif
+
+ return (uint)Math.Ceiling(dblRating);
+ }
+
+ ///
+ /// 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[] vChars = StrUtil.Utf8.GetChars(pbUnprotectedUtf8);
+ uint uResult = EstimatePasswordBits(vChars);
+ Array.Clear(vChars, 0, vChars.Length);
+
+ return uResult;
+ }
+ }
+}
diff --git a/ModernKeePassLib/Cryptography/SHA256Managed.cs b/ModernKeePassLib/Cryptography/SHA256Managed.cs
new file mode 100644
index 0000000..4503da8
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/SHA256Managed.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.Security.Cryptography;
+using Windows.Security.Cryptography.Core;
+using Windows.Storage.Streams;
+
+namespace ModernKeePassLib.Cryptography
+{
+ // Singleton adaptor that provides a part of the .net SHA256Managed class
+
+ class SHA256Managed
+ {
+ private static SHA256Managed instance;
+ private static HashAlgorithmProvider m_AlgProv;
+
+ private SHA256Managed()
+ {
+ String strAlgName = "SHA256";
+ m_AlgProv = HashAlgorithmProvider.OpenAlgorithm(strAlgName);
+ m_AlgProv.CreateHash();
+ }
+
+ public static SHA256Managed Instance
+ {
+ get
+ {
+ if (instance == null)
+ {
+ instance = new SHA256Managed();
+ }
+ return instance;
+ }
+ }
+
+ public byte[] ComputeHash(byte[] buffer )
+ {
+ IBuffer input = CryptographicBuffer.CreateFromByteArray( buffer);
+ IBuffer hashBuffer = m_AlgProv.HashData(input);
+ byte[] hash;
+ CryptographicBuffer.CopyToByteArray(hashBuffer, out hash);
+ return hash;
+ }
+
+ }
+}
diff --git a/ModernKeePassLib/Cryptography/SelfTest.cs b/ModernKeePassLib/Cryptography/SelfTest.cs
new file mode 100644
index 0000000..b076a62
--- /dev/null
+++ b/ModernKeePassLib/Cryptography/SelfTest.cs
@@ -0,0 +1,425 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.Security;
+using Windows.Security.Cryptography.Core;
+
+using ModernKeePassLib.Cryptography.Cipher;
+using ModernKeePassLib.Utility;
+using ModernKeePassLib.Resources;
+using Windows.Storage.Streams;
+using Windows.Security.Cryptography;
+
+namespace ModernKeePassLib.Cryptography
+{
+ /* #pragma warning disable 1591
+ ///
+ /// Return values of the SelfTest.Perform method.
+ ///
+ public enum SelfTestResult
+ {
+ Success = 0,
+ RijndaelEcbError = 1,
+ Salsa20Error = 2,
+ NativeKeyTransformationError = 3
+ }
+ #pragma warning restore 1591 */
+
+ ///
+ /// Class containing self-test methods.
+ ///
+ public static class SelfTest
+ {
+ ///
+ /// Perform a self-test.
+ ///
+ public static void Perform()
+ {
+ TestFipsComplianceProblems(); // Must be the first test
+
+ TestRijndael();
+ TestSalsa20();
+
+ TestNativeKeyTransform();
+
+ TestHmacOtp();
+
+ TestProtectedObjects();
+ TestMemUtil();
+ TestStrUtil();
+ TestUrlUtil();
+
+ Debug.Assert((int)PwIcon.World == 1);
+ Debug.Assert((int)PwIcon.Warning == 2);
+ Debug.Assert((int)PwIcon.BlackBerry == 68);
+ }
+
+ internal static void TestFipsComplianceProblems()
+ {
+#if !KeePassWinRT
+ try { new RijndaelManaged(); }
+ catch(Exception exAes)
+ {
+ throw new SecurityException("AES/Rijndael: " + exAes.Message);
+ }
+
+ try { new SHA256Managed(); }
+ catch(Exception exSha256)
+ {
+ throw new SecurityException("SHA-256: " + exSha256.Message);
+ }
+#endif
+ }
+
+ private static void TestRijndael()
+ {
+
+ // 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;
+
+ String strAlgName = "AES_ECB"; // Algorithm name
+
+ IBuffer iv = null; // no IV used in ECB.
+ IBuffer buffMsg = CryptographicBuffer.CreateFromByteArray(pbTestData);
+ IBuffer keyMaterial = CryptographicBuffer.CreateFromByteArray(pbTestKey);
+ SymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(strAlgName);
+ CryptographicKey key = objAlg.CreateSymmetricKey(keyMaterial);
+
+ // Encrypt the data and return.
+ IBuffer buffEncrypt = CryptographicEngine.Encrypt(key, buffMsg, iv);
+ CryptographicBuffer.CopyToByteArray(buffEncrypt, out pbTestData);
+
+ if (!MemUtil.ArraysEqual(pbTestData, pbReferenceCT))
+ throw new SecurityException(KLRes.EncAlgorithmAes + ".");
+
+
+#if false
+
+ RijndaelManaged r = new RijndaelManaged();
+
+ if(r.BlockSize != 128) // AES block size
+ {
+ Debug.Assert(false);
+ r.BlockSize = 128;
+ }
+
+ r.IV = pbIV;
+ r.KeySize = 256;
+ r.Key = pbTestKey;
+ r.Mode = CipherMode.ECB;
+ ICryptoTransform iCrypt = r.CreateEncryptor();
+
+ iCrypt.TransformBlock(pbTestData, 0, 16, pbTestData, 0);
+
+ if(!MemUtil.ArraysEqual(pbTestData, pbReferenceCT))
+ throw new SecurityException(KLRes.EncAlgorithmAes + ".");
+
+#endif
+ }
+
+ private static void TestSalsa20()
+ {
+ // 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, pb.Length, false);
+ if(!MemUtil.ArraysEqual(pb, pbExpected))
+ throw new SecurityException("Salsa20.");
+
+#if DEBUG
+ // Extended test in debug mode
+ 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
+ };
+
+ Random r = new Random();
+ int nPos = Salsa20ToPos(c, r, pb.Length, 65536);
+ c.Encrypt(pb, pb.Length, false);
+ 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, pb.Length, true);
+ if(!MemUtil.ArraysEqual(pb, pbExpected3))
+ throw new SecurityException("Salsa20-3.");
+#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, nGen, r.Next(0, 2) == 0);
+ nPos += nGen;
+ }
+
+ return nTargetPos;
+ }
+#endif
+
+ private static void TestNativeKeyTransform()
+ {
+#if DEBUG && TODO
+ byte[] pbOrgKey = CryptoRandom.Instance.GetRandomBytes(32);
+ byte[] pbSeed = CryptoRandom.Instance.GetRandomBytes(32);
+ ulong uRounds = (ulong)((new Random()).Next(1, 0x3FFF));
+
+ byte[] pbManaged = new byte[32];
+ Array.Copy(pbOrgKey, pbManaged, 32);
+ if(CompositeKey.TransformKeyManaged(pbManaged, pbSeed, uRounds) == false)
+ throw new SecurityException("Managed transform.");
+
+ byte[] pbNative = new byte[32];
+ Array.Copy(pbOrgKey, pbNative, 32);
+ if(NativeLib.TransformKey256(pbNative, pbSeed, uRounds) == false)
+ return; // Native library not available ("success")
+
+ if(!MemUtil.ArraysEqual(pbManaged, pbNative))
+ throw new SecurityException("Native transform.");
+#endif
+ }
+
+ private static void TestMemUtil()
+ {
+#if DEBUG && !KeePassWinRT
+ Random r = new Random();
+ 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");
+
+ pb = Encoding.ASCII.GetBytes("012345678901234567890a");
+ byte[] pbN = Encoding.ASCII.GetBytes("9012");
+ if(MemUtil.IndexOf(pb, pbN) != 9)
+ throw new InvalidOperationException("MemUtil-1");
+ pbN = Encoding.ASCII.GetBytes("01234567890123");
+ if(MemUtil.IndexOf(pb, pbN) != 0)
+ throw new InvalidOperationException("MemUtil-2");
+ pbN = Encoding.ASCII.GetBytes("a");
+ if(MemUtil.IndexOf(pb, pbN) != 21)
+ throw new InvalidOperationException("MemUtil-3");
+ pbN = Encoding.ASCII.GetBytes("0a");
+ if(MemUtil.IndexOf(pb, pbN) != 20)
+ throw new InvalidOperationException("MemUtil-4");
+ pbN = Encoding.ASCII.GetBytes("1");
+ if(MemUtil.IndexOf(pb, pbN) != 1)
+ throw new InvalidOperationException("MemUtil-5");
+ pbN = Encoding.ASCII.GetBytes("b");
+ if(MemUtil.IndexOf(pb, pbN) >= 0)
+ throw new InvalidOperationException("MemUtil-6");
+ pbN = Encoding.ASCII.GetBytes("012b");
+ if(MemUtil.IndexOf(pb, pbN) >= 0)
+ throw new InvalidOperationException("MemUtil-7");
+#endif
+ }
+
+ private static void TestHmacOtp()
+ {
+#if (DEBUG && !KeePassLibSD && TODO)
+ byte[] pbSecret = Encoding.ASCII.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()
+ {
+
+#if TODO
+#if DEBUG
+ byte[] pbData = Encoding.UTF8.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 = Encoding.UTF8.GetBytes("Test Test Test Test");
+ byte[] pbData3 = Encoding.UTF8.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,
+ StrUtil.Utf8.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");
+#endif
+#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, true) != "255.0")
+ throw new InvalidOperationException("StrUtil-V5");
+ if(StrUtil.VersionToString(0x0000000000070000UL, true) != "0.0.7")
+ throw new InvalidOperationException("StrUtil-V6");
+#endif
+ }
+
+ private static void TestUrlUtil()
+ {
+#if DEBUG && TODO
+ if(UrlUtil.GetHost(@"scheme://domain:port/path?query_string#fragment_id") !=
+ "domain")
+ throw new InvalidOperationException("UrlUtil-H1");
+ if(UrlUtil.GetHost(@"http://example.org:80") != "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");
+#endif
+ }
+ }
+}
diff --git a/ModernKeePassLib/DebugAssert.cs b/ModernKeePassLib/DebugAssert.cs
new file mode 100644
index 0000000..caaf213
--- /dev/null
+++ b/ModernKeePassLib/DebugAssert.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ModernKeePassLib
+{
+ public class Debug
+ {
+ [Conditional("DEBUG")]
+ public static void Assert(bool condition, string why)
+ {
+ if (!condition)
+ System.Diagnostics.Debugger.Break();
+
+ }
+
+ [Conditional("DEBUG")]
+ public static void Assert(bool condition)
+ {
+ if (!condition)
+ System.Diagnostics.Debugger.Break();
+
+ }
+
+ }
+
+}
diff --git a/ModernKeePassLib/Delegates/Handlers.cs b/ModernKeePassLib/Delegates/Handlers.cs
new file mode 100644
index 0000000..1ad7df6
--- /dev/null
+++ b/ModernKeePassLib/Delegates/Handlers.cs
@@ -0,0 +1,49 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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);
+}
diff --git a/ModernKeePassLib/Interfaces/IDeepCloneable.cs b/ModernKeePassLib/Interfaces/IDeepCloneable.cs
new file mode 100644
index 0000000..b77011a
--- /dev/null
+++ b/ModernKeePassLib/Interfaces/IDeepCloneable.cs
@@ -0,0 +1,37 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
new file mode 100644
index 0000000..3234533
--- /dev/null
+++ b/ModernKeePassLib/Interfaces/IStatusLogger.cs
@@ -0,0 +1,105 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
new file mode 100644
index 0000000..915cef3
--- /dev/null
+++ b/ModernKeePassLib/Interfaces/IStructureItem.cs
@@ -0,0 +1,37 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
new file mode 100644
index 0000000..114ced4
--- /dev/null
+++ b/ModernKeePassLib/Interfaces/ITimeLogger.cs
@@ -0,0 +1,105 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 accessed.
+ ///
+ DateTime LastAccessTime
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// The date/time when the object was last modified.
+ ///
+ DateTime LastModificationTime
+ {
+ 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
new file mode 100644
index 0000000..eb063fc
--- /dev/null
+++ b/ModernKeePassLib/Interfaces/IUIOperations.cs
@@ -0,0 +1,37 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
new file mode 100644
index 0000000..7e42c9f
--- /dev/null
+++ b/ModernKeePassLib/Interfaces/IXmlSerializerEx.cs
@@ -0,0 +1,33 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.2.19.0.26321.nupkg b/ModernKeePassLib/KeePassLib.2.19.0.26321.nupkg
new file mode 100644
index 0000000..197666a
Binary files /dev/null and b/ModernKeePassLib/KeePassLib.2.19.0.26321.nupkg differ
diff --git a/ModernKeePassLib/KeePassLib.nuget.targets b/ModernKeePassLib/KeePassLib.nuget.targets
new file mode 100644
index 0000000..8930d73
--- /dev/null
+++ b/ModernKeePassLib/KeePassLib.nuget.targets
@@ -0,0 +1,9 @@
+
+
+
+ $(UserProfile)\.nuget\packages\
+
+
+
+
+
\ No newline at end of file
diff --git a/ModernKeePassLib/Keys/CompositeKey.cs b/ModernKeePassLib/Keys/CompositeKey.cs
new file mode 100644
index 0000000..6e2cdce
--- /dev/null
+++ b/ModernKeePassLib/Keys/CompositeKey.cs
@@ -0,0 +1,410 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.Text;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using Windows.Security.Cryptography.Core;
+
+using ModernKeePassLib.Native;
+using ModernKeePassLib.Resources;
+using ModernKeePassLib.Security;
+using ModernKeePassLib.Utility;
+using System.Threading.Tasks;
+using Windows.Security.Cryptography;
+using Windows.Storage.Streams;
+using ModernKeePassLib.Cryptography;
+
+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(false, "not yet implemented");
+ return false;
+#if TODO
+ Debug.Assert(tUserKeyType != null);
+ if(tUserKeyType == null) throw new ArgumentNullException("tUserKeyType");
+
+ foreach(IUserKey pKey in m_vUserKeys)
+ {
+ if(tUserKeyType.IsInstanceOfType(pKey))
+ return true;
+ }
+
+ return false;
+#endif
+ }
+
+ ///
+ /// 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(false, "not yet implemented");
+ return null;
+#if TODO
+
+ Debug.Assert(tUserKeyType != null);
+ if(tUserKeyType == null) throw new ArgumentNullException("tUserKeyType");
+
+ foreach(IUserKey pKey in m_vUserKeys)
+ {
+ if(tUserKeyType.IsInstanceOfType(pKey))
+ return pKey;
+ }
+
+ return null;
+#endif
+ }
+
+ ///
+ /// Creates the composite key from the supplied user key sources (password,
+ /// key file, user account, computer ID, etc.).
+ ///
+ private async Task CreateRawCompositeKey32()
+ {
+ ValidateUserKeys();
+
+ // Concatenate user key data
+ MemoryStream ms = new MemoryStream();
+ foreach(IUserKey pKey in m_vUserKeys)
+ {
+ ProtectedBinary b = pKey.KeyData;
+ if(b != null)
+ {
+ byte[] pbKeyData = b.ReadData();
+ ms.Write(pbKeyData, 0, pbKeyData.Length);
+ MemUtil.ZeroByteArray(pbKeyData);
+ }
+ }
+
+ byte[] pbHash = SHA256Managed.Instance.ComputeHash(ms.ToArray());
+
+ return pbHash;
+
+ }
+
+ public async Task EqualsValue(CompositeKey ckOther)
+ {
+ if(ckOther == null) throw new ArgumentNullException("ckOther");
+
+ byte[] pbThis = await CreateRawCompositeKey32();
+ byte[] pbOther = await ckOther.CreateRawCompositeKey32();
+ bool bResult = MemUtil.ArraysEqual(pbThis, pbOther);
+ Array.Clear(pbOther, 0, pbOther.Length);
+ Array.Clear(pbThis, 0, pbThis.Length);
+
+ return bResult;
+ }
+
+ ///
+ /// Generate a 32-bit wide key out of the composite key.
+ ///
+ /// Seed used in the key transformation
+ /// rounds. Must be a byte array containing exactly 32 bytes; must
+ /// not be null.
+ /// Number of key transformation rounds.
+ /// Returns a protected binary object that contains the
+ /// resulting 32-bit wide key.
+ public async Task 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");
+
+ byte[] pbRaw32 = await CreateRawCompositeKey32();
+ if((pbRaw32 == null) || (pbRaw32.Length != 32))
+ { Debug.Assert(false); return null; }
+
+ byte[] pbTrf32 = TransformKey(pbRaw32, pbKeySeed32, uNumRounds);
+ if((pbTrf32 == null) || (pbTrf32.Length != 32))
+ { Debug.Assert(false); return null; }
+
+ 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();
+ }
+ }
+
+ ///
+ /// Transform the current key uNumRounds times.
+ ///
+ /// The original key which will be transformed.
+ /// This parameter won't be modified.
+ /// Seed used for key transformations. Must not
+ /// be null. This parameter won't be modified.
+ /// Transformation count.
+ /// 256-bit transformed key.
+ 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);
+
+ if(TransformKeyManaged(pbNewKey, pbKeySeed32, uNumRounds) == false)
+ return null;
+
+ byte[] transformedKey = SHA256Managed.Instance.ComputeHash(pbNewKey);
+ return (transformedKey);
+ }
+
+ public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32,
+ ulong uNumRounds)
+ {
+
+ byte[] pbIV = new byte[16];
+ Array.Clear(pbIV, 0, pbIV.Length);
+
+ String strAlgName = "AES_ECB"; // Algorithm name
+
+ IBuffer iv = null; // no IV used in ECB.
+ IBuffer buffMsg = CryptographicBuffer.CreateFromByteArray(pbNewKey32);
+ IBuffer keyMaterial = CryptographicBuffer.CreateFromByteArray(pbKeySeed32);
+ SymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(strAlgName);
+ CryptographicKey key = objAlg.CreateSymmetricKey(keyMaterial);
+
+ for (ulong i = 0; i < uNumRounds; ++i)
+ {
+ buffMsg = CryptographicEngine.Encrypt(key, buffMsg, iv);
+ }
+ byte[] newKey32;
+ CryptographicBuffer.CopyToByteArray(buffMsg, out newKey32);
+ newKey32.CopyTo(pbNewKey32,0);
+
+ return true;
+ }
+
+ ///
+ /// Benchmark the TransformKey method. Within
+ /// ms, random keys will be transformed
+ /// and the number of performed transformations are returned.
+ ///
+ /// Test duration in ms.
+ /// Stepping.
+ /// should be a prime number. For fast processors
+ /// (PCs) a value of 3001 is recommended, for slower processors (PocketPC)
+ /// a value of 401 is recommended.
+ /// Number of transformations performed in the specified
+ /// amount of time. Maximum value is uint.MaxValue.
+ public static ulong TransformKeyBenchmark(uint uMilliseconds, ulong uStep)
+ {
+ Debug.Assert(false, "not yet implemented");
+ return 0;
+#if TODO
+ ulong uRounds;
+
+ // Try native method
+ if(NativeLib.TransformKeyBenchmark256(uMilliseconds, out uRounds))
+ return uRounds;
+
+ byte[] pbIV = new byte[16];
+ Array.Clear(pbIV, 0, pbIV.Length);
+
+ 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;
+ }
+
+ RijndaelManaged r = new RijndaelManaged();
+ if(r.BlockSize != 128) // AES block size
+ {
+ Debug.Assert(false);
+ r.BlockSize = 128;
+ }
+
+ r.IV = pbIV;
+ r.Mode = CipherMode.ECB;
+ r.KeySize = 256;
+ r.Key = pbKey;
+ ICryptoTransform iCrypt = r.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 PwDefs.DefaultKeyEncryptionRounds;
+ }
+
+ DateTime dtStart = DateTime.Now;
+ TimeSpan ts;
+ double dblReqMillis = uMilliseconds;
+
+ uRounds = 0;
+ while(true)
+ {
+ for(ulong j = 0; j < uStep; ++j)
+ {
+ iCrypt.TransformBlock(pbNewKey, 0, 16, pbNewKey, 0);
+ iCrypt.TransformBlock(pbNewKey, 16, 16, pbNewKey, 16);
+ }
+
+ uRounds += uStep;
+ if(uRounds < uStep) // Overflow check
+ {
+ uRounds = ulong.MaxValue;
+ break;
+ }
+
+ ts = DateTime.Now - dtStart;
+ if(ts.TotalMilliseconds > dblReqMillis) break;
+ }
+
+ return uRounds;
+#endif
+ }
+ }
+
+ public sealed class InvalidCompositeKeyException : Exception
+ {
+
+ public override string Message
+ {
+ get
+ {
+ return "The composite key is invalid!" + Environment.NewLine + "Make sure the composite key is correct and try again."; // No translation needed here, the message will not be shown in the UI.
+ }
+ }
+
+ ///
+ /// Construct a new invalid composite key exception.
+ ///
+ public InvalidCompositeKeyException()
+ {
+ }
+ }
+}
diff --git a/ModernKeePassLib/Keys/IUserKey.cs b/ModernKeePassLib/Keys/IUserKey.cs
new file mode 100644
index 0000000..81fa416
--- /dev/null
+++ b/ModernKeePassLib/Keys/IUserKey.cs
@@ -0,0 +1,46 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
new file mode 100644
index 0000000..c87083b
--- /dev/null
+++ b/ModernKeePassLib/Keys/KcpCustomKey.cs
@@ -0,0 +1,69 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 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(false, "not yet implemented");
+ return;
+#if TODO
+
+ 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)
+ {
+ SHA256Managed sha256 = new SHA256Managed();
+ byte[] pbRaw = sha256.ComputeHash(pbKeyData);
+ m_pbKey = new ProtectedBinary(true, pbRaw);
+ }
+ else m_pbKey = new ProtectedBinary(true, pbKeyData);
+#endif
+ }
+
+ // public void Clear()
+ // {
+ // m_pbKey = null;
+ // }
+ }
+}
diff --git a/ModernKeePassLib/Keys/KcpKeyFile.cs b/ModernKeePassLib/Keys/KcpKeyFile.cs
new file mode 100644
index 0000000..124e499
--- /dev/null
+++ b/ModernKeePassLib/Keys/KcpKeyFile.cs
@@ -0,0 +1,287 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 ModernKeePassLib.Security;
+using ModernKeePassLib.Serialization;
+
+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; }
+ }
+
+ public KcpKeyFile(string strKeyFile)
+ {
+ Construct(IOConnectionInfo.FromPath(strKeyFile));
+ }
+
+ public KcpKeyFile(IOConnectionInfo iocKeyFile)
+ {
+ Construct(iocKeyFile);
+ }
+
+ private void Construct(IOConnectionInfo iocFile)
+ {
+ Debug.Assert(false, "not yet implemented");
+ return;
+#if TODO
+ byte[] pbFileData = IOConnection.ReadFile(iocFile);
+ if(pbFileData == null) throw new FileNotFoundException();
+
+ 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);
+#endif
+ }
+
+ // public void Clear()
+ // {
+ // m_strPath = string.Empty;
+ // m_pbKeyData = null;
+ // }
+
+ private static byte[] LoadKeyFile(byte[] pbFileData)
+ {
+ Debug.Assert(false, "not yet implemented");
+ return null;
+#if TODO
+ 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)
+ {
+ SHA256Managed sha256 = new SHA256Managed();
+ pbKey = sha256.ComputeHash(pbFileData);
+ }
+
+ return pbKey;
+#endif
+ }
+
+ 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)
+ {
+ Debug.Assert(false, "not yet implemented");
+ return null;
+#if TODO
+ if(pbFileData == null) { Debug.Assert(false); return null; }
+ if(pbFileData.Length != 64) { Debug.Assert(false); return null; }
+
+ try
+ {
+ string strHex = Encoding.ASCII.GetString(pbFileData, 0, 64);
+ if(!StrUtil.IsHexString(strHex, true)) return null;
+
+ byte[] pbKey = MemUtil.HexStringToByteArray(strHex);
+ if((pbKey == null) || (pbKey.Length != 32))
+ return null;
+
+ return pbKey;
+ }
+ catch(Exception) { Debug.Assert(false); }
+
+ return null;
+#endif
+ }
+
+ ///
+ /// 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.
+ public static void Create(string strFilePath, byte[] pbAdditionalEntropy)
+ {
+ Debug.Assert(false, "not yet implemented");
+ return;
+#if TODO
+ byte[] pbKey32 = CryptoRandom.Instance.GetRandomBytes(32);
+ if(pbKey32 == null) throw new SecurityException();
+
+ byte[] pbFinalKey32;
+ if((pbAdditionalEntropy == null) || (pbAdditionalEntropy.Length == 0))
+ pbFinalKey32 = pbKey32;
+ else
+ {
+ MemoryStream ms = new MemoryStream();
+ ms.Write(pbAdditionalEntropy, 0, pbAdditionalEntropy.Length);
+ ms.Write(pbKey32, 0, 32);
+
+ SHA256Managed sha256 = new SHA256Managed();
+ pbFinalKey32 = sha256.ComputeHash(ms.ToArray());
+ ms.Close();
+ }
+
+ CreateXmlKeyFile(strFilePath, pbFinalKey32);
+#endif
+ }
+
+ // ================================================================
+ // 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)
+ {
+ Debug.Assert(false, "not yet implemented");
+ return null;
+#if TODO
+ if(pbFileData == null) { Debug.Assert(false); return null; }
+
+ MemoryStream ms = new MemoryStream(pbFileData, false);
+ byte[] pbKeyData = null;
+
+ try
+ {
+ XmlDocument doc = new XmlDocument();
+ 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);
+ }
+ }
+ }
+ }
+ }
+ catch(Exception) { pbKeyData = null; }
+ finally { ms.Close(); }
+
+ return pbKeyData;
+#endif
+ }
+
+ private static void CreateXmlKeyFile(string strFile, byte[] pbKeyData)
+ {
+ Debug.Assert(false, "not yet implemented");
+ return;
+#if TODO
+
+ Debug.Assert(strFile != null);
+ if(strFile == null) throw new ArgumentNullException("strFile");
+ Debug.Assert(pbKeyData != null);
+ if(pbKeyData == null) throw new ArgumentNullException("pbKeyData");
+
+ XmlTextWriter xtw = new XmlTextWriter(strFile, StrUtil.Utf8);
+
+ xtw.WriteStartDocument();
+ xtw.WriteWhitespace("\r\n");
+ xtw.WriteStartElement(RootElementName); // KeyFile
+ xtw.WriteWhitespace("\r\n\t");
+
+ xtw.WriteStartElement(MetaElementName); // Meta
+ xtw.WriteWhitespace("\r\n\t\t");
+ xtw.WriteStartElement(VersionElementName); // Version
+ xtw.WriteString("1.00");
+ xtw.WriteEndElement(); // End Version
+ xtw.WriteWhitespace("\r\n\t");
+ xtw.WriteEndElement(); // End Meta
+ xtw.WriteWhitespace("\r\n\t");
+
+ xtw.WriteStartElement(KeyElementName); // Key
+ xtw.WriteWhitespace("\r\n\t\t");
+
+ xtw.WriteStartElement(KeyDataElementName); // Data
+ xtw.WriteString(Convert.ToBase64String(pbKeyData));
+ xtw.WriteEndElement(); // End Data
+ xtw.WriteWhitespace("\r\n\t");
+
+ xtw.WriteEndElement(); // End Key
+ xtw.WriteWhitespace("\r\n");
+
+ xtw.WriteEndElement(); // RootElementName
+ xtw.WriteWhitespace("\r\n");
+ xtw.WriteEndDocument(); // End KeyFile
+ xtw.Close();
+#endif
+ }
+ }
+}
diff --git a/ModernKeePassLib/Keys/KcpPassword.cs b/ModernKeePassLib/Keys/KcpPassword.cs
new file mode 100644
index 0000000..323a4ca
--- /dev/null
+++ b/ModernKeePassLib/Keys/KcpPassword.cs
@@ -0,0 +1,82 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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;
+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");
+
+ byte[] pbRaw = SHA256Managed.Instance.ComputeHash(pbPasswordUtf8);
+
+ m_psPassword = new ProtectedString(true, pbPasswordUtf8);
+ m_pbKeyData = new ProtectedBinary(true, pbRaw);
+
+ }
+
+ // public void Clear()
+ // {
+ // m_psPassword = null;
+ // m_pbKeyData = null;
+ // }
+ }
+}
diff --git a/ModernKeePassLib/Keys/KcpUserAccount.cs b/ModernKeePassLib/Keys/KcpUserAccount.cs
new file mode 100644
index 0000000..ffd5914
--- /dev/null
+++ b/ModernKeePassLib/Keys/KcpUserAccount.cs
@@ -0,0 +1,150 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 ModernKeePassLib.Security;
+
+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()
+ {
+ Debug.Assert(false, "not yet implemented");
+ return;
+#if TODO
+ // Test if ProtectedData is supported -- throws an exception
+ // when running on an old system (Windows 98 / ME).
+ byte[] pbDummyData = new byte[128];
+ ProtectedData.Protect(pbDummyData, m_pbEntropy,
+ DataProtectionScope.CurrentUser);
+
+ byte[] pbKey = LoadUserKey(false);
+ if(pbKey == null) pbKey = CreateUserKey();
+ if(pbKey == null) throw new SecurityException(KLRes.UserAccountKeyError);
+
+ m_pbKeyData = new ProtectedBinary(true, pbKey);
+ Array.Clear(pbKey, 0, pbKey.Length);
+#endif
+ }
+
+ // public void Clear()
+ // {
+ // m_pbKeyData = null;
+ // }
+
+ private static string GetUserKeyFilePath(bool bCreate)
+ {
+ Debug.Assert(false, "not yet implemented");
+ return null;
+#if TODO
+
+ string strUserDir = Environment.GetFolderPath(
+ Environment.SpecialFolder.ApplicationData);
+
+ strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
+ strUserDir += PwDefs.ShortProductName;
+
+ if(bCreate && !Directory.Exists(strUserDir))
+ Directory.CreateDirectory(strUserDir);
+
+ strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
+ return strUserDir + UserKeyFileName;
+#endif
+ }
+
+ private static byte[] LoadUserKey(bool bShowWarning)
+ {
+ byte[] pbKey = null;
+
+#if !KeePassLibSD && TODO
+ try
+ {
+ string strFilePath = GetUserKeyFilePath(false);
+ byte[] pbProtectedKey = File.ReadAllBytes(strFilePath);
+
+ pbKey = ProtectedData.Unprotect(pbProtectedKey, m_pbEntropy,
+ DataProtectionScope.CurrentUser);
+
+ Array.Clear(pbProtectedKey, 0, pbProtectedKey.Length);
+ }
+ catch(Exception exLoad)
+ {
+ if(bShowWarning) MessageService.ShowWarning(exLoad);
+
+ pbKey = null;
+ }
+#endif
+
+ return pbKey;
+ }
+
+ private static byte[] CreateUserKey()
+ {
+ byte[] pbKey = null;
+
+#if !KeePassLibSD && TODO
+ try
+ {
+ string strFilePath = GetUserKeyFilePath(true);
+
+ byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64);
+ byte[] pbProtectedKey = ProtectedData.Protect(pbRandomKey,
+ m_pbEntropy, DataProtectionScope.CurrentUser);
+
+ File.WriteAllBytes(strFilePath, pbProtectedKey);
+
+ Array.Clear(pbProtectedKey, 0, pbProtectedKey.Length);
+ Array.Clear(pbRandomKey, 0, pbRandomKey.Length);
+
+ pbKey = LoadUserKey(true);
+ }
+ catch(Exception) { pbKey = null; }
+#endif
+
+ return pbKey;
+ }
+ }
+}
diff --git a/ModernKeePassLib/Keys/KeyProvider.cs b/ModernKeePassLib/Keys/KeyProvider.cs
new file mode 100644
index 0000000..631126f
--- /dev/null
+++ b/ModernKeePassLib/Keys/KeyProvider.cs
@@ -0,0 +1,152 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
new file mode 100644
index 0000000..83dc45d
--- /dev/null
+++ b/ModernKeePassLib/Keys/KeyProviderPool.cs
@@ -0,0 +1,105 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
new file mode 100644
index 0000000..3c7390a
--- /dev/null
+++ b/ModernKeePassLib/Keys/KeyValidator.cs
@@ -0,0 +1,51 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
new file mode 100644
index 0000000..631afb4
--- /dev/null
+++ b/ModernKeePassLib/Keys/KeyValidatorPool.cs
@@ -0,0 +1,86 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
new file mode 100644
index 0000000..2179813
--- /dev/null
+++ b/ModernKeePassLib/Keys/UserKeyType.cs
@@ -0,0 +1,33 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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/ModernKeePassLib.csproj b/ModernKeePassLib/ModernKeePassLib.csproj
new file mode 100644
index 0000000..92492b6
--- /dev/null
+++ b/ModernKeePassLib/ModernKeePassLib.csproj
@@ -0,0 +1,219 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {A207789D-9020-401B-9D0A-D0D2CFF721BD}
+ Library
+ Properties
+ ModernKeePassLib
+ ModernKeePassLib
+ en-US
+ 512
+ {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 14.0
+ v5.0
+
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ TRACE;DEBUG;NETFX_CORE, KeePassWinRT
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE;NETFX_CORE, KeePassWinRT
+ prompt
+ 4
+
+
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE
+ ;2008
+ full
+ ARM
+ false
+ prompt
+ true
+
+
+ bin\ARM\Release\
+ TRACE
+ true
+ ;2008
+ pdbonly
+ ARM
+ false
+ prompt
+ true
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ ;2008
+ full
+ x64
+ false
+ prompt
+ true
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ ;2008
+ pdbonly
+ x64
+ false
+ prompt
+ true
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ ;2008
+ full
+ x86
+ false
+ prompt
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ ;2008
+ pdbonly
+ x86
+ false
+ prompt
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5.1\System.Net.Requests.dll
+
+
+ ..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5.1\System.Xml.XmlSerializer.dll
+
+
+ ..\..\..\..\..\..\Program Files (x86)\Windows Kits\8.1\References\CommonConfiguration\Neutral\Windows.winmd
+
+
+
+ 12.0
+
+
+
+
\ No newline at end of file
diff --git a/ModernKeePassLib/ModernKeePassLib.csproj.user b/ModernKeePassLib/ModernKeePassLib.csproj.user
new file mode 100644
index 0000000..ca1d04b
--- /dev/null
+++ b/ModernKeePassLib/ModernKeePassLib.csproj.user
@@ -0,0 +1,6 @@
+
+
+
+ ProjectFiles
+
+
\ No newline at end of file
diff --git a/ModernKeePassLib/ModernKeePassLib.nuget.targets b/ModernKeePassLib/ModernKeePassLib.nuget.targets
new file mode 100644
index 0000000..8930d73
--- /dev/null
+++ b/ModernKeePassLib/ModernKeePassLib.nuget.targets
@@ -0,0 +1,9 @@
+
+
+
+ $(UserProfile)\.nuget\packages\
+
+
+
+
+
\ No newline at end of file
diff --git a/ModernKeePassLib/ModernKeePassLib.nuspec b/ModernKeePassLib/ModernKeePassLib.nuspec
new file mode 100644
index 0000000..13d5f6a
--- /dev/null
+++ b/ModernKeePassLib/ModernKeePassLib.nuspec
@@ -0,0 +1,18 @@
+
+
+
+ $id$
+ $version$
+ $title$
+ $author$
+ $author$
+ http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE
+ http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE
+ http://ICON_URL_HERE_OR_DELETE_THIS_LINE
+ false
+ $description$
+ Summary of changes made in this release of the package.
+ Copyright 2017
+ Tag1 Tag2
+
+
\ No newline at end of file
diff --git a/ModernKeePassLib/ModernKeePassLib.pfx b/ModernKeePassLib/ModernKeePassLib.pfx
new file mode 100644
index 0000000..19b0155
Binary files /dev/null and b/ModernKeePassLib/ModernKeePassLib.pfx differ
diff --git a/ModernKeePassLib/Native/NativeLib.cs b/ModernKeePassLib/Native/NativeLib.cs
new file mode 100644
index 0000000..31faabd
--- /dev/null
+++ b/ModernKeePassLib/Native/NativeLib.cs
@@ -0,0 +1,244 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.Runtime.InteropServices;
+using System.Diagnostics;
+
+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; }
+ }
+
+ ///
+ /// 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;
+
+#if KeePassWinRT
+ return false;
+#else
+
+ 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;
+#endif //KeePassWinRT
+ }
+
+ // TODO Bert : Not supported for the time being.
+#if !KeePassWinRT
+ private static PlatformID? m_platID = null;
+ public static PlatformID GetPlatformID()
+ {
+ if(m_platID.HasValue) return m_platID.Value;
+
+ m_platID = Environment.OSVersion.Platform;
+
+#if !KeePassLibSD
+ // 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;
+ }
+#endif
+
+
+ // BERT Todo: Not supported for the moment.
+#if !KeePassLibSD && TODO
+ public static string RunConsoleApp(string strAppPath, string strParams)
+ {
+ return RunConsoleApp(strAppPath, strParams, null);
+ }
+
+ public static string RunConsoleApp(string strAppPath, string strParams,
+ string strStdInput)
+ {
+ if(strAppPath == null) throw new ArgumentNullException("strAppPath");
+ if(strAppPath.Length == 0) throw new ArgumentException("strAppPath");
+
+ try
+ {
+ ProcessStartInfo psi = new ProcessStartInfo();
+
+ psi.CreateNoWindow = true;
+ psi.FileName = strAppPath;
+ psi.WindowStyle = ProcessWindowStyle.Hidden;
+ psi.UseShellExecute = false;
+ psi.RedirectStandardOutput = true;
+
+ if(strStdInput != null) psi.RedirectStandardInput = true;
+
+ if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams;
+
+ Process p = Process.Start(psi);
+
+ if(strStdInput != null)
+ {
+ p.StandardInput.Write(strStdInput);
+ p.StandardInput.Close();
+ }
+
+ string strOutput = p.StandardOutput.ReadToEnd();
+ p.WaitForExit();
+
+ return strOutput;
+ }
+ catch(Exception) { Debug.Assert(false); }
+
+ return null;
+ }
+#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(m_bAllowNative == false) 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);
+
+ NativeLib.FreeArrays(kvp);
+ return bResult;
+ }
+
+ ///
+ /// Benchmark key transformation.
+ ///
+ /// Number of seconds 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(m_bAllowNative == false) return false;
+
+ try { puRounds = NativeMethods.TransformKeyBenchmark(uTimeMs); }
+ catch(Exception) { return false; }
+
+ return true;
+ }
+
+ 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.cs b/ModernKeePassLib/Native/NativeMethods.cs
new file mode 100644
index 0000000..3378e01
--- /dev/null
+++ b/ModernKeePassLib/Native/NativeMethods.cs
@@ -0,0 +1,154 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.Text;
+using System.Security;
+using System.Runtime.InteropServices;
+
+namespace ModernKeePassLib.Native
+{
+ internal static class NativeMethods
+ {
+ internal const int MAX_PATH = 260;
+
+ /* [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(Marshal.SizeOf(typeof(IntPtr)) == 8)
+ return TransformKey64(pBuf256, pKey256, uRounds);
+ else
+ return TransformKey32(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(Marshal.SizeOf(typeof(IntPtr)) == 8)
+ return TransformKeyTimed64(pBuf256, pKey256, ref puRounds, uSeconds);
+ else
+ return TransformKeyTimed32(pBuf256, pKey256, ref puRounds, uSeconds);
+ } */
+
+ [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(Marshal.SizeOf(typeof(IntPtr)) == 8)
+ return TransformKey64(pBuf256, pKey256, uRounds);
+ else
+ return TransformKey32(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(Marshal.SizeOf(typeof(IntPtr)) == 8)
+ return TransformKeyBenchmark64(uTimeMs);
+ else
+ return TransformKeyBenchmark32(uTimeMs);
+ }
+
+#if !KeePassLibSD && TODO
+ [DllImport("ShlWApi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
+ internal static extern int StrCmpLogicalW(string x, string y);
+
+ [DllImport("ShlWApi.dll", CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool PathRelativePathTo([Out] StringBuilder pszPath,
+ [In] string pszFrom, [In] uint dwAttrFrom, [In] string pszTo,
+ [In] uint dwAttrTo);
+#endif
+
+ private static bool? m_bSupportsLogicalCmp = null;
+
+ private static void TestNaturalComparisonsSupport()
+ {
+#if KeePassLibSD || !TODO
+#warning No native natural comparisons supported.
+ m_bSupportsLogicalCmp = false;
+#else
+ try
+ {
+ StrCmpLogicalW("0", "0"); // Throws exception if unsupported
+ m_bSupportsLogicalCmp = true;
+ }
+ catch(Exception) { m_bSupportsLogicalCmp = false; }
+#endif
+ }
+
+ internal static bool SupportsStrCmpNaturally
+ {
+ get
+ {
+ if(m_bSupportsLogicalCmp.HasValue == false)
+ TestNaturalComparisonsSupport();
+
+ return m_bSupportsLogicalCmp.Value;
+ }
+ }
+
+ internal static int StrCmpNaturally(string x, string y)
+ {
+ if(m_bSupportsLogicalCmp.HasValue == false) TestNaturalComparisonsSupport();
+ if(m_bSupportsLogicalCmp.Value == false) return 0;
+
+#if KeePassLibSD || !TODO
+#warning No native natural comparisons supported.
+ return x.CompareTo(y);
+#else
+ return StrCmpLogicalW(x, y);
+#endif
+ }
+ }
+}
diff --git a/ModernKeePassLib/Properties/AssemblyInfo.cs b/ModernKeePassLib/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0b2c71f
--- /dev/null
+++ b/ModernKeePassLib/Properties/AssemblyInfo.cs
@@ -0,0 +1,43 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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("Portable KeePass Password Management Library")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Geoffroy Bonneville")]
+[assembly: AssemblyProduct("ModernKeePassLib")]
+[assembly: AssemblyCopyright("Copyright © 2017 Geoffroy Bonneville")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// COM settings
+[assembly: ComVisible(false)]
+
+// Assembly GUID
+//Bert TODO: Disabled Guid
+//[assembly: Guid("395f6eec-a1e0-4438-aa82-b75099348134")]
+
+// Assembly version information
+[assembly: AssemblyVersion("2.19.0.*")]
+[assembly: AssemblyFileVersion("2.19.0.0")]
diff --git a/ModernKeePassLib/Properties/AssemblyInfo.cs.bak b/ModernKeePassLib/Properties/AssemblyInfo.cs.bak
new file mode 100644
index 0000000..fa77aab
--- /dev/null
+++ b/ModernKeePassLib/Properties/AssemblyInfo.cs.bak
@@ -0,0 +1,42 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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("KeePassLib")]
+[assembly: AssemblyDescription("KeePass Password Management Library")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Dominik Reichl")]
+[assembly: AssemblyProduct("KeePassLib")]
+[assembly: AssemblyCopyright("Copyright © 2003-2012 Dominik Reichl")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// COM settings
+[assembly: ComVisible(false)]
+
+// Assembly GUID
+[assembly: Guid("395f6eec-a1e0-4438-aa82-b75099348134")]
+
+// Assembly version information
+[assembly: AssemblyVersion("2.19.0.*")]
+[assembly: AssemblyFileVersion("2.19.0.0")]
diff --git a/ModernKeePassLib/PwCustomIcon.cs b/ModernKeePassLib/PwCustomIcon.cs
new file mode 100644
index 0000000..397b186
--- /dev/null
+++ b/ModernKeePassLib/PwCustomIcon.cs
@@ -0,0 +1,73 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.Drawing;
+using Windows.UI.Xaml.Media.Imaging;
+
+// Bert TODO: http://blog.tallcomponents.com/2012/06/windows-8-release-preview-back-to-earth.html
+namespace ModernKeePassLib
+{
+ ///
+ /// Custom icon. PwCustomIcon objects are immutable.
+ ///
+ public sealed class PwCustomIcon
+ {
+ private PwUuid m_pwUuid;
+ private byte[] m_pbImageDataPng;
+ private BitmapImage m_pCachedImage;
+
+ public PwUuid Uuid
+ {
+ get { return m_pwUuid; }
+ }
+
+ public byte[] ImageDataPng
+ {
+ get { return m_pbImageDataPng; }
+ }
+
+ public BitmapImage Image
+ {
+ get { return m_pCachedImage; }
+ }
+
+ public PwCustomIcon(PwUuid pwUuid, byte[] pbImageDataPng)
+ {
+ Debug.Assert(pwUuid != null);
+ if(pwUuid == null) throw new ArgumentNullException("pwUuid");
+ Debug.Assert(pwUuid != PwUuid.Zero);
+ if(pwUuid == PwUuid.Zero) throw new ArgumentException("pwUuid == 0");
+
+ Debug.Assert(pbImageDataPng != null);
+ if(pbImageDataPng == null) throw new ArgumentNullException("pbImageDataPng");
+
+ m_pwUuid = pwUuid;
+ m_pbImageDataPng = pbImageDataPng;
+
+#if !KeePassLibSD && false
+ MemoryStream ms = new MemoryStream(m_pbImageDataPng, false);
+ m_pCachedImage = Image.FromStream(ms);
+ ms.Close();
+#else
+ m_pCachedImage = null;
+#endif
+ }
+ }
+}
diff --git a/ModernKeePassLib/PwDatabase.cs b/ModernKeePassLib/PwDatabase.cs
new file mode 100644
index 0000000..b5429f6
--- /dev/null
+++ b/ModernKeePassLib/PwDatabase.cs
@@ -0,0 +1,1770 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.Drawing;
+
+using ModernKeePassLib.WinRTAdaptors;
+using ModernKeePassLib.Collections;
+using ModernKeePassLib.Cryptography.Cipher;
+using ModernKeePassLib.Delegates;
+using ModernKeePassLib.Interfaces;
+using ModernKeePassLib.Keys;
+using ModernKeePassLib.Serialization;
+using ModernKeePassLib.Utility;
+using Windows.UI.Xaml.Media.Imaging;
+using System.Threading.Tasks;
+
+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 CompositeKey m_pwUserKey = null;
+ private MemoryProtectionConfig m_memProtConfig = new MemoryProtectionConfig();
+
+ private List m_vCustomIcons = new List();
+ private bool m_bUINeedsIconUpdate = true;
+
+ 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 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_vCustomData = new StringDictionaryEx();
+
+ 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;
+ }
+ }
+
+ ///
+ /// 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; }
+ }
+
+ ///
+ /// 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 (in order to make dictionary
+ /// attacks harder).
+ ///
+ public ulong KeyEncryptionRounds
+ {
+ get { return m_uKeyEncryptionRounds; }
+ set { m_uKeyEncryptionRounds = 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.
+ ///
+ public StringDictionaryEx CustomData
+ {
+ get { return m_vCustomData; }
+ set
+ {
+ Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
+ m_vCustomData = 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_pwUserKey = null;
+ m_memProtConfig = new MemoryProtectionConfig();
+
+ m_vCustomIcons = new List();
+ m_bUINeedsIconUpdate = true;
+
+ DateTime dtNow = DateTime.Now;
+
+ 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_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_vCustomData = new StringDictionaryEx();
+
+ 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 async Task 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;
+
+ Kdb4File kdb4 = new Kdb4File(this);
+ kdb4.DetachBinaries = m_strDetachBins;
+
+ IOConnection ioc = new IOConnection();
+ Stream s = await ioc.OpenRead(ioSource);
+ await kdb4.Load(s, Kdb4Format.Default, slLogger);
+
+ s.Dispose();
+
+ m_pbHashOfLastIO = kdb4.HashOfFileOnDisk;
+ m_pbHashOfFileOnDisk = kdb4.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(ValidateUuidUniqueness());
+
+ FileLock fl = null;
+ if(m_bUseFileLocks) fl = new FileLock(m_ioSource);
+ try
+ {
+ FileTransactionEx ft = new FileTransactionEx(m_ioSource,
+ m_bUseFileTransactions);
+ Stream s = ft.OpenWrite();
+
+ Kdb4File kdb = new Kdb4File(this);
+ kdb.Save(s, null, Kdb4Format.Default, slLogger);
+
+ ft.CommitWrite();
+
+ m_pbHashOfLastIO = kdb.HashOfFileOnDisk;
+ m_pbHashOfFileOnDisk = kdb.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 pwSource, PwMergeMethod mm)
+ {
+ MergeIn(pwSource, mm, null);
+ }
+
+ ///
+ /// Synchronize the current database with another one.
+ ///
+ /// Input database to synchronize with. This input
+ /// database is used to update the current one, but is not modified! You
+ /// must copy the current object if you want a second instance of the
+ /// synchronized database. The input database must not be seen as valid
+ /// database any more after calling Synchronize.
+ /// Merge method.
+ /// Logger to report status messages to.
+ /// May be null.
+ public void MergeIn(PwDatabase pwSource, PwMergeMethod mm,
+ IStatusLogger slStatus)
+ {
+ if(pwSource == null) throw new ArgumentNullException("pwSource");
+
+ PwGroup pgOrgStructure = m_pgRootGroup.CloneStructure();
+ PwGroup pgSrcStructure = pwSource.m_pgRootGroup.CloneStructure();
+
+ if(mm == PwMergeMethod.CreateNewUuids)
+ pwSource.RootGroup.CreateNewItemUuids(true, true, true);
+
+ GroupHandler gh = delegate(PwGroup pg)
+ {
+ if(pg == pwSource.m_pgRootGroup) return true;
+
+ PwGroup pgLocal = m_pgRootGroup.FindGroup(pg.Uuid, true);
+ if(pgLocal == null)
+ {
+ PwGroup pgSourceParent = pg.ParentGroup;
+ PwGroup pgLocalContainer;
+ if(pgSourceParent == pwSource.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);
+ }
+ 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 eh = delegate(PwEntry pe)
+ {
+ PwEntry peLocal = m_pgRootGroup.FindEntry(pe.Uuid, true);
+ if(peLocal == null)
+ {
+ PwGroup pgSourceParent = pe.ParentGroup;
+ PwGroup pgLocalContainer;
+ if(pgSourceParent == pwSource.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);
+ }
+ 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 &= (pe.LastModificationTime > peLocal.LastModificationTime);
+ bOrgBackup &= !pe.HasBackupOfData(peLocal, false, true);
+ if(bOrgBackup) peLocal.CreateBackup(null); // Maintain at end
+
+ bool bSrcBackup = !bEquals && (mm != PwMergeMethod.OverwriteExisting);
+ bSrcBackup &= (peLocal.LastModificationTime > pe.LastModificationTime);
+ 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);
+ };
+
+ if(!pwSource.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh))
+ throw new InvalidOperationException();
+
+ IStatusLogger slPrevStatus = m_slStatus;
+ m_slStatus = slStatus;
+
+ if(mm == PwMergeMethod.Synchronize)
+ {
+ ApplyDeletions(pwSource.m_vDeletedObjects, true);
+ ApplyDeletions(m_vDeletedObjects, false);
+
+ PwObjectPool ppOrgGroups = PwObjectPool.FromGroupRecursive(
+ pgOrgStructure, false);
+ PwObjectPool ppSrcGroups = PwObjectPool.FromGroupRecursive(
+ pgSrcStructure, false);
+ PwObjectPool ppOrgEntries = PwObjectPool.FromGroupRecursive(
+ pgOrgStructure, true);
+ PwObjectPool ppSrcEntries = PwObjectPool.FromGroupRecursive(
+ pgSrcStructure, true);
+
+ RelocateGroups(ppOrgGroups, ppSrcGroups);
+ ReorderGroups(ppOrgGroups, ppSrcGroups);
+ RelocateEntries(ppOrgEntries, ppSrcEntries);
+ ReorderEntries(ppOrgEntries, ppSrcEntries);
+ Debug.Assert(ValidateUuidUniqueness());
+ }
+
+ // Must be called *after* merging groups, because group UUIDs
+ // are required for recycle bin and entry template UUIDs
+ MergeInDbProperties(pwSource, mm);
+
+ MergeInCustomIcons(pwSource);
+
+ MaintainBackups();
+
+ m_slStatus = slPrevStatus;
+ }
+
+ private void MergeInCustomIcons(PwDatabase pwSource)
+ {
+ foreach(PwCustomIcon pwci in pwSource.CustomIcons)
+ {
+ if(GetCustomIconIndex(pwci.Uuid) >= 0) continue;
+
+ m_vCustomIcons.Add(pwci); // PwCustomIcon is immutable
+ m_bUINeedsIconUpdate = true;
+ }
+ }
+
+ ///
+ /// Apply a list of deleted objects.
+ ///
+ /// List of deleted objects.
+ private void ApplyDeletions(PwObjectList listDelObjects,
+ bool bCopyDeletionInfoToLocal)
+ {
+ Debug.Assert(listDelObjects != null); if(listDelObjects == null) throw new ArgumentNullException("listDelObjects");
+
+ LinkedList listGroupsToDelete = new LinkedList();
+ LinkedList listEntriesToDelete = new LinkedList();
+
+ GroupHandler gh = delegate(PwGroup pg)
+ {
+ if(pg == m_pgRootGroup) return true;
+
+ foreach(PwDeletedObject pdo in listDelObjects)
+ {
+ if(pg.Uuid.EqualsValue(pdo.Uuid))
+ if(pg.LastModificationTime < pdo.DeletionTime)
+ listGroupsToDelete.AddLast(pg);
+ }
+
+ return ((m_slStatus != null) ? m_slStatus.ContinueWork() : true);
+ };
+
+ EntryHandler eh = delegate(PwEntry pe)
+ {
+ foreach(PwDeletedObject pdo in listDelObjects)
+ {
+ if(pe.Uuid.EqualsValue(pdo.Uuid))
+ if(pe.LastModificationTime < pdo.DeletionTime)
+ listEntriesToDelete.AddLast(pe);
+ }
+
+ return ((m_slStatus != null) ? m_slStatus.ContinueWork() : true);
+ };
+
+ m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh);
+
+ foreach(PwGroup pg in listGroupsToDelete)
+ pg.ParentGroup.Groups.Remove(pg);
+ foreach(PwEntry pe in listEntriesToDelete)
+ pe.ParentGroup.Entries.Remove(pe);
+
+ if(bCopyDeletionInfoToLocal)
+ {
+ foreach(PwDeletedObject pdoNew in listDelObjects)
+ {
+ bool bCopy = true;
+
+ foreach(PwDeletedObject pdoLocal in m_vDeletedObjects)
+ {
+ if(pdoNew.Uuid.EqualsValue(pdoLocal.Uuid))
+ {
+ bCopy = false;
+
+ if(pdoNew.DeletionTime > pdoLocal.DeletionTime)
+ pdoLocal.DeletionTime = pdoNew.DeletionTime;
+
+ break;
+ }
+ }
+
+ if(bCopy) m_vDeletedObjects.Add(pdoNew);
+ }
+ }
+ }
+
+ private void RelocateGroups(PwObjectPool ppOrgStructure,
+ PwObjectPool ppSrcStructure)
+ {
+ 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 = ppOrgStructure.Get(pg.Uuid);
+ if(ptOrg == null) continue;
+ // PwGroup pgSrc = pgSrcStructure.FindGroup(pg.Uuid, true);
+ IStructureItem ptSrc = ppSrcStructure.Get(pg.Uuid);
+ if(ptSrc == null) continue;
+
+ PwGroup pgOrgParent = ptOrg.ParentGroup;
+ PwGroup pgSrcParent = ptSrc.ParentGroup;
+ if(pgOrgParent.Uuid.EqualsValue(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);
+ pg.LocationChanged = ptSrc.LocationChanged;
+ }
+ else
+ {
+ Debug.Assert(pg.ParentGroup.Uuid.EqualsValue(pgOrgParent.Uuid));
+ Debug.Assert(pg.LocationChanged == ptOrg.LocationChanged);
+ }
+ }
+
+ Debug.Assert(m_pgRootGroup.GetGroups(true).UCount == vGroups.UCount);
+ }
+
+ private void RelocateEntries(PwObjectPool ppOrgStructure,
+ PwObjectPool ppSrcStructure)
+ {
+ 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 = ppOrgStructure.Get(pe.Uuid);
+ if(ptOrg == null) continue;
+ // PwEntry peSrc = pgSrcStructure.FindEntry(pe.Uuid, true);
+ IStructureItem ptSrc = ppSrcStructure.Get(pe.Uuid);
+ if(ptSrc == null) continue;
+
+ PwGroup pgOrg = ptOrg.ParentGroup;
+ PwGroup pgSrc = ptSrc.ParentGroup;
+ if(pgOrg.Uuid.EqualsValue(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);
+ pe.LocationChanged = ptSrc.LocationChanged;
+ }
+ else
+ {
+ Debug.Assert(pe.ParentGroup.Uuid.EqualsValue(pgOrg.Uuid));
+ Debug.Assert(pe.LocationChanged == ptOrg.LocationChanged);
+ }
+ }
+
+ Debug.Assert(m_pgRootGroup.GetEntries(true).UCount == vEntries.UCount);
+ }
+
+ private void ReorderGroups(PwObjectPool ppOrgStructure,
+ PwObjectPool ppSrcStructure)
+ {
+ GroupHandler gh = delegate(PwGroup pg)
+ {
+ ReorderObjectList(pg.Groups, ppOrgStructure,
+ ppSrcStructure, false);
+ return true;
+ };
+
+ ReorderObjectList(m_pgRootGroup.Groups, ppOrgStructure,
+ ppSrcStructure, false);
+ m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, null);
+ }
+
+ private void ReorderEntries(PwObjectPool ppOrgStructure,
+ PwObjectPool ppSrcStructure)
+ {
+ GroupHandler gh = delegate(PwGroup pg)
+ {
+ ReorderObjectList(pg.Entries, ppOrgStructure,
+ ppSrcStructure, true);
+ return true;
+ };
+
+ ReorderObjectList(m_pgRootGroup.Entries, ppOrgStructure,
+ ppSrcStructure, true);
+ m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, null);
+ }
+
+ private void ReorderObjectList(PwObjectList vItems,
+ PwObjectPool ppOrgStructure, PwObjectPool ppSrcStructure, bool bEntries)
+ where T : class, IStructureItem, IDeepCloneable
+ {
+ if(!ObjectListRequiresReorder(vItems, ppOrgStructure, ppSrcStructure,
+ bEntries)) return;
+
+#if DEBUG
+ PwObjectList vOrgListItems = vItems.CloneShallow();
+#endif
+
+ Queue> qToDo = new Queue>();
+ qToDo.Enqueue(new KeyValuePair(0, vItems.UCount - 1));
+
+ while(qToDo.Count > 0)
+ {
+ if((m_slStatus != null) && !m_slStatus.ContinueWork()) break;
+
+ KeyValuePair kvp = qToDo.Dequeue();
+ if(kvp.Value <= kvp.Key) { Debug.Assert(false); continue; }
+
+ Queue qRelBefore = new Queue();
+ Queue qRelAfter = new Queue();
+ uint uPivot = FindLocationChangedPivot(vItems, kvp, ppOrgStructure,
+ ppSrcStructure, qRelBefore, qRelAfter, bEntries);
+ T ptPivot = vItems.GetAt(uPivot);
+
+ List vToSort = vItems.GetRange(kvp.Key, kvp.Value);
+ Queue qBefore = new Queue();
+ Queue qAfter = new Queue();
+ bool bBefore = true;
+
+ foreach(T pt in vToSort)
+ {
+ if(pt == ptPivot) { bBefore = false; continue; }
+
+ bool bAdded = false;
+ foreach(PwUuid puBefore in qRelBefore)
+ {
+ if(puBefore.EqualsValue(pt.Uuid))
+ {
+ qBefore.Enqueue(pt);
+ bAdded = true;
+ break;
+ }
+ }
+ if(bAdded) continue;
+
+ foreach(PwUuid puAfter in qRelAfter)
+ {
+ if(puAfter.EqualsValue(pt.Uuid))
+ {
+ qAfter.Enqueue(pt);
+ bAdded = true;
+ break;
+ }
+ }
+ if(bAdded) continue;
+
+ if(bBefore) qBefore.Enqueue(pt);
+ else qAfter.Enqueue(pt);
+ }
+ Debug.Assert(bBefore == false);
+
+ uint uPos = kvp.Key;
+ while(qBefore.Count > 0) vItems.SetAt(uPos++, qBefore.Dequeue());
+ vItems.SetAt(uPos++, ptPivot);
+ while(qAfter.Count > 0) vItems.SetAt(uPos++, qAfter.Dequeue());
+ Debug.Assert(uPos == (kvp.Value + 1));
+
+ int iNewPivot = vItems.IndexOf(ptPivot);
+ if((iNewPivot < (int)kvp.Key) || (iNewPivot > (int)kvp.Value))
+ {
+ Debug.Assert(false);
+ continue;
+ }
+
+ if((iNewPivot - 1) > (int)kvp.Key)
+ qToDo.Enqueue(new KeyValuePair(kvp.Key,
+ (uint)(iNewPivot - 1)));
+
+ if((iNewPivot + 1) < (int)kvp.Value)
+ qToDo.Enqueue(new KeyValuePair((uint)(iNewPivot + 1),
+ kvp.Value));
+ }
+
+#if DEBUG
+ foreach(T ptItem in vOrgListItems)
+ {
+ Debug.Assert(vItems.IndexOf(ptItem) >= 0);
+ }
+#endif
+ }
+
+ private static uint FindLocationChangedPivot(PwObjectList vItems,
+ KeyValuePair kvpRange, PwObjectPool ppOrgStructure,
+ PwObjectPool ppSrcStructure, Queue qBefore, Queue qAfter,
+ bool bEntries)
+ where T : class, IStructureItem, IDeepCloneable
+ {
+ uint uPosMax = kvpRange.Key;
+ DateTime dtMax = DateTime.MinValue;
+ List vNeighborSrc = null;
+
+ for(uint u = kvpRange.Key; u <= kvpRange.Value; ++u)
+ {
+ T pt = vItems.GetAt(u);
+
+ // IStructureItem ptOrg = pgOrgStructure.FindObject(pt.Uuid, true, bEntries);
+ IStructureItem ptOrg = ppOrgStructure.Get(pt.Uuid);
+ if((ptOrg != null) && (ptOrg.LocationChanged > dtMax))
+ {
+ uPosMax = u;
+ dtMax = ptOrg.LocationChanged; // No 'continue'
+ vNeighborSrc = ptOrg.ParentGroup.GetObjects(false, bEntries);
+ }
+
+ // IStructureItem ptSrc = pgSrcStructure.FindObject(pt.Uuid, true, bEntries);
+ IStructureItem ptSrc = ppSrcStructure.Get(pt.Uuid);
+ if((ptSrc != null) && (ptSrc.LocationChanged > dtMax))
+ {
+ uPosMax = u;
+ dtMax = ptSrc.LocationChanged; // No 'continue'
+ vNeighborSrc = ptSrc.ParentGroup.GetObjects(false, bEntries);
+ }
+ }
+
+ GetNeighborItems(vNeighborSrc, vItems.GetAt(uPosMax).Uuid, qBefore, qAfter);
+ return uPosMax;
+ }
+
+ private static void GetNeighborItems(List vItems,
+ PwUuid pwPivot, Queue qBefore, Queue qAfter)
+ {
+ qBefore.Clear();
+ qAfter.Clear();
+
+ // Checks after clearing the queues
+ if(vItems == null) { Debug.Assert(false); return; } // No throw
+
+ bool bBefore = true;
+ for(int i = 0; i < vItems.Count; ++i)
+ {
+ PwUuid pw = vItems[i].Uuid;
+
+ if(pw.EqualsValue(pwPivot)) bBefore = false;
+ else if(bBefore) qBefore.Enqueue(pw);
+ else qAfter.Enqueue(pw);
+ }
+ Debug.Assert(bBefore == false);
+ }
+
+ ///
+ /// Method to check whether a reordering is required. This fast test
+ /// allows to skip the reordering routine, resulting in a large
+ /// performance increase.
+ ///
+ private bool ObjectListRequiresReorder(PwObjectList vItems,
+ PwObjectPool ppOrgStructure, PwObjectPool ppSrcStructure, bool bEntries)
+ where T : class, IStructureItem, IDeepCloneable
+ {
+ Debug.Assert(ppOrgStructure.ContainsOnlyType(bEntries ? typeof(PwEntry) : typeof(PwGroup)));
+ Debug.Assert(ppSrcStructure.ContainsOnlyType(bEntries ? typeof(PwEntry) : typeof(PwGroup)));
+ if(vItems.UCount <= 1) return false;
+
+ if((m_slStatus != null) && !m_slStatus.ContinueWork()) return false;
+
+ T ptFirst = vItems.GetAt(0);
+ // IStructureItem ptOrg = pgOrgStructure.FindObject(ptFirst.Uuid, true, bEntries);
+ IStructureItem ptOrg = ppOrgStructure.Get(ptFirst.Uuid);
+ if(ptOrg == null) return true;
+ // IStructureItem ptSrc = pgSrcStructure.FindObject(ptFirst.Uuid, true, bEntries);
+ IStructureItem ptSrc = ppSrcStructure.Get(ptFirst.Uuid);
+ if(ptSrc == null) return true;
+
+ if(ptFirst.ParentGroup == null) { Debug.Assert(false); return true; }
+ PwGroup pgOrgParent = ptOrg.ParentGroup;
+ if(pgOrgParent == null) return true; // Root might be in tree
+ PwGroup pgSrcParent = ptSrc.ParentGroup;
+ if(pgSrcParent == null) return true; // Root might be in tree
+
+ if(!ptFirst.ParentGroup.Uuid.EqualsValue(pgOrgParent.Uuid)) return true;
+ if(!pgOrgParent.Uuid.EqualsValue(pgSrcParent.Uuid)) return true;
+
+ List lOrg = pgOrgParent.GetObjects(false, bEntries);
+ List lSrc = pgSrcParent.GetObjects(false, bEntries);
+ if(vItems.UCount != (uint)lOrg.Count) return true;
+ if(lOrg.Count != lSrc.Count) return true;
+
+ for(uint u = 0; u < vItems.UCount; ++u)
+ {
+ IStructureItem pt = vItems.GetAt(u);
+ Debug.Assert(pt.ParentGroup == ptFirst.ParentGroup);
+
+ if(!pt.Uuid.EqualsValue(lOrg[(int)u].Uuid)) return true;
+ if(!pt.Uuid.EqualsValue(lSrc[(int)u].Uuid)) return true;
+ if(pt.LocationChanged != lOrg[(int)u].LocationChanged) return true;
+ if(pt.LocationChanged != lSrc[(int)u].LocationChanged) return true;
+ }
+
+ return false;
+ }
+
+ private void MergeInDbProperties(PwDatabase pwSource, PwMergeMethod mm)
+ {
+ if(pwSource == null) { Debug.Assert(false); return; }
+ if((mm == PwMergeMethod.KeepExisting) || (mm == PwMergeMethod.None))
+ return;
+
+ bool bForce = (mm == PwMergeMethod.OverwriteExisting);
+
+ if(bForce || (pwSource.m_dtNameChanged > m_dtNameChanged))
+ {
+ m_strName = pwSource.m_strName;
+ m_dtNameChanged = pwSource.m_dtNameChanged;
+ }
+
+ if(bForce || (pwSource.m_dtDescChanged > m_dtDescChanged))
+ {
+ m_strDesc = pwSource.m_strDesc;
+ m_dtDescChanged = pwSource.m_dtDescChanged;
+ }
+
+ if(bForce || (pwSource.m_dtDefaultUserChanged > m_dtDefaultUserChanged))
+ {
+ m_strDefaultUserName = pwSource.m_strDefaultUserName;
+ m_dtDefaultUserChanged = pwSource.m_dtDefaultUserChanged;
+ }
+
+ if(bForce) m_clr = pwSource.m_clr;
+
+ PwUuid pwPrefBin = m_pwRecycleBin, pwAltBin = pwSource.m_pwRecycleBin;
+ if(bForce || (pwSource.m_dtRecycleBinChanged > m_dtRecycleBinChanged))
+ {
+ pwPrefBin = pwSource.m_pwRecycleBin;
+ pwAltBin = m_pwRecycleBin;
+ m_bUseRecycleBin = pwSource.m_bUseRecycleBin;
+ m_dtRecycleBinChanged = pwSource.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 = pwSource.m_pwEntryTemplatesGroup;
+ if(bForce || (pwSource.m_dtEntryTemplatesChanged > m_dtEntryTemplatesChanged))
+ {
+ pwPrefTmp = pwSource.m_pwEntryTemplatesGroup;
+ pwAltTmp = m_pwEntryTemplatesGroup;
+ m_dtEntryTemplatesChanged = pwSource.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);
+ }
+
+ private void MergeEntryHistory(PwEntry pe, PwEntry peSource,
+ PwMergeMethod mm)
+ {
+ Debug.Assert(false, "not yet implemented");
+ return ;
+#if TODO
+ if(!pe.Uuid.EqualsValue(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;
+
+ SortedList list = new SortedList();
+ foreach(PwEntry peOrg in pe.History)
+ {
+ list[peOrg.LastModificationTime] = peOrg;
+ }
+
+ foreach(PwEntry peSrc in peSource.History)
+ {
+ DateTime dt = peSrc.LastModificationTime;
+ if(list.ContainsKey(dt))
+ {
+ if(mm == PwMergeMethod.OverwriteExisting)
+ list[dt] = peSrc.CloneDeep();
+ }
+ else list[dt] = peSrc.CloneDeep();
+ }
+
+ pe.History.Clear();
+ foreach(KeyValuePair kvpCur in list)
+ {
+ Debug.Assert(kvpCur.Value.Uuid.EqualsValue(pe.Uuid));
+ Debug.Assert(kvpCur.Value.History.UCount == 0);
+ pe.History.Add(kvpCur.Value);
+ }
+#endif
+ }
+
+ 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 pwSource = new PwDatabase();
+
+ IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile);
+ pwSource.Open(ioc, m_pwUserKey, null);
+
+ MergeIn(pwSource, PwMergeMethod.Synchronize);
+ } */
+
+ ///
+ /// Get the index of a custom icon.
+ ///
+ /// ID of the icon.
+ /// Index of the icon.
+ public int GetCustomIconIndex(PwUuid pwIconId)
+ {
+ int nIndex = 0;
+
+ foreach(PwCustomIcon pwci in m_vCustomIcons)
+ {
+ if(pwci.Uuid.EqualsValue(pwIconId))
+ return nIndex;
+
+ ++nIndex;
+ }
+
+ // Debug.Assert(false); // Do not assert
+ return -1;
+ }
+
+ ///
+ /// Get a custom icon. This function can return null, if
+ /// no cached image of the icon is available.
+ ///
+ /// ID of the icon.
+ /// Image data.
+ public BitmapImage GetCustomIcon(PwUuid pwIconId)
+ {
+ int nIndex = GetCustomIconIndex(pwIconId);
+
+ if(nIndex >= 0) return m_vCustomIcons[nIndex].Image;
+ else { Debug.Assert(false); return null; }
+ }
+
+ 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.EqualsValue(PwUuid.Zero)) return true;
+
+ foreach(PwUuid uuidDelete in vUuidsToDelete)
+ {
+ if(uuidThis.EqualsValue(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.EqualsValue(PwUuid.Zero)) return;
+
+ foreach(PwUuid uuidDelete in vToDelete)
+ {
+ if(uuidThis.EqualsValue(uuidDelete))
+ {
+ pe.CustomIconUuid = PwUuid.Zero;
+ break;
+ }
+ }
+
+ foreach(PwEntry peHistory in pe.History)
+ RemoveCustomIconUuid(peHistory, vToDelete);
+ }
+
+ private bool ValidateUuidUniqueness()
+ {
+#if DEBUG
+ List l = new List();
+ bool bAllUnique = true;
+
+ GroupHandler gh = delegate(PwGroup pg)
+ {
+ foreach(PwUuid u in l)
+ bAllUnique &= !pg.Uuid.EqualsValue(u);
+ l.Add(pg.Uuid);
+ return bAllUnique;
+ };
+
+ EntryHandler eh = delegate(PwEntry pe)
+ {
+ foreach(PwUuid u in l)
+ bAllUnique &= !pe.Uuid.EqualsValue(u);
+ l.Add(pe.Uuid);
+ return bAllUnique;
+ };
+
+ m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh);
+ return bAllUnique;
+#else
+ return true;
+#endif
+ }
+
+ /* 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);
+ sOut.Close();
+ }
+
+ sIn.Close();
+ }
+ }
+
+ 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.Now;
+ 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 = (peA.LastModificationTime <= peB.LastModificationTime);
+ 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)
+ {
+
+ Debug.Assert(false, "not yet implemented");
+ return true;
+#if TODO
+ 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(!kvpA.Value.ReadString().Equals(psB.ReadString())) 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(kvpB.Value.ReadString().Equals(psA.ReadString()));
+ }
+
+ if(a.Binaries.UCount != b.Binaries.UCount) return false;
+ foreach(KeyValuePair kvpBin in a.Binaries)
+ {
+ ProtectedBinary pbB = b.Binaries.Get(kvpBin.Key);
+ if(pbB == null) return false;
+
+ // Ignore protection setting, compare values only
+ byte[] pbDataA = kvpBin.Value.ReadData();
+ byte[] pbDataB = pbB.ReadData();
+ bool bBinEq = MemUtil.ArraysEqual(pbDataA, pbDataB);
+ MemUtil.ZeroByteArray(pbDataA);
+ MemUtil.ZeroByteArray(pbDataB);
+ if(!bBinEq) return false;
+ }
+
+ return true;
+#endif
+ }
+
+ 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.Now));
+
+ ++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.EqualsValue(PwUuid.Zero)) return true;
+
+ for(int i = 0; i < lToDelete.Count; ++i)
+ {
+ if(lToDelete[i].EqualsValue(pwUuid))
+ {
+ lToDelete.RemoveAt(i);
+ break;
+ }
+ }
+
+ return true;
+ };
+
+ EntryHandler eh = delegate(PwEntry pe)
+ {
+ PwUuid pwUuid = pe.CustomIconUuid;
+ if((pwUuid == null) || pwUuid.EqualsValue(PwUuid.Zero)) return true;
+
+ for(int i = 0; i < lToDelete.Count; ++i)
+ {
+ if(lToDelete[i].EqualsValue(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
new file mode 100644
index 0000000..caffb94
--- /dev/null
+++ b/ModernKeePassLib/PwDefs.cs
@@ -0,0 +1,461 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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.Serialization;
+using System.ComponentModel;
+using System.Diagnostics;
+
+using ModernKeePassLib.Delegates;
+using ModernKeePassLib.Interfaces;
+
+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";
+
+ ///
+ /// 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 = 0x02130000;
+
+ ///
+ /// Version, encoded as 64-bit unsigned integer
+ /// (component-wise, 16 bits per component).
+ ///
+ public const ulong FileVersion64 = 0x0002001300000000UL;
+
+ ///
+ /// Version, encoded as string.
+ ///
+ public const string VersionString = "2.19";
+
+ public const string Copyright = @"Copyright 2003-2012 Dominik Reichl";
+
+ ///
+ /// Product website URL. Terminated by a forward slash.
+ ///
+ public const string HomepageUrl = "http://keepass.info/";
+
+ ///
+ /// Product donations URL.
+ ///
+ public const string DonationsUrl = "http://keepass.info/donate.html";
+
+ ///
+ /// URL to the online plugins page.
+ ///
+ public const string PluginsUrl = "http://keepass.info/plugins.html";
+
+ ///
+ /// URL to the online translations page.
+ ///
+ public const string TranslationsUrl = "http://keepass.info/translations.html";
+
+ ///
+ /// URL to a TXT file (eventually compressed) that contains information
+ /// about the latest KeePass version available on the website.
+ ///
+ public const string VersionUrl = "http://keepass.info/update/version2x.txt.gz";
+
+ ///
+ /// URL to the root path of the online KeePass help. Terminated by
+ /// a forward slash.
+ ///
+ public const string HelpUrl = "http://keepass.info/help/";
+
+ ///
+ /// A DateTime object that represents the time when the assembly
+ /// was loaded.
+ ///
+ public static readonly DateTime DtDefaultNow = DateTime.Now;
+
+ ///
+ /// Default number of master key encryption/transformation rounds (making dictionary attacks harder).
+ ///
+ public const ulong DefaultKeyEncryptionRounds = 6000;
+
+ ///
+ /// 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);
+ }
+ }
+
+ #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_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; }
+ }
+
+ private bool m_bSearchInTags = true;
+ [DefaultValue(true)]
+ public bool SearchInTags
+ {
+ get { return m_bSearchInTags; }
+ set { m_bSearchInTags = value; }
+ }
+
+
+ //Bert TODO: Check if using CurrentCultureIgnoreCase makes sense.
+ private StringComparison m_scType = StringComparison.CurrentCultureIgnoreCase;
+ //private StringComparison m_scType = StringComparison.InvariantCultureIgnoreCase;
+ ///
+ /// 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();
+
+ // sp.m_strText = string.Empty;
+ // sp.m_bRegex = false;
+ sp.m_bSearchInTitles = false;
+ sp.m_bSearchInUserNames = false;
+ // sp.m_bSearchInPasswords = false;
+ sp.m_bSearchInUrls = false;
+ sp.m_bSearchInNotes = false;
+ sp.m_bSearchInOther = false;
+ // sp.m_bSearchInUuids = false;
+ // sp.SearchInGroupNames = false;
+ sp.m_bSearchInTags = false;
+ // sp.m_scType = StringComparison.InvariantCultureIgnoreCase;
+ // sp.m_bExcludeExpired = false;
+ // m_bRespectEntrySearchingDisabled = true;
+
+ 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;
+ }
+ }
+}
diff --git a/ModernKeePassLib/PwDeletedObject.cs b/ModernKeePassLib/PwDeletedObject.cs
new file mode 100644
index 0000000..2b0b609
--- /dev/null
+++ b/ModernKeePassLib/PwDeletedObject.cs
@@ -0,0 +1,86 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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
new file mode 100644
index 0000000..e7df340
--- /dev/null
+++ b/ModernKeePassLib/PwEntry.cs
@@ -0,0 +1,881 @@
+/*
+ KeePass Password Safe - The Open-Source Password Manager
+ Copyright (C) 2003-2012 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 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 WinRTAdaptors.Color m_clrForeground = WinRTAdaptors.Color.Empty;
+ private WinRTAdaptors.Color m_clrBackground = WinRTAdaptors.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();
+
+ ///
+ /// 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 WinRTAdaptors.Color ForegroundColor
+ {
+ get { return m_clrForeground; }
+ set { m_clrForeground = value; }
+ }
+
+ ///
+ /// Get or set the background color of this entry.
+ ///
+ public WinRTAdaptors.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 accessed (read).
+ ///
+ public DateTime LastAccessTime
+ {
+ get { return m_tLastAccess; }
+ set { m_tLastAccess = 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 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;
+ }
+ }
+
+ 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)
+ {
+ m_tCreation = m_tLastMod = m_tLastAccess =
+ m_tParentGroupLastMod = DateTime.Now;
+ }
+ }
+
+ ///
+ /// 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)
+ {
+ m_tCreation = m_tLastMod = m_tLastAccess =
+ m_tParentGroupLastMod = DateTime.Now;
+ }
+ }
+
+ ///
+ /// 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);
+
+ 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)
+ {
+ Debug.Assert(false, "not yet implemented");
+ return false;
+#if TODO
+
+ 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.EqualsValue(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.EqualsValue(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;
+ }
+
+ return true;
+#endif
+ }
+
+ ///
+ /// 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)
+ {
+ Debug.Assert(peTemplate != null); if(peTemplate == null) throw new ArgumentNullException("peTemplate");
+
+ if(bOnlyIfNewer && (peTemplate.m_tLastMod < m_tLastMod)) return;
+
+ // Template UUID should be the same as the current one
+ Debug.Assert(m_uuid.EqualsValue(peTemplate.m_uuid));
+ m_uuid = peTemplate.m_uuid;
+
+ if(bAssignLocationChanged)
+ m_tParentGroupLastMod = peTemplate.m_tParentGroupLastMod;
+
+ m_listStrings = peTemplate.m_listStrings;
+ m_listBinaries = peTemplate.m_listBinaries;
+ m_listAutoType = peTemplate.m_listAutoType;
+ if(bIncludeHistory) m_listHistory = peTemplate.m_listHistory;
+
+ 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);
+ }
+
+ ///
+ /// Touch the entry. This function updates the internal last access
+ /// time. If the