diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ecdf0f19..ea60139b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,7 +78,7 @@ jobs: # - name: Build keepass2android (net) # run: | - # make msbuild Flavor=Net + # make dotnetbuild Flavor=Net # - name: Build APK (net) # run: | @@ -96,7 +96,7 @@ jobs: # - name: Build keepass2android (nonet) # run: | - # make msbuild Flavor=NoNet + # make dotnetbuild Flavor=NoNet # - name: Build APK (nonet) # run: | @@ -212,7 +212,7 @@ jobs: # - name: Build keepass2android (net) # run: | - # make msbuild Flavor=Net + # make dotnetbuild Flavor=Net # - name: Build APK (net) # run: | @@ -230,7 +230,7 @@ jobs: # - name: Build keepass2android (nonet) # run: | - # make msbuild Flavor=NoNet + # make dotnetbuild Flavor=NoNet # - name: Build APK (nonet) # run: | @@ -279,7 +279,7 @@ jobs: with: minimum-size: 8GB - - name: Add msbuild to PATH + - name: Add dotnetbuild to PATH uses: microsoft/setup-msbuild@v2 # If we want to also have nmake, use this instead #uses: ilammy/msvc-dev-cmd@v1 @@ -309,30 +309,49 @@ jobs: run: | make java + - name: Update dotnet workloads + run: | + dotnet workload update + + - name: Select the manifest + run: | + make manifestlink Flavor=Net + - name: Install NuGet dependencies (net) run: make nuget Flavor=Net - name: Build keepass2android (net) run: | - make msbuild Flavor=Net + make dotnetbuild Flavor=Net - name: Build APK (net) + if: github.ref == 'refs/heads/master' + env: + DropboxAppKey: ${{ secrets.DROPBOX_APP_KEY }} + DropboxAppSecret: ${{ secrets.DROPBOX_APP_SECRET }} + DropboxAppFolderAppKey: ${{ secrets.DROPBOX_APP_FOLDER_APP_KEY }} + DropboxAppFolderAppSecret: ${{ secrets.DROPBOX_APP_FOLDER_APP_SECRET }} run: | - make apk Flavor=Net + make apk Configuration=Release Flavor=Net - name: Archive production artifacts (net) uses: actions/upload-artifact@v4 with: - name: signed APK ('net' built on ${{ github.job }}) + name: archive APK ('net' built on ${{ github.job }}) path: | - src/keepass2android/bin/*/*-Signed.apk + src/keepass2android-app/bin/Release/net8.0-android/publish/*.apk + + - name: Select the manifest + run: | + make manifestlink Flavor=NoNet - name: Install NuGet dependencies (nonet) run: make nuget Flavor=NoNet - name: Build keepass2android (nonet) run: | - make msbuild Flavor=NoNet + make dotnetbuild Flavor=NoNet + - name: Test Autofill working-directory: ./src/Kp2aAutofillParser.Tests run: dotnet test @@ -344,9 +363,7 @@ jobs: - name: Archive production artifacts (nonet) uses: actions/upload-artifact@v4 with: - name: signed APK ('nonet' built on ${{ github.job }}) + name: archive APK ('nonet' built on ${{ github.job }}) path: | - src/keepass2android/bin/*/*-Signed.apk + src/keepass2android-app/bin/Release/net8.0-android/publish/*.apk - - name: Perform "make distclean" - run: make distclean diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..d7f73ce2 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,147 @@ +name: Create keepass2android release +env: + NAME: 'Release' + +on: + push: + tags: + - "v1.*" + workflow_dispatch: # Allows manual triggering of the workflow +jobs: + + build-release: + + runs-on: windows-2022 + + strategy: + matrix: + flavor: [Net, NoNet] + target: [apk, apk_split] + + steps: + + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Extract key store + env: + KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }} + KeyStore: "${{ github.workspace }}/kp2a.keystore" + + shell: bash + run: | + echo $KeyStore + echo $KEYSTORE_BASE64 | base64 --decode > $KeyStore + + + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('src/**/*.csproj', 'src/**/packages.config') }} + restore-keys: | + ${{ runner.os }}-nuget- + + # Workaround an issue when building on windows-2022. Error was + # D8 : OpenJDK 64-Bit Server VM warning : INFO: os::commit_memory(0x00000000ae400000, 330301440, 0) failed; error='The paging file is too small for this operation to complete' (DOS error/errno=1455) [D:\a\keepass2android\keepass2android\src\keepass2android\keepass2android-app.csproj] + # C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Xamarin\Android\Xamarin.Android.D8.targets(81,5): error MSB6006: "java.exe" exited with code 1. [D:\a\keepass2android\keepass2android\src\keepass2android\keepass2android-app.csproj] + - name: Configure Pagefile + uses: al-cheb/configure-pagefile-action@a3b6ebd6b634da88790d9c58d4b37a7f4a7b8708 # v1.4 + with: + minimum-size: 8GB + + - name: Add msbuild/dotnet to PATH + uses: microsoft/setup-msbuild@v2 + # If we want to also have nmake, use this instead + #uses: ilammy/msvc-dev-cmd@v1 + + - name: Switch to JDK-17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Display java version + run: java -version + + - name: Build native dependencies + shell: cmd + run: | + make native + + - name: Build java dependencies + shell: cmd + run: | + make java + + - name: List apks + run: find . -type f -name "*.apk" + shell: bash + + - name: Update dotnet workloads + run: | + dotnet workload update + + - name: List apks + run: find . -type f -name "*.apk" + shell: bash + + + - name: Select the manifest + run: | + make manifestlink Flavor=${{ matrix.flavor }} + + - name: List apks + run: find . -type f -name "*.apk" + shell: bash + + + - name: Install NuGet dependencies + run: make nuget Flavor=${{ matrix.flavor }} + + - name: List apks + run: find . -type f -name "*.apk" + shell: bash + + - name: Build APK (net) + env: + KeyStore: "${{ github.workspace }}/kp2a.keystore" + MyAndroidSigningStorePass: ${{ secrets.KEY_STORE_PASSWORD }} + MyAndroidSigningKeyPass: ${{ secrets.KEY_PASSWORD }} + DropboxAppKey: ${{ secrets.DROPBOX_APP_KEY }} + DropboxAppSecret: ${{ secrets.DROPBOX_APP_SECRET }} + DropboxAppFolderAppKey: ${{ secrets.DROPBOX_APP_FOLDER_APP_KEY }} + DropboxAppFolderAppSecret: ${{ secrets.DROPBOX_APP_FOLDER_APP_SECRET }} + + run: | + make ${{ matrix.target }} Configuration=Release Flavor=${{ matrix.flavor }} + + - name: List apks + run: find . -type f -name "*.apk" + shell: bash + + - name: Archive production artifacts + uses: actions/upload-artifact@v4 + with: + name: keepass2android_${{ matrix.target }}_${{ matrix.flavor }} + # the first line is for "apk" target, the second line is for "apk_split" target + path: | + src/keepass2android-app/bin/Release/net8.0-android/publish/*.apk + src/keepass2android-app/bin/Release/net8.0-android/*/publish/*.apk + + - name: List apks + run: find . -type f -name "*.apk" + shell: bash + + - name: Upload APK to GitHub Release + uses: softprops/action-gh-release@v2 + with: + draft: true + files: | + src/keepass2android-app/bin/Release/net8.0-android/publish/*.apk + src/keepass2android-app/bin/Release/net8.0-android/*/publish/*.apk diff --git a/.gitignore b/.gitignore index 47b55426..edfb7c62 100644 --- a/.gitignore +++ b/.gitignore @@ -64,7 +64,7 @@ Thumbs.db /src/java/android-filechooser/code/projectzip/project.zip /src/java/android-filechooser/code/unused.txt -/src/Kp2aBusinessLogic/Io/DropboxFileStorageKeys.cs +/src/Kp2aBusinessLogic/Io/DropboxFileStorage.g.cs /src/java/workspace/DriveTest diff --git a/Makefile b/Makefile index 83cd6419..341f8662 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,10 @@ # This Makefile can be used on both unix-like (use make) & windows (with GNU make) # # append the Configuration variable to 'make' call with value to use in '/p:Configuration=' -# of msbuild command. +# of dotnetbuild command. # # append the Flavor variable to 'make' call with value to use in '/p:Flavor=' -# of msbuild command. +# of dotnetbuild command. # # Example: # make Configuration=Release Flavor=NoNet @@ -18,7 +18,7 @@ # - native: build the native libs # - java: build the java libs # - nuget: restore NuGet packages -# - msbuild: build the project +# - dotnetbuild: build the project # - apk: same as all # - manifestlink: creates a symlink (to be used in building) to the AndroidManifest corresponding to the selected Flavor # @@ -27,7 +27,7 @@ # - clean_native: clean native lib # - clean_java: call clean target of java libs # - clean_nuget: cleanup the 'nuget restore' -# - clean_msbuild: call clean target of msbuild +# - clean_dotnet: call clean target of dotnetbuild # # # @@ -60,45 +60,23 @@ $(info MAKESHELL: $(MAKESHELL)) $(info SHELL: $(SHELL)) $(info ) -# On linux use xabuild, on Windows use MSBuild.exe, otherwise (macos?) use msbuild. ifeq ($(detected_OS),Linux) - MSBUILD_binary := xabuild - MSBUILD := $(shell $(WHICH) $(MSBUILD_binary)) + DOTNET_binary := dotnet + DOTNET := $(shell $(WHICH) $(DOTNET_binary)) else ifeq ($(detected_OS),Windows) - MSBUILD_binary := MSBuild.exe - MSBUILD := $(shell $(WHICH) $(MSBUILD_binary) 2> nul) - ifeq ($(MSBUILD),) - # Additional heuristic to find MSBUILD_BINARY on Windows - VSWHERE := "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" - VSWHERE_CHECK := $(shell @echo off & $(VSWHERE) 2> nul || echo VSWHERE_NOT_FOUND) - ifneq ($(VSWHERE_CHECK),VSWHERE_NOT_FOUND) - MSBUILD := $(shell @echo off & $(VSWHERE) -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe) - VS_INSTALL_PATH := $(shell @echo off & $(VSWHERE) -property installationPath) - endif - endif + DOTNET_binary := dotnet + DOTNET := $(shell $(WHICH) $(DOTNET_binary) 2> nul) else - MSBUILD_binary := msbuild - MSBUILD := $(shell $(WHICH) $(MSBUILD_binary)) + DOTNET_binary := dotnet + DOTNET := $(shell $(WHICH) $(DOTNET_binary)) endif -ifeq ($(MSBUILD),) +ifeq ($(DOTNET),) $(info ) - $(info '$(MSBUILD_binary)' binary could not be found. Check it is in your PATH.) - ifeq ($(detected_OS),Windows) - ifneq ($(VSWHERE_CHECK),VSWHERE_NOT_FOUND) - $(info ) - $(info You may retry after running in the command prompt:) - $(info ) - $(info "$(VS_INSTALL_PATH)\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64) - $(info ) - $(info If this doesn't work, install/find the location of vcvarsall.bat) - $(info or install and add msbuild.exe to your PATH) - $(info ) - endif - endif + $(info '$(DOTNET_binary)' binary could not be found. Check it is in your PATH.) $(error ) endif -$(info MSBUILD: $(MSBUILD)) +$(info DOTNET: $(DOTNET)) $(info ) ifeq ($(ANDROID_SDK_ROOT),) @@ -117,7 +95,7 @@ endif $(info ANDROID_NDK_ROOT: $(ANDROID_NDK_ROOT)) ifneq ($(Configuration),) - MSBUILD_PARAM = -p:Configuration="$(Configuration)" + DOTNET_PARAM = -p:Configuration="$(Configuration)" else $(warning Configuration environment variable not set.) endif @@ -127,7 +105,7 @@ CREATE_MANIFEST_LINK := MANIFEST_FILE := ifneq ($(Flavor),) - MSBUILD_PARAM += -p:Flavor="$(Flavor)" + DOTNET_PARAM += -p:Flavor="$(Flavor)" ifneq ($(Flavor),) ifeq ($(Flavor),Debug) MANIFEST_FILE := AndroidManifest_debug.xml @@ -152,7 +130,7 @@ else endif ifneq ($(KeyStore),) - MSBUILD_PARAM += -p:AndroidKeyStore=True -p:AndroidSigningKeyStore="$(KeyStore)" -p:AndroidSigningStorePass=env:MyAndroidSigningStorePass -p:AndroidSigningKeyPass=env:MyAndroidSigningKeyPass -p:AndroidSigningKeyAlias="kp2a" + DOTNET_PARAM += -p:AndroidKeyStore=True -p:AndroidSigningKeyStore="$(KeyStore)" -p:AndroidSigningStorePass=env:MyAndroidSigningStorePass -p:AndroidSigningKeyPass=env:MyAndroidSigningKeyPass -p:AndroidSigningKeyAlias="kp2a" endif ifeq ($(detected_OS),Windows) @@ -176,7 +154,7 @@ endif # Recursive wildcard: https://stackoverflow.com/a/18258352 rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) -$(info MSBUILD_PARAM: $(MSBUILD_PARAM)) +$(info DOTNET_PARAM: $(DOTNET_PARAM)) $(info nuget path: $(shell $(WHICH) nuget)) $(info ) @@ -254,7 +232,7 @@ OUTPUT_PluginQR = src/java/Keepass2AndroidPluginSDK2/app/build/outputs/aar/Keepa .PHONY: native $(NATIVE_COMPONENTS) clean_native $(NATIVE_CLEAN_TARGETS) \ java $(JAVA_COMPONENTS) clean_java $(JAVA_CLEAN_TARGETS) \ nuget clean_nuget \ - msbuild clean_msbuild \ + dotnetbuild clean_dotnet \ apk all clean all: apk @@ -303,7 +281,7 @@ ifeq ($(shell $(WHICH) nuget),) endif $(RMFILE) stamp.nuget_* nuget restore src/KeePass.sln - $(MSBUILD) src/KeePass.sln -t:restore $(MSBUILD_PARAM) -p:RestorePackagesConfig=true + $(DOTNET) restore src/KeePass.sln $(DOTNET_PARAM) -p:RestorePackagesConfig=true @echo "" > stamp.nuget_$(Flavor) manifestlink: @@ -312,20 +290,21 @@ manifestlink: $(CREATE_MANIFEST_LINK) ##### -src/Kp2aBusinessLogic/Io/DropboxFileStorageKeys.cs: -ifeq ($(detected_OS),Windows) - $(CP) src\Kp2aBusinessLogic\Io\DropboxFileStorageKeysDummy.cs src\Kp2aBusinessLogic\Io\DropboxFileStorageKeys.cs -else - $(CP) src/Kp2aBusinessLogic/Io/DropboxFileStorageKeysDummy.cs $@ -endif -msbuild: manifestlink native java nuget src/Kp2aBusinessLogic/Io/DropboxFileStorageKeys.cs - $(MSBUILD) src/KeePass.sln -target:keepass2android-app -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -p:BuildProjectReferences=true $(MSBUILD_PARAM) -p:Platform="Any CPU" -m +dotnetbuild: manifestlink native java nuget + $(DOTNET) build src/KeePass.sln -target:keepass2android-app -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -p:BuildProjectReferences=true $(DOTNET_PARAM) -p:Platform="Any CPU" -m -apk: msbuild - $(MSBUILD) src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(MSBUILD_PARAM) -p:Platform=AnyCPU -m +apk: manifestlink native java nuget + $(DOTNET) publish src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(DOTNET_PARAM) -p:Platform=AnyCPU -m -build_all: msbuild +apk_split: manifestlink native java nuget + $(DOTNET) publish src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(DOTNET_PARAM) -p:Platform=AnyCPU -m -p:RuntimeIdentifier=android-arm + $(DOTNET) publish src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(DOTNET_PARAM) -p:Platform=AnyCPU -m -p:RuntimeIdentifier=android-arm64 + $(DOTNET) publish src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(DOTNET_PARAM) -p:Platform=AnyCPU -m -p:RuntimeIdentifier=android-x86 + $(DOTNET) publish src/keepass2android-app/keepass2android-app.csproj -p:AndroidSdkDirectory="$(ANDROID_SDK_ROOT)" -t:SignAndroidPackage $(DOTNET_PARAM) -p:Platform=AnyCPU -m -p:RuntimeIdentifier=android-x64 + src/build-scripts/rename-output-apks.sh src/keepass2android-app/bin/Release/net8.0-android/ + +build_all: dotnetbuild ##### Cleanup targets @@ -369,10 +348,10 @@ else endif $(RMFILE) stamp.nuget_* -clean_msbuild: - $(MSBUILD) src/KeePass.sln -target:clean $(MSBUILD_PARAM) +clean_dotnet: + $(DOTNET) clean src/KeePass.sln $(DOTNET_PARAM) -clean: clean_native clean_java clean_nuget clean_msbuild +clean: clean_native clean_java clean_nuget clean_dotnet distclean: clean ifneq ("$(wildcard ./allow_git_clean)","") diff --git a/docs/README.md b/docs/README.md index 372713aa..385d3d74 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,10 +11,10 @@ Regular stable releases of Keepass2Android are available on [Google Play](https: Beta-releases can be obtained by opting in to the [Beta testing channel](https://play.google.com/apps/testing/keepass2android.keepass2android) or [Beta testing channel for Keepass2Android Offline](https://play.google.com/apps/testing/keepass2android.keepass2android_nonet). # How can I contribute? -* Help to translate Keepass2Android into your language or improve translations at [our Crowdin page](http://crowdin.net/project/keepass2android) +* Help to translate Keepass2Android into your language or improve translations at [our Crowdin page](https://crowdin.net/project/keepass2android) * Add features by [creating a plugin](How-to-create-a-plug-in_.md) or creating a pull request. You might want to contact me before you start working so I can coordinate efforts. * [Become a GitHub sponsor to boost 🚀 development](https://github.com/sponsors/PhilippC) -* [Make a donation](http://philipp.crocoll.net/donate.php) +* [Make a donation](https://philipp.crocoll.net/donate.php) # How do I learn more? Please see the [wiki](https://github.com/PhilippC/keepass2android/wiki/Documentation) for further information. diff --git a/src/KeePassLib2Android/Cryptography/CryptoRandomStream.cs b/src/KeePassLib2Android/Cryptography/CryptoRandomStream.cs index b0081c4b..d697a616 100644 --- a/src/KeePassLib2Android/Cryptography/CryptoRandomStream.cs +++ b/src/KeePassLib2Android/Cryptography/CryptoRandomStream.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2017 Dominik Reichl + Copyright (C) 2003-2025 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 @@ -29,197 +29,226 @@ using KeePassLib.Utility; namespace KeePassLib.Cryptography { - /// - /// Algorithms supported by CryptoRandomStream. - /// - public enum CrsAlgorithm - { - /// - /// Not supported. - /// - Null = 0, + /// + /// Algorithms supported by CryptoRandomStream. + /// + public enum CrsAlgorithm + { + /// + /// Not supported. + /// + Null = 0, - /// - /// A variant of the ARCFour algorithm (RC4 incompatible). - /// - /// - ArcFourVariant = 1, + /// + /// A variant of the ArcFour algorithm (RC4 incompatible). + /// Insecure; for backward compatibility only. + /// + ArcFourVariant = 1, - /// - /// Salsa20 stream cipher algorithm. - /// - Salsa20 = 2, + /// + /// Salsa20 stream cipher algorithm. + /// + Salsa20 = 2, - /// - /// ChaCha20 stream cipher algorithm. - /// - ChaCha20 = 3, + /// + /// ChaCha20 stream cipher algorithm. + /// + ChaCha20 = 3, - Count = 4 - } + Count = 4 + } - /// - /// A random stream class. The class is initialized using random - /// bytes provided by the caller. The produced stream has random - /// properties, but for the same seed always the same stream - /// is produced, i.e. this class can be used as stream cipher. - /// - public sealed class CryptoRandomStream : IDisposable - { - private readonly CrsAlgorithm m_crsAlgorithm; + /// + /// A random stream class. The class is initialized using random + /// bytes provided by the caller. The produced stream has random + /// properties, but for the same seed always the same stream + /// is produced, i.e. this class can be used as stream cipher. + /// + public sealed class CryptoRandomStream : IDisposable + { + private readonly CrsAlgorithm m_alg; + private bool m_bDisposed = false; - private byte[] m_pbState = null; - private byte m_i = 0; - private byte m_j = 0; + private readonly byte[] m_pbKey = null; + private readonly byte[] m_pbIV = null; - private Salsa20Cipher m_salsa20 = null; - private ChaCha20Cipher m_chacha20 = null; + private readonly ChaCha20Cipher m_chacha20 = null; + private readonly 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. - public CryptoRandomStream(CrsAlgorithm a, byte[] pbKey) - { - if(pbKey == null) { Debug.Assert(false); throw new ArgumentNullException("pbKey"); } - /// Thrown if the - int cbKey = pbKey.Length; - if(cbKey <= 0) - { - Debug.Assert(false); // Need at least one byte - throw new ArgumentOutOfRangeException("pbKey"); - } - /// parameter is null. - m_crsAlgorithm = a; - /// Thrown if the - if(a == CrsAlgorithm.ChaCha20) - { - byte[] pbKey32 = new byte[32]; - byte[] pbIV12 = new byte[12]; - /// parameter contains no bytes or the - using(SHA512Managed h = new SHA512Managed()) - { - byte[] pbHash = h.ComputeHash(pbKey); - Array.Copy(pbHash, pbKey32, 32); - Array.Copy(pbHash, 32, pbIV12, 0, 12); - MemUtil.ZeroByteArray(pbHash); - } - /// algorithm is unknown. - m_chacha20 = new ChaCha20Cipher(pbKey32, pbIV12, true); - } - else if(a == CrsAlgorithm.Salsa20) - { - byte[] pbKey32 = CryptoUtil.HashSha256(pbKey); - byte[] pbIV8 = new byte[8] { 0xE8, 0x30, 0x09, 0x4B, - 0x97, 0x20, 0x5D, 0x2A }; // Unique constant + private readonly byte[] m_pbState = null; + private byte m_i = 0; + private byte m_j = 0; - m_salsa20 = new Salsa20Cipher(pbKey32, pbIV8); - } - else if(a == CrsAlgorithm.ArcFourVariant) - { - // Fill the state linearly - m_pbState = new byte[256]; - for(int w = 0; w < 256; ++w) m_pbState[w] = (byte)w; + /// + /// Construct a new cryptographically secure random stream object. + /// + /// Algorithm to use. + /// Initialization key. Must not be null + /// and must contain at least 1 byte. + public CryptoRandomStream(CrsAlgorithm a, byte[] pbKey) + { + if (pbKey == null) { Debug.Assert(false); throw new ArgumentNullException("pbKey"); } - unchecked - { - byte j = 0, t; - int inxKey = 0; - for(int w = 0; w < 256; ++w) // Key setup - { - j += (byte)(m_pbState[w] + pbKey[inxKey]); + int cbKey = pbKey.Length; + if (cbKey <= 0) + { + Debug.Assert(false); // Need at least one byte + throw new ArgumentOutOfRangeException("pbKey"); + } - t = m_pbState[0]; // Swap entries - m_pbState[0] = m_pbState[j]; - m_pbState[j] = t; + m_alg = a; - ++inxKey; - if(inxKey >= cbKey) inxKey = 0; - } - } + if (a == CrsAlgorithm.ChaCha20) + { + m_pbKey = new byte[32]; + m_pbIV = new byte[12]; - GetRandomBytes(512); // Increases security, see cryptanalysis - } - else // Unknown algorithm - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("a"); - } - } + using (SHA512Managed h = new SHA512Managed()) + { + byte[] pbHash = h.ComputeHash(pbKey); + Array.Copy(pbHash, m_pbKey, 32); + Array.Copy(pbHash, 32, m_pbIV, 0, 12); + MemUtil.ZeroByteArray(pbHash); + } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + m_chacha20 = new ChaCha20Cipher(m_pbKey, m_pbIV, true); + } + else if (a == CrsAlgorithm.Salsa20) + { + m_pbKey = CryptoUtil.HashSha256(pbKey); + m_pbIV = new byte[8] { 0xE8, 0x30, 0x09, 0x4B, + 0x97, 0x20, 0x5D, 0x2A }; // Unique constant - private void Dispose(bool disposing) - { - if(disposing) - { - if(m_crsAlgorithm == CrsAlgorithm.ChaCha20) - m_chacha20.Dispose(); - else if(m_crsAlgorithm == CrsAlgorithm.Salsa20) - m_salsa20.Dispose(); - else if(m_crsAlgorithm == CrsAlgorithm.ArcFourVariant) - { - MemUtil.ZeroByteArray(m_pbState); - m_i = 0; - m_j = 0; - } - else { Debug.Assert(false); } - } - } + m_salsa20 = new Salsa20Cipher(m_pbKey, m_pbIV); + } + else if (a == CrsAlgorithm.ArcFourVariant) + { + // Fill the state linearly + m_pbState = new byte[256]; + for (int w = 0; w < 256; ++w) m_pbState[w] = (byte)w; - /// - /// Get random bytes. - /// - /// Number of random bytes to retrieve. - /// Returns random bytes. - public byte[] GetRandomBytes(uint uRequestedCount) - { - if(uRequestedCount == 0) return MemUtil.EmptyByteArray; + unchecked + { + byte j = 0, t; + int inxKey = 0; + for (int w = 0; w < 256; ++w) // Key setup + { + j += (byte)(m_pbState[w] + pbKey[inxKey]); - if(uRequestedCount > (uint)int.MaxValue) - throw new ArgumentOutOfRangeException("uRequestedCount"); - int cb = (int)uRequestedCount; + t = m_pbState[0]; // Swap entries + m_pbState[0] = m_pbState[j]; + m_pbState[j] = t; - byte[] pbRet = new byte[cb]; + ++inxKey; + if (inxKey >= cbKey) inxKey = 0; + } + } - if(m_crsAlgorithm == CrsAlgorithm.ChaCha20) - m_chacha20.Encrypt(pbRet, 0, cb); - else if(m_crsAlgorithm == CrsAlgorithm.Salsa20) - m_salsa20.Encrypt(pbRet, 0, cb); - else if(m_crsAlgorithm == CrsAlgorithm.ArcFourVariant) - { - unchecked - { - for(int w = 0; w < cb; ++w) - { - ++m_i; - m_j += m_pbState[m_i]; + GetRandomBytes(512); // Increases security, see cryptanalysis + } + else // Unknown algorithm + { + Debug.Assert(false); + throw new ArgumentOutOfRangeException("a"); + } + } - byte t = m_pbState[m_i]; // Swap entries - m_pbState[m_i] = m_pbState[m_j]; - m_pbState[m_j] = t; + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - t = (byte)(m_pbState[m_i] + m_pbState[m_j]); - pbRet[w] = m_pbState[t]; - } - } - } - else { Debug.Assert(false); } + private void Dispose(bool disposing) + { + if (disposing) + { + if (m_alg == CrsAlgorithm.ChaCha20) + m_chacha20.Dispose(); + else if (m_alg == CrsAlgorithm.Salsa20) + m_salsa20.Dispose(); + else if (m_alg == CrsAlgorithm.ArcFourVariant) + { + MemUtil.ZeroByteArray(m_pbState); + m_i = 0; + m_j = 0; + } + else { Debug.Assert(false); } - return pbRet; - } + if (m_pbKey != null) MemUtil.ZeroByteArray(m_pbKey); + if (m_pbIV != null) MemUtil.ZeroByteArray(m_pbIV); - public ulong GetRandomUInt64() - { - byte[] pb = GetRandomBytes(8); - return MemUtil.BytesToUInt64(pb); - } + m_bDisposed = true; + } + } + + /// + /// Get random bytes. + /// + /// Number of random bytes to retrieve. + /// Returns random bytes. + public byte[] GetRandomBytes(uint uRequestedCount) + { + if (m_bDisposed) throw new ObjectDisposedException(null); + + if (uRequestedCount == 0) return MemUtil.EmptyByteArray; + if (uRequestedCount > (uint)int.MaxValue) + throw new ArgumentOutOfRangeException("uRequestedCount"); + int cb = (int)uRequestedCount; + + byte[] pbRet = new byte[cb]; + + if (m_alg == CrsAlgorithm.ChaCha20) + m_chacha20.Encrypt(pbRet, 0, cb); + else if (m_alg == CrsAlgorithm.Salsa20) + m_salsa20.Encrypt(pbRet, 0, cb); + else if (m_alg == CrsAlgorithm.ArcFourVariant) + { + unchecked + { + for (int w = 0; w < cb; ++w) + { + ++m_i; + m_j += m_pbState[m_i]; + + byte t = m_pbState[m_i]; // Swap entries + m_pbState[m_i] = m_pbState[m_j]; + m_pbState[m_j] = t; + + t = (byte)(m_pbState[m_i] + m_pbState[m_j]); + pbRet[w] = m_pbState[t]; + } + } + } + else { Debug.Assert(false); } + + return pbRet; + } + + public ulong GetRandomUInt64() + { + byte[] pb = GetRandomBytes(8); + return MemUtil.BytesToUInt64(pb); + } + + internal ulong GetRandomUInt64(ulong uMaxExcl) + { + if (uMaxExcl == 0) { Debug.Assert(false); throw new ArgumentOutOfRangeException("uMaxExcl"); } + + ulong uGen, uRem; + do + { + uGen = GetRandomUInt64(); + uRem = uGen % uMaxExcl; + } + while ((uGen - uRem) > (ulong.MaxValue - (uMaxExcl - 1UL))); + // This ensures that the last number of the block (i.e. + // (uGen - uRem) + (uMaxExcl - 1)) is generatable; + // for signed longs, overflow to negative number: + // while((uGen - uRem) + (uMaxExcl - 1) < 0); + + return uRem; + } #if CRSBENCHMARK public static string Benchmark() @@ -237,22 +266,21 @@ namespace KeePassLib.Cryptography return str; } - private static int BenchTime(CrsAlgorithm cra, int nRounds, int nDataSize) + private static int BenchTime(CrsAlgorithm a, int nRounds, int cbData) { byte[] pbKey = new byte[4] { 0x00, 0x01, 0x02, 0x03 }; - int nStart = Environment.TickCount; + int tStart = Environment.TickCount; for(int i = 0; i < nRounds; ++i) { - using(CryptoRandomStream c = new CryptoRandomStream(cra, pbKey)) + using(CryptoRandomStream crs = new CryptoRandomStream(a, pbKey)) { - c.GetRandomBytes((uint)nDataSize); + crs.GetRandomBytes((uint)cbData); } } - int nEnd = Environment.TickCount; - return (nEnd - nStart); + return (Environment.TickCount - tStart); } #endif - } + } } diff --git a/src/KeePassLib2Android/Cryptography/PasswordGenerator/CharSetBasedGenerator.cs b/src/KeePassLib2Android/Cryptography/PasswordGenerator/CharSetBasedGenerator.cs deleted file mode 100644 index f7cec856..00000000 --- a/src/KeePassLib2Android/Cryptography/PasswordGenerator/CharSetBasedGenerator.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2017 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 KeePassLib.Security; -using KeePassLib.Utility; - -namespace KeePassLib.Cryptography.PasswordGenerator -{ - internal static class CharSetBasedGenerator - { - internal static PwgError Generate(out ProtectedString psOut, - PwProfile pwProfile, CryptoRandomStream crsRandomSource) - { - psOut = ProtectedString.Empty; - if(pwProfile.Length == 0) return PwgError.Success; - - PwCharSet pcs = new PwCharSet(pwProfile.CharSet.ToString()); - char[] vGenerated = new char[pwProfile.Length]; - - PwGenerator.PrepareCharSet(pcs, pwProfile); - - for(int nIndex = 0; nIndex < (int)pwProfile.Length; ++nIndex) - { - char ch = PwGenerator.GenerateCharacter(pwProfile, pcs, - crsRandomSource); - - if(ch == char.MinValue) - { - MemUtil.ZeroArray(vGenerated); - return PwgError.TooFewCharacters; - } - - vGenerated[nIndex] = ch; - } - - byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vGenerated); - psOut = new ProtectedString(true, pbUtf8); - MemUtil.ZeroByteArray(pbUtf8); - MemUtil.ZeroArray(vGenerated); - - return PwgError.Success; - } - } -} diff --git a/src/KeePassLib2Android/Cryptography/PasswordGenerator/PatternBasedGenerator.cs b/src/KeePassLib2Android/Cryptography/PasswordGenerator/PatternBasedGenerator.cs deleted file mode 100644 index bb7e7302..00000000 --- a/src/KeePassLib2Android/Cryptography/PasswordGenerator/PatternBasedGenerator.cs +++ /dev/null @@ -1,173 +0,0 @@ -/* - KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2017 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 KeePassLib.Security; -using KeePassLib.Utility; - -namespace KeePassLib.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); - MemUtil.ZeroArray(vArray); - vGenerated.Clear(); - - return PwgError.Success; - } - - private static string ExpandPattern(string strPattern) - { - Debug.Assert(strPattern != null); if(strPattern == null) return string.Empty; - string str = strPattern; - - while(true) - { - int nOpen = FindFirstUnescapedChar(str, '{'); - int nClose = FindFirstUnescapedChar(str, '}'); - - if((nOpen >= 0) && (nOpen < nClose)) - { - string strCount = str.Substring(nOpen + 1, nClose - nOpen - 1); - str = str.Remove(nOpen, nClose - nOpen + 1); - - uint uRepeat; - if(StrUtil.TryParseUInt(strCount, out uRepeat) && (nOpen >= 1)) - { - if(uRepeat == 0) - str = str.Remove(nOpen - 1, 1); - else - str = str.Insert(nOpen, new string(str[nOpen - 1], (int)uRepeat - 1)); - } - } - else break; - } - - return str; - } - - private static int FindFirstUnescapedChar(string str, char ch) - { - for(int i = 0; i < str.Length; ++i) - { - char chCur = str[i]; - - if(chCur == '\\') ++i; // Next is escaped, skip it - else if(chCur == ch) return i; - } - - return -1; - } - } -} diff --git a/src/KeePassLib2Android/Cryptography/PasswordGenerator/PwCharSet.cs b/src/KeePassLib2Android/Cryptography/PasswordGenerator/PwCharSet.cs index 97f34248..e06df070 100644 --- a/src/KeePassLib2Android/Cryptography/PasswordGenerator/PwCharSet.cs +++ b/src/KeePassLib2Android/Cryptography/PasswordGenerator/PwCharSet.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2017 Dominik Reichl + Copyright (C) 2003-2025 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 @@ -19,333 +19,311 @@ using System; using System.Collections.Generic; -using System.Text; using System.Diagnostics; +using System.Text; + +using KeePassLib.Utility; namespace KeePassLib.Cryptography.PasswordGenerator { - public sealed class PwCharSet - { - public const string UpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - public const string LowerCase = "abcdefghijklmnopqrstuvwxyz"; - public const string Digits = "0123456789"; + public sealed class PwCharSet : IEquatable + { + public static readonly string UpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + public static readonly string LowerCase = "abcdefghijklmnopqrstuvwxyz"; + public static readonly string Digits = "0123456789"; - public const string UpperConsonants = "BCDFGHJKLMNPQRSTVWXYZ"; - public const string LowerConsonants = "bcdfghjklmnpqrstvwxyz"; - public const string UpperVowels = "AEIOU"; - public const string LowerVowels = "aeiou"; + public static readonly string UpperConsonants = "BCDFGHJKLMNPQRSTVWXYZ"; + public static readonly string LowerConsonants = "bcdfghjklmnpqrstvwxyz"; + public static readonly string UpperVowels = "AEIOU"; + public static readonly string LowerVowels = "aeiou"; - public const string Punctuation = @",.;:"; - public const string Brackets = @"[]{}()<>"; + public static readonly string Punctuation = ",.;:"; + public static readonly string Brackets = @"[]{}()<>"; - public const string PrintableAsciiSpecial = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; + public static readonly string Special = "!\"#$%&'*+,./:;=?@\\^`|~"; + public static readonly string PrintableAsciiSpecial = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; - public const string UpperHex = "0123456789ABCDEF"; - public const string LowerHex = "0123456789abcdef"; + public static readonly string UpperHex = "0123456789ABCDEF"; + public static readonly string LowerHex = "0123456789abcdef"; - public const string Invalid = "\t\r\n"; - public const string LookAlike = @"O0l1I|"; + public static readonly string LookAlike = "O0Il1|"; - internal const string MenuAccels = PwCharSet.LowerCase + PwCharSet.Digits; + /// + /// Latin-1 Supplement except U+00A0 (NBSP) and U+00AD (SHY). + /// + public static readonly string Latin1S = + "\u00A1\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7" + + "\u00A8\u00A9\u00AA\u00AB\u00AC\u00AE\u00AF" + + "\u00B0\u00B1\u00B2\u00B3\u00B4\u00B5\u00B6\u00B7" + + "\u00B8\u00B9\u00BA\u00BB\u00BC\u00BD\u00BE\u00BF" + + "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7" + + "\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF" + + "\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7" + + "\u00D8\u00D9\u00DA\u00DB\u00DC\u00DD\u00DE\u00DF" + + "\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7" + + "\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF" + + "\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7" + + "\u00F8\u00F9\u00FA\u00FB\u00FC\u00FD\u00FE\u00FF"; - private const int CharTabSize = (0x10000 / 8); + // internal static readonly string MenuAccels = PwCharSet.LowerCase + PwCharSet.Digits; - private List m_vChars = new List(); - private byte[] m_vTab = new byte[CharTabSize]; + [Obsolete] + public static string SpecialChars { get { return PwCharSet.Special; } } + [Obsolete] + public static string HighAnsiChars { get { return PwCharSet.Latin1S; } } - private static string m_strHighAnsi = null; - public static string HighAnsiChars - { - get - { - if(m_strHighAnsi == null) { new PwCharSet(); } // Create string - Debug.Assert(m_strHighAnsi != null); - return m_strHighAnsi; - } - } + private readonly List m_lChars = new List(); + private readonly byte[] m_vTab = new byte[0x10000 / 8]; - private static string m_strSpecial = null; - public static string SpecialChars - { - get - { - if(m_strSpecial == null) { new PwCharSet(); } // Create string - Debug.Assert(m_strSpecial != null); - return m_strSpecial; - } - } + /// + /// Create a new, empty character set. + /// + public PwCharSet() + { + Debug.Assert(PwCharSet.Latin1S.Length == (16 * 6 - 2)); + } - /// - /// Create a new, empty character set collection object. - /// - public PwCharSet() - { - Initialize(true); - } + public PwCharSet(string strCharSet) + { + Add(strCharSet); + } - public PwCharSet(string strCharSet) - { - Initialize(true); - Add(strCharSet); - } + /// + /// Number of characters in this set. + /// + public uint Size + { + get { return (uint)m_lChars.Count; } + } - private PwCharSet(bool bFullInitialize) - { - Initialize(bFullInitialize); - } + /// + /// 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_lChars.Count) + throw new ArgumentOutOfRangeException("uPos"); - private void Initialize(bool bFullInitialize) - { - Clear(); + return m_lChars[(int)uPos]; + } + } - if(!bFullInitialize) return; + public bool Equals(PwCharSet other) + { + if (object.ReferenceEquals(other, this)) return true; + if (object.ReferenceEquals(other, null)) return false; - if(m_strHighAnsi == null) - { - StringBuilder sbHighAnsi = new StringBuilder(); - // [U+0080, U+009F] are C1 control characters, - // U+00A0 is non-breaking space - for(char ch = '\u00A1'; ch <= '\u00AC'; ++ch) - sbHighAnsi.Append(ch); - // U+00AD is soft hyphen (format character) - for(char ch = '\u00AE'; ch < '\u00FF'; ++ch) - sbHighAnsi.Append(ch); - sbHighAnsi.Append('\u00FF'); + if (m_lChars.Count != other.m_lChars.Count) return false; - m_strHighAnsi = sbHighAnsi.ToString(); - } + return MemUtil.ArraysEqual(m_vTab, other.m_vTab); + } - if(m_strSpecial == null) - { - PwCharSet pcs = new PwCharSet(false); - pcs.AddRange('!', '/'); - pcs.AddRange(':', '@'); - pcs.AddRange('[', '`'); - pcs.Add(@"|~"); - pcs.Remove(@"-_ "); - pcs.Remove(PwCharSet.Brackets); + public override bool Equals(object obj) + { + return Equals(obj as PwCharSet); + } - m_strSpecial = pcs.ToString(); - } - } + public override int GetHashCode() + { + return (int)MemUtil.Hash32(m_vTab, 0, m_vTab.Length); + } - /// - /// Number of characters in this set. - /// - public uint Size - { - get { return (uint)m_vChars.Count; } - } + /// + /// Remove all characters from this set. + /// + public void Clear() + { + m_lChars.Clear(); + Array.Clear(m_vTab, 0, m_vTab.Length); + } - /// - /// 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"); + public bool Contains(char ch) + { + return (((m_vTab[ch / 8] >> (ch % 8)) & 1) != char.MinValue); + } - return m_vChars[(int)uPos]; - } - } + public bool Contains(string strCharacters) + { + Debug.Assert(strCharacters != null); + if (strCharacters == null) throw new ArgumentNullException("strCharacters"); - /// - /// Remove all characters from this set. - /// - public void Clear() - { - m_vChars.Clear(); - Array.Clear(m_vTab, 0, m_vTab.Length); - } + foreach (char ch in strCharacters) + { + if (!Contains(ch)) return false; + } - public bool Contains(char ch) - { - return (((m_vTab[ch / 8] >> (ch % 8)) & 1) != char.MinValue); - } + return true; + } - public bool Contains(string strCharacters) - { - Debug.Assert(strCharacters != null); - if(strCharacters == null) throw new ArgumentNullException("strCharacters"); + /// + /// Add characters to the set. + /// + /// Character to add. + public void Add(char ch) + { + if (ch == char.MinValue) { Debug.Assert(false); return; } - foreach(char ch in strCharacters) - { - if(!Contains(ch)) return false; - } + if (!Contains(ch)) + { + m_lChars.Add(ch); + m_vTab[ch / 8] |= (byte)(1 << (ch % 8)); + } + } - return true; - } + /// + /// 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"); - /// - /// Add characters to the set. - /// - /// Character to add. - public void Add(char ch) - { - if(ch == char.MinValue) { Debug.Assert(false); return; } + foreach (char ch in strCharSet) + Add(ch); + } - if(!Contains(ch)) - { - m_vChars.Add(ch); - m_vTab[ch / 8] |= (byte)(1 << (ch % 8)); - } - } + public void Add(string strCharSet1, string strCharSet2) + { + Add(strCharSet1); + Add(strCharSet2); + } - /// - /// 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"); + public void Add(string strCharSet1, string strCharSet2, string strCharSet3) + { + Add(strCharSet1); + Add(strCharSet2); + Add(strCharSet3); + } - m_vChars.Capacity = m_vChars.Count + strCharSet.Length; + public void AddRange(char chMin, char chMax) + { + for (char ch = chMin; ch < chMax; ++ch) + Add(ch); - foreach(char ch in strCharSet) - Add(ch); - } + Add(chMax); + } - public void Add(string strCharSet1, string strCharSet2) - { - Add(strCharSet1); - Add(strCharSet2); - } + public bool AddCharSet(char chCharSetIdentifier) + { + bool bResult = true; - public void Add(string strCharSet1, string strCharSet2, string strCharSet3) - { - Add(strCharSet1); - Add(strCharSet2); - Add(strCharSet3); - } + switch (chCharSetIdentifier) + { + case 'a': Add(PwCharSet.LowerCase, PwCharSet.Digits); break; + case 'A': + Add(PwCharSet.LowerCase, PwCharSet.UpperCase, + PwCharSet.Digits); break; + case 'U': Add(PwCharSet.UpperCase, PwCharSet.Digits); break; + case 'c': Add(PwCharSet.LowerConsonants); break; + case 'C': + Add(PwCharSet.LowerConsonants, + PwCharSet.UpperConsonants); break; + case 'z': Add(PwCharSet.UpperConsonants); break; + case 'd': Add(PwCharSet.Digits); break; // Digit + case 'h': Add(PwCharSet.LowerHex); break; + case 'H': Add(PwCharSet.UpperHex); break; + case 'l': Add(PwCharSet.LowerCase); break; + case 'L': Add(PwCharSet.LowerCase, PwCharSet.UpperCase); break; + case 'u': Add(PwCharSet.UpperCase); break; + case 'p': Add(PwCharSet.Punctuation); break; + case 'b': Add(PwCharSet.Brackets); break; + case 's': Add(PwCharSet.PrintableAsciiSpecial); break; + case 'S': + Add(PwCharSet.UpperCase, PwCharSet.LowerCase); + Add(PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial); break; + case 'v': Add(PwCharSet.LowerVowels); break; + case 'V': Add(PwCharSet.LowerVowels, PwCharSet.UpperVowels); break; + case 'Z': Add(PwCharSet.UpperVowels); break; + case 'x': Add(PwCharSet.Latin1S); break; + default: bResult = false; break; + } - public void AddRange(char chMin, char chMax) - { - m_vChars.Capacity = m_vChars.Count + (chMax - chMin) + 1; + return bResult; + } - for(char ch = chMin; ch < chMax; ++ch) - Add(ch); + public bool Remove(char ch) + { + m_vTab[ch / 8] &= (byte)(~(1 << (ch % 8))); + return m_lChars.Remove(ch); + } - Add(chMax); - } + public bool Remove(string strCharacters) + { + Debug.Assert(strCharacters != null); + if (strCharacters == null) throw new ArgumentNullException("strCharacters"); - public bool AddCharSet(char chCharSetIdentifier) - { - bool bResult = true; + bool bResult = true; + foreach (char ch in strCharacters) + { + if (!Remove(ch)) bResult = false; + } - switch(chCharSetIdentifier) - { - case 'a': Add(PwCharSet.LowerCase, PwCharSet.Digits); break; - case 'A': Add(PwCharSet.LowerCase, PwCharSet.UpperCase, - PwCharSet.Digits); break; - case 'U': Add(PwCharSet.UpperCase, PwCharSet.Digits); break; - case 'c': Add(PwCharSet.LowerConsonants); break; - case 'C': Add(PwCharSet.LowerConsonants, - PwCharSet.UpperConsonants); break; - case 'z': Add(PwCharSet.UpperConsonants); break; - case 'd': Add(PwCharSet.Digits); break; // Digit - case 'h': Add(PwCharSet.LowerHex); break; - case 'H': Add(PwCharSet.UpperHex); break; - case 'l': Add(PwCharSet.LowerCase); break; - case 'L': Add(PwCharSet.LowerCase, PwCharSet.UpperCase); break; - case 'u': Add(PwCharSet.UpperCase); break; - case 'p': Add(PwCharSet.Punctuation); break; - case 'b': Add(PwCharSet.Brackets); break; - case 's': Add(PwCharSet.PrintableAsciiSpecial); break; - case 'S': Add(PwCharSet.UpperCase, PwCharSet.LowerCase); - Add(PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial); break; - case 'v': Add(PwCharSet.LowerVowels); break; - case 'V': Add(PwCharSet.LowerVowels, PwCharSet.UpperVowels); break; - case 'Z': Add(PwCharSet.UpperVowels); break; - case 'x': Add(m_strHighAnsi); break; - default: bResult = false; break; - } + return bResult; + } - return bResult; - } + public bool RemoveIfAllExist(string strCharacters) + { + Debug.Assert(strCharacters != null); + if (strCharacters == null) throw new ArgumentNullException("strCharacters"); - public bool Remove(char ch) - { - m_vTab[ch / 8] &= (byte)(~(1 << (ch % 8))); - return m_vChars.Remove(ch); - } + if (!Contains(strCharacters)) + return false; - public bool Remove(string strCharacters) - { - Debug.Assert(strCharacters != null); - if(strCharacters == null) throw new ArgumentNullException("strCharacters"); + return Remove(strCharacters); + } - bool bResult = true; - foreach(char ch in strCharacters) - { - if(!Remove(ch)) bResult = false; - } + /// + /// 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(m_lChars.Count); + foreach (char ch in m_lChars) + sb.Append(ch); - return bResult; - } + return sb.ToString(); + } - public bool RemoveIfAllExist(string strCharacters) - { - Debug.Assert(strCharacters != null); - if(strCharacters == null) throw new ArgumentNullException("strCharacters"); + public string PackAndRemoveCharRanges() + { + StringBuilder sb = new StringBuilder(); - if(!Contains(strCharacters)) - return false; + sb.Append(RemoveIfAllExist(PwCharSet.UpperCase) ? 'U' : '_'); + sb.Append(RemoveIfAllExist(PwCharSet.LowerCase) ? 'L' : '_'); + sb.Append(RemoveIfAllExist(PwCharSet.Digits) ? 'D' : '_'); + sb.Append(RemoveIfAllExist(PwCharSet.Special) ? 'S' : '_'); + sb.Append(RemoveIfAllExist(PwCharSet.Punctuation) ? 'P' : '_'); + sb.Append(RemoveIfAllExist("-") ? 'm' : '_'); + sb.Append(RemoveIfAllExist("_") ? 'u' : '_'); + sb.Append(RemoveIfAllExist(" ") ? 's' : '_'); + sb.Append(RemoveIfAllExist(PwCharSet.Brackets) ? 'B' : '_'); + sb.Append(RemoveIfAllExist(PwCharSet.Latin1S) ? 'H' : '_'); - return Remove(strCharacters); - } + return sb.ToString(); + } - /// - /// 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); + public void UnpackCharRanges(string strRanges) + { + if (strRanges == null) { Debug.Assert(false); return; } + if (strRanges.Length < 10) { Debug.Assert(false); return; } - return sb.ToString(); - } - - public string PackAndRemoveCharRanges() - { - StringBuilder sb = new StringBuilder(); - - sb.Append(RemoveIfAllExist(PwCharSet.UpperCase) ? 'U' : '_'); - sb.Append(RemoveIfAllExist(PwCharSet.LowerCase) ? 'L' : '_'); - sb.Append(RemoveIfAllExist(PwCharSet.Digits) ? 'D' : '_'); - sb.Append(RemoveIfAllExist(m_strSpecial) ? 'S' : '_'); - sb.Append(RemoveIfAllExist(PwCharSet.Punctuation) ? 'P' : '_'); - sb.Append(RemoveIfAllExist(@"-") ? 'm' : '_'); - sb.Append(RemoveIfAllExist(@"_") ? 'u' : '_'); - sb.Append(RemoveIfAllExist(@" ") ? 's' : '_'); - sb.Append(RemoveIfAllExist(PwCharSet.Brackets) ? 'B' : '_'); - sb.Append(RemoveIfAllExist(m_strHighAnsi) ? 'H' : '_'); - - return sb.ToString(); - } - - public void UnpackCharRanges(string strRanges) - { - if(strRanges == null) { Debug.Assert(false); return; } - if(strRanges.Length < 10) { Debug.Assert(false); return; } - - if(strRanges[0] != '_') Add(PwCharSet.UpperCase); - if(strRanges[1] != '_') Add(PwCharSet.LowerCase); - if(strRanges[2] != '_') Add(PwCharSet.Digits); - if(strRanges[3] != '_') Add(m_strSpecial); - if(strRanges[4] != '_') Add(PwCharSet.Punctuation); - if(strRanges[5] != '_') Add('-'); - if(strRanges[6] != '_') Add('_'); - if(strRanges[7] != '_') Add(' '); - if(strRanges[8] != '_') Add(PwCharSet.Brackets); - if(strRanges[9] != '_') Add(m_strHighAnsi); - } - } + if (strRanges[0] != '_') Add(PwCharSet.UpperCase); + if (strRanges[1] != '_') Add(PwCharSet.LowerCase); + if (strRanges[2] != '_') Add(PwCharSet.Digits); + if (strRanges[3] != '_') Add(PwCharSet.Special); + if (strRanges[4] != '_') Add(PwCharSet.Punctuation); + if (strRanges[5] != '_') Add('-'); + if (strRanges[6] != '_') Add('_'); + if (strRanges[7] != '_') Add(' '); + if (strRanges[8] != '_') Add(PwCharSet.Brackets); + if (strRanges[9] != '_') Add(PwCharSet.Latin1S); + } + } } diff --git a/src/KeePassLib2Android/Cryptography/PasswordGenerator/PwGenerator.cs b/src/KeePassLib2Android/Cryptography/PasswordGenerator/PwGenerator.cs index 73f9284c..68a1a952 100644 --- a/src/KeePassLib2Android/Cryptography/PasswordGenerator/PwGenerator.cs +++ b/src/KeePassLib2Android/Cryptography/PasswordGenerator/PwGenerator.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2016 Dominik Reichl + Copyright (C) 2003-2025 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 @@ -20,133 +20,172 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Security.Cryptography; using System.Text; +#if !KeePassUAP +using System.Security.Cryptography; +#endif + +using KeePassLib.Resources; using KeePassLib.Security; using KeePassLib.Utility; namespace KeePassLib.Cryptography.PasswordGenerator { - public enum PwgError - { - Success = 0, - Unknown = 1, - TooFewCharacters = 2, - UnknownAlgorithm = 3 - } + public enum PwgError + { + Success = 0, + Unknown = 1, + TooFewCharacters = 2, + UnknownAlgorithm = 3, + InvalidCharSet = 4, + InvalidPattern = 5 + } - /// - /// 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"); + /// + /// Password generator. + /// + public static class PwGenerator + { - CryptoRandomStream crs = CreateCryptoStream(pbUserEntropy); - PwgError e = PwgError.Unknown; + private static CryptoRandomStream CreateRandomStream(byte[] pbAdditionalEntropy, + out byte[] pbKey) + { + pbKey = CryptoRandom.Instance.GetRandomBytes(128); - 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; } + // Mix in additional entropy + Debug.Assert(pbKey.Length >= 64); + if ((pbAdditionalEntropy != null) && (pbAdditionalEntropy.Length != 0)) + { + using (SHA512Managed h = new SHA512Managed()) + { + byte[] pbHash = h.ComputeHash(pbAdditionalEntropy); + MemUtil.XorArray(pbHash, 0, pbKey, 0, pbHash.Length); + MemUtil.ZeroByteArray(pbHash); + } + } - return e; - } + return new CryptoRandomStream(CrsAlgorithm.ChaCha20, pbKey); + } - private static CryptoRandomStream CreateCryptoStream(byte[] pbAdditionalEntropy) - { - byte[] pbKey = CryptoRandom.Instance.GetRandomBytes(128); + internal static char GenerateCharacter(PwCharSet pwCharSet, + CryptoRandomStream crsRandomSource) + { + uint cc = pwCharSet.Size; + if (cc == 0) return char.MinValue; - // Mix in additional entropy - Debug.Assert(pbKey.Length >= 64); - if ((pbAdditionalEntropy != null) && (pbAdditionalEntropy.Length > 0)) - { - using (SHA512Managed h = new SHA512Managed()) - { - byte[] pbHash = h.ComputeHash(pbAdditionalEntropy); - MemUtil.XorArray(pbHash, 0, pbKey, 0, pbHash.Length); - } - } + uint i = (uint)crsRandomSource.GetRandomUInt64(cc); + return pwCharSet[i]; + } - return new CryptoRandomStream(CrsAlgorithm.ChaCha20, pbKey); - } + internal static bool PrepareCharSet(PwCharSet pwCharSet, PwProfile pwProfile) + { + uint cc = pwCharSet.Size; + for (uint i = 0; i < cc; ++i) + { + char ch = pwCharSet[i]; + if ((ch == char.MinValue) || (ch == '\t') || (ch == '\r') || + (ch == '\n') || char.IsSurrogate(ch)) + return false; + } - internal static char GenerateCharacter(PwProfile pwProfile, - PwCharSet pwCharSet, CryptoRandomStream crsRandomSource) - { - if (pwCharSet.Size == 0) return char.MinValue; + if (pwProfile.ExcludeLookAlike) pwCharSet.Remove(PwCharSet.LookAlike); - ulong uIndex = crsRandomSource.GetRandomUInt64(); - uIndex %= (ulong)pwCharSet.Size; + if (!string.IsNullOrEmpty(pwProfile.ExcludeCharacters)) + pwCharSet.Remove(pwProfile.ExcludeCharacters); - char ch = pwCharSet[(uint)uIndex]; + return true; + } - if (pwProfile.NoRepeatingCharacters) - pwCharSet.Remove(ch); + internal static void Shuffle(char[] v, CryptoRandomStream crsRandomSource) + { + if (v == null) { Debug.Assert(false); return; } + if (crsRandomSource == null) { Debug.Assert(false); return; } - return ch; - } + for (int i = v.Length - 1; i >= 1; --i) + { + int j = (int)crsRandomSource.GetRandomUInt64((ulong)(i + 1)); - internal static void PrepareCharSet(PwCharSet pwCharSet, PwProfile pwProfile) - { - pwCharSet.Remove(PwCharSet.Invalid); + char t = v[i]; + v[i] = v[j]; + v[j] = t; + } + } - if (pwProfile.ExcludeLookAlike) pwCharSet.Remove(PwCharSet.LookAlike); + private static PwgError GenerateCustom(out ProtectedString psOut, + PwProfile pwProfile, CryptoRandomStream crs, + CustomPwGeneratorPool pwAlgorithmPool) + { + psOut = ProtectedString.Empty; - if (pwProfile.ExcludeCharacters.Length > 0) - pwCharSet.Remove(pwProfile.ExcludeCharacters); - } + Debug.Assert(pwProfile.GeneratorType == PasswordGeneratorType.Custom); + if (pwAlgorithmPool == null) return PwgError.UnknownAlgorithm; - internal static void ShufflePassword(char[] pPassword, - CryptoRandomStream crsRandomSource) - { - Debug.Assert(pPassword != null); if (pPassword == null) return; - Debug.Assert(crsRandomSource != null); if (crsRandomSource == null) return; + string strID = pwProfile.CustomAlgorithmUuid; + if (string.IsNullOrEmpty(strID)) return PwgError.UnknownAlgorithm; - if (pPassword.Length <= 1) return; // Nothing to shuffle + byte[] pbUuid = Convert.FromBase64String(strID); + PwUuid uuid = new PwUuid(pbUuid); + CustomPwGenerator pwg = pwAlgorithmPool.Find(uuid); + if (pwg == null) { Debug.Assert(false); return PwgError.UnknownAlgorithm; } - for (int nSelect = 0; nSelect < pPassword.Length; ++nSelect) - { - ulong uRandomIndex = crsRandomSource.GetRandomUInt64(); - uRandomIndex %= (ulong)(pPassword.Length - nSelect); + ProtectedString pwd = pwg.Generate(pwProfile.CloneDeep(), crs); + if (pwd == null) return PwgError.Unknown; - char chTemp = pPassword[nSelect]; - pPassword[nSelect] = pPassword[nSelect + (int)uRandomIndex]; - pPassword[nSelect + (int)uRandomIndex] = chTemp; - } - } + psOut = pwd; + return PwgError.Success; + } - private static PwgError GenerateCustom(out ProtectedString psOut, - PwProfile pwProfile, CryptoRandomStream crs, - CustomPwGeneratorPool pwAlgorithmPool) - { - psOut = ProtectedString.Empty; + internal static string ErrorToString(PwgError e, bool bHeader) + { + if (e == PwgError.Success) { Debug.Assert(false); return string.Empty; } + if ((e == PwgError.Unknown) && bHeader) return KLRes.PwGenFailed; - Debug.Assert(pwProfile.GeneratorType == PasswordGeneratorType.Custom); - if (pwAlgorithmPool == null) return PwgError.UnknownAlgorithm; + string str = KLRes.UnknownError; + switch (e) + { + // case PwgError.Success: + // break; - string strID = pwProfile.CustomAlgorithmUuid; - if (string.IsNullOrEmpty(strID)) { Debug.Assert(false); return PwgError.UnknownAlgorithm; } + case PwgError.Unknown: + break; - byte[] pbUuid = Convert.FromBase64String(strID); - PwUuid uuid = new PwUuid(pbUuid); - CustomPwGenerator pwg = pwAlgorithmPool.Find(uuid); - if (pwg == null) { Debug.Assert(false); return PwgError.UnknownAlgorithm; } + case PwgError.TooFewCharacters: + str = KLRes.CharSetTooFewChars; + break; - ProtectedString pwd = pwg.Generate(pwProfile.CloneDeep(), crs); - if (pwd == null) return PwgError.Unknown; + case PwgError.UnknownAlgorithm: + str = KLRes.AlgorithmUnknown; + break; - psOut = pwd; - return PwgError.Success; - } - } + case PwgError.InvalidCharSet: + str = KLRes.CharSetInvalid; + break; + + case PwgError.InvalidPattern: + str = KLRes.PatternInvalid; + break; + + default: + Debug.Assert(false); + break; + } + + if (bHeader) + str = KLRes.PwGenFailed + MessageService.NewParagraph + str; + + return str; + } + + internal static string ErrorToString(Exception ex, bool bHeader) + { + string str = ((ex == null) ? KLRes.UnknownError : + StrUtil.FormatException(ex)); + + if (bHeader) + str = KLRes.PwGenFailed + MessageService.NewParagraph + str; + + return str; + } + } } diff --git a/src/KeePassLib2Android/Cryptography/PopularPasswords.cs b/src/KeePassLib2Android/Cryptography/PopularPasswords.cs index e6223c82..d7323a4a 100644 --- a/src/KeePassLib2Android/Cryptography/PopularPasswords.cs +++ b/src/KeePassLib2Android/Cryptography/PopularPasswords.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2017 Dominik Reichl + Copyright (C) 2003-2025 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 @@ -19,114 +19,115 @@ using System; using System.Collections.Generic; -using System.Text; using System.Diagnostics; +using System.Text; using KeePassLib.Utility; namespace KeePassLib.Cryptography { - public static class PopularPasswords - { - private static Dictionary> m_dicts = - new Dictionary>(); + public static class PopularPasswords + { + private static readonly Dictionary> g_dicts = + new Dictionary>(); - internal static int MaxLength - { - get - { - int iMaxLen = 0; - foreach(int iLen in m_dicts.Keys) - { - if(iLen > iMaxLen) iMaxLen = iLen; - } + internal static int MaxLength + { + get + { + Debug.Assert(g_dicts.Count > 0); // Should be initialized - return iMaxLen; - } - } + int iMaxLen = 0; + foreach (int iLen in g_dicts.Keys) + { + if (iLen > iMaxLen) iMaxLen = iLen; + } - internal static bool ContainsLength(int nLength) - { - Dictionary dDummy; - return m_dicts.TryGetValue(nLength, out dDummy); - } + return iMaxLen; + } + } - public static bool IsPopularPassword(char[] vPassword) - { - ulong uDummy; - return IsPopularPassword(vPassword, out uDummy); - } + internal static bool ContainsLength(int nLength) + { + Dictionary dDummy; + return g_dicts.TryGetValue(nLength, out dDummy); + } - public static bool IsPopularPassword(char[] vPassword, out ulong uDictSize) - { - if(vPassword == null) throw new ArgumentNullException("vPassword"); - if(vPassword.Length == 0) { uDictSize = 0; return false; } + public static bool IsPopularPassword(char[] vPassword) + { + ulong uDummy; + return IsPopularPassword(vPassword, out uDummy); + } - string str = new string(vPassword); + public static bool IsPopularPassword(char[] vPassword, out ulong uDictSize) + { + if (vPassword == null) throw new ArgumentNullException("vPassword"); + if (vPassword.Length == 0) { uDictSize = 0; return false; } - try { return IsPopularPasswordPriv(str, out uDictSize); } - catch(Exception) { Debug.Assert(false); } +#if DEBUG + Array.ForEach(vPassword, ch => Debug.Assert(ch == char.ToLower(ch))); +#endif - uDictSize = 0; - return false; - } + try { return IsPopularPasswordPriv(vPassword, out uDictSize); } + catch (Exception) { Debug.Assert(false); } - private static bool IsPopularPasswordPriv(string str, out ulong uDictSize) - { - Debug.Assert(m_dicts.Count > 0); // Should be initialized with data + uDictSize = 0; + return false; + } - Dictionary d; - if(!m_dicts.TryGetValue(str.Length, out d)) - { - uDictSize = 0; - return false; - } + private static bool IsPopularPasswordPriv(char[] vPassword, out ulong uDictSize) + { + Debug.Assert(g_dicts.Count > 0); // Should be initialized with data - uDictSize = (ulong)d.Count; - return d.ContainsKey(str); - } + Dictionary d; + if (!g_dicts.TryGetValue(vPassword.Length, out d)) + { + uDictSize = 0; + return false; + } - public static void Add(byte[] pbData, bool bGZipped) - { - try - { - if(bGZipped) - pbData = MemUtil.Decompress(pbData); + uDictSize = (ulong)d.Count; + return d.ContainsKey(vPassword); + } - string strData = StrUtil.Utf8.GetString(pbData, 0, pbData.Length); - if(string.IsNullOrEmpty(strData)) { Debug.Assert(false); return; } + public static void Add(byte[] pbData, bool bGZipped) + { + try + { + if (bGZipped) + pbData = MemUtil.Decompress(pbData); - if(!char.IsWhiteSpace(strData[strData.Length - 1])) - strData += "\n"; + string strData = StrUtil.Utf8.GetString(pbData, 0, pbData.Length); + if (string.IsNullOrEmpty(strData)) { Debug.Assert(false); return; } - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < strData.Length; ++i) - { - char ch = strData[i]; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i <= strData.Length; ++i) + { + char ch = ((i == strData.Length) ? ' ' : strData[i]); - if(char.IsWhiteSpace(ch)) - { - int cc = sb.Length; - if(cc > 0) - { - string strWord = sb.ToString(); - Debug.Assert(strWord.Length == cc); + if (char.IsWhiteSpace(ch)) + { + int cc = sb.Length; + if (cc > 0) + { + char[] vWord = new char[cc]; + sb.CopyTo(0, vWord, 0, cc); - Dictionary d; - if(!m_dicts.TryGetValue(cc, out d)) - { - d = new Dictionary(); - m_dicts[cc] = d; - } + Dictionary d; + if (!g_dicts.TryGetValue(cc, out d)) + { + d = new Dictionary(MemUtil.ArrayHelperExOfChar); + g_dicts[cc] = d; + } - d[strWord] = true; - sb.Remove(0, cc); - } - } - else sb.Append(char.ToLower(ch)); - } - } - catch(Exception) { Debug.Assert(false); } - } - } + d[vWord] = true; + sb.Remove(0, cc); + } + } + else sb.Append(char.ToLower(ch)); + } + } + catch (Exception) { Debug.Assert(false); } + } + } } diff --git a/src/KeePassLib2Android/Cryptography/QualityEstimation.cs b/src/KeePassLib2Android/Cryptography/QualityEstimation.cs index cf835825..686e1ec4 100644 --- a/src/KeePassLib2Android/Cryptography/QualityEstimation.cs +++ b/src/KeePassLib2Android/Cryptography/QualityEstimation.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2017 Dominik Reichl + Copyright (C) 2003-2025 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 @@ -19,750 +19,756 @@ using System; using System.Collections.Generic; -using System.Text; using System.Diagnostics; +using System.Text; using KeePassLib.Cryptography.PasswordGenerator; using KeePassLib.Utility; namespace KeePassLib.Cryptography { - /// - /// A class that offers static functions to estimate the quality of - /// passwords. - /// - public static class QualityEstimation - { - private static class PatternID - { - public const char LowerAlpha = 'L'; - public const char UpperAlpha = 'U'; - public const char Digit = 'D'; - public const char Special = 'S'; - public const char High = 'H'; - public const char Other = 'X'; + /// + /// A class that offers static functions to estimate the quality of + /// passwords. + /// + public static class QualityEstimation + { + private static class PatternID + { + internal const char LowerAlpha = 'L'; + internal const char UpperAlpha = 'U'; + internal const char Digit = 'D'; + internal const char Special = 'S'; + internal const char Latin1S = 'H'; + internal const char Other = 'X'; - public const char Dictionary = 'W'; - public const char Repetition = 'R'; - public const char Number = 'N'; - public const char DiffSeq = 'C'; + internal const char Dictionary = 'W'; + internal const char Repetition = 'R'; + internal const char Number = 'N'; + internal const char DiffSeq = 'C'; - public const string All = "LUDSHXWRNC"; - } + internal const string All = "LUDSHXWRNC"; + } - // private static class CharDistrib - // { - // public static readonly ulong[] LowerAlpha = new ulong[26] { - // 884, 211, 262, 249, 722, 98, 172, 234, 556, 124, 201, 447, 321, - // 483, 518, 167, 18, 458, 416, 344, 231, 105, 80, 48, 238, 76 - // }; - // public static readonly ulong[] UpperAlpha = new ulong[26] { - // 605, 188, 209, 200, 460, 81, 130, 163, 357, 122, 144, 332, 260, - // 317, 330, 132, 18, 320, 315, 250, 137, 76, 60, 36, 161, 54 - // }; - // public static readonly ulong[] Digit = new ulong[10] { - // 574, 673, 524, 377, 339, 336, 312, 310, 357, 386 - // }; - // } + // private static class CharDistrib + // { + // public static readonly ulong[] LowerAlpha = new ulong[26] { + // 884, 211, 262, 249, 722, 98, 172, 234, 556, 124, 201, 447, 321, + // 483, 518, 167, 18, 458, 416, 344, 231, 105, 80, 48, 238, 76 + // }; + // public static readonly ulong[] UpperAlpha = new ulong[26] { + // 605, 188, 209, 200, 460, 81, 130, 163, 357, 122, 144, 332, 260, + // 317, 330, 132, 18, 320, 315, 250, 137, 76, 60, 36, 161, 54 + // }; + // public static readonly ulong[] Digit = new ulong[10] { + // 574, 673, 524, 377, 339, 336, 312, 310, 357, 386 + // }; + // } - private sealed class QeCharType - { - private readonly char m_chTypeID; - public char TypeID { get { return m_chTypeID; } } + private sealed class QeCharType + { + private readonly char m_chTypeID; + public char TypeID { get { return m_chTypeID; } } - private readonly string m_strAlph; - public string Alphabet { get { return m_strAlph; } } + private readonly string m_strAlph; + public string Alphabet { get { return m_strAlph; } } - private readonly int m_nChars; - public int CharCount { get { return m_nChars; } } + private readonly int m_nChars; + public int CharCount { get { return m_nChars; } } - private readonly char m_chFirst; - private readonly char m_chLast; + private readonly char m_chFirst; + private readonly char m_chLast; - private readonly double m_dblCharSize; - public double CharSize { get { return m_dblCharSize; } } + private readonly double m_dblCharSize; + public double CharSize { get { return m_dblCharSize; } } - public QeCharType(char chTypeID, string strAlphabet, bool bIsConsecutive) - { - if(strAlphabet == null) throw new ArgumentNullException(); - if(strAlphabet.Length == 0) throw new ArgumentException(); + public QeCharType(char chTypeID, string strAlphabet, bool bIsConsecutive) + { + if (strAlphabet == null) throw new ArgumentNullException(); + if (strAlphabet.Length == 0) throw new ArgumentException(); - m_chTypeID = chTypeID; - m_strAlph = strAlphabet; - m_nChars = m_strAlph.Length; - m_chFirst = (bIsConsecutive ? m_strAlph[0] : char.MinValue); - m_chLast = (bIsConsecutive ? m_strAlph[m_nChars - 1] : char.MinValue); + m_chTypeID = chTypeID; + m_strAlph = strAlphabet; + m_nChars = m_strAlph.Length; + m_chFirst = (bIsConsecutive ? m_strAlph[0] : char.MinValue); + m_chLast = (bIsConsecutive ? m_strAlph[m_nChars - 1] : char.MinValue); - m_dblCharSize = Log2(m_nChars); + m_dblCharSize = Log2(m_nChars); - Debug.Assert(((int)(m_chLast - m_chFirst) == (m_nChars - 1)) || - !bIsConsecutive); - } + Debug.Assert(((int)(m_chLast - m_chFirst) == (m_nChars - 1)) || + !bIsConsecutive); + } - public QeCharType(char chTypeID, int nChars) // Catch-none set - { - if(nChars <= 0) throw new ArgumentOutOfRangeException(); + public QeCharType(char chTypeID, int nChars) // Catch-none set + { + if (nChars <= 0) throw new ArgumentOutOfRangeException(); - m_chTypeID = chTypeID; - m_strAlph = string.Empty; - m_nChars = nChars; - m_chFirst = char.MinValue; - m_chLast = char.MinValue; + m_chTypeID = chTypeID; + m_strAlph = string.Empty; + m_nChars = nChars; + m_chFirst = char.MinValue; + m_chLast = char.MinValue; - m_dblCharSize = Log2(m_nChars); - } + m_dblCharSize = Log2(m_nChars); + } - public bool Contains(char ch) - { - if(m_chLast != char.MinValue) - return ((ch >= m_chFirst) && (ch <= m_chLast)); + public bool Contains(char ch) + { + if (m_chLast != char.MinValue) + return ((ch >= m_chFirst) && (ch <= m_chLast)); - Debug.Assert(m_strAlph.Length > 0); // Don't call for catch-none set - return (m_strAlph.IndexOf(ch) >= 0); - } - } + Debug.Assert(m_strAlph.Length > 0); // Don't call for catch-none set + return (m_strAlph.IndexOf(ch) >= 0); + } + } - private sealed class EntropyEncoder - { - private readonly string m_strAlph; - private Dictionary m_dHisto = new Dictionary(); - private readonly ulong m_uBaseWeight; - private readonly ulong m_uCharWeight; - private readonly ulong m_uOccExclThreshold; + private sealed class EntropyEncoder + { + private readonly string m_strAlph; + private readonly Dictionary m_dHisto = new Dictionary(); + private readonly ulong m_uBaseWeight; + private readonly ulong m_uCharWeight; + private readonly ulong m_uOccExclThreshold; - public EntropyEncoder(string strAlphabet, ulong uBaseWeight, - ulong uCharWeight, ulong uOccExclThreshold) - { - if(strAlphabet == null) throw new ArgumentNullException(); - if(strAlphabet.Length == 0) throw new ArgumentException(); + public EntropyEncoder(string strAlphabet, ulong uBaseWeight, + ulong uCharWeight, ulong uOccExclThreshold) + { + if (strAlphabet == null) throw new ArgumentNullException(); + if (strAlphabet.Length == 0) throw new ArgumentException(); - m_strAlph = strAlphabet; - m_uBaseWeight = uBaseWeight; - m_uCharWeight = uCharWeight; - m_uOccExclThreshold = uOccExclThreshold; + m_strAlph = strAlphabet; + m_uBaseWeight = uBaseWeight; + m_uCharWeight = uCharWeight; + m_uOccExclThreshold = uOccExclThreshold; #if DEBUG - Dictionary d = new Dictionary(); - foreach(char ch in m_strAlph) { d[ch] = true; } - Debug.Assert(d.Count == m_strAlph.Length); // No duplicates + Dictionary d = new Dictionary(); + foreach (char ch in m_strAlph) { d[ch] = true; } + Debug.Assert(d.Count == m_strAlph.Length); // No duplicates #endif - } - - public void Reset() - { - m_dHisto.Clear(); - } - - public void Write(char ch) - { - Debug.Assert(m_strAlph.IndexOf(ch) >= 0); - - ulong uOcc; - m_dHisto.TryGetValue(ch, out uOcc); - Debug.Assert(m_dHisto.ContainsKey(ch) || (uOcc == 0)); - m_dHisto[ch] = uOcc + 1; - } - - public double GetOutputSize() - { - ulong uTotalWeight = m_uBaseWeight * (ulong)m_strAlph.Length; - foreach(ulong u in m_dHisto.Values) - { - Debug.Assert(u >= 1); - if(u > m_uOccExclThreshold) - uTotalWeight += (u - m_uOccExclThreshold) * m_uCharWeight; - } - - double dSize = 0.0, dTotalWeight = (double)uTotalWeight; - foreach(ulong u in m_dHisto.Values) - { - ulong uWeight = m_uBaseWeight; - if(u > m_uOccExclThreshold) - uWeight += (u - m_uOccExclThreshold) * m_uCharWeight; - - dSize -= (double)u * Log2((double)uWeight / dTotalWeight); - } - - return dSize; - } - } - - private sealed class MultiEntropyEncoder - { - private Dictionary m_dEncs = - new Dictionary(); - - public MultiEntropyEncoder() - { - } - - public void AddEncoder(char chTypeID, EntropyEncoder ec) - { - if(ec == null) { Debug.Assert(false); return; } - - Debug.Assert(!m_dEncs.ContainsKey(chTypeID)); - m_dEncs[chTypeID] = ec; - } - - public void Reset() - { - foreach(EntropyEncoder ec in m_dEncs.Values) { ec.Reset(); } - } - - public bool Write(char chTypeID, char chData) - { - EntropyEncoder ec; - if(!m_dEncs.TryGetValue(chTypeID, out ec)) - return false; - - ec.Write(chData); - return true; - } - - public double GetOutputSize() - { - double d = 0.0; - - foreach(EntropyEncoder ec in m_dEncs.Values) - { - d += ec.GetOutputSize(); - } - - return d; - } - } - - private sealed class QePatternInstance - { - private readonly int m_iPos; - public int Position { get { return m_iPos; } } - - private readonly int m_nLen; - public int Length { get { return m_nLen; } } - - private readonly char m_chPatternID; - public char PatternID { get { return m_chPatternID; } } - - private readonly double m_dblCost; - public double Cost { get { return m_dblCost; } } - - private readonly QeCharType m_ctSingle; - public QeCharType SingleCharType { get { return m_ctSingle; } } - - public QePatternInstance(int iPosition, int nLength, char chPatternID, - double dblCost) - { - m_iPos = iPosition; - m_nLen = nLength; - m_chPatternID = chPatternID; - m_dblCost = dblCost; - m_ctSingle = null; - } - - public QePatternInstance(int iPosition, int nLength, QeCharType ctSingle) - { - m_iPos = iPosition; - m_nLen = nLength; - m_chPatternID = ctSingle.TypeID; - m_dblCost = ctSingle.CharSize; - m_ctSingle = ctSingle; - } - } - - private sealed class QePathState - { - public readonly int Position; - public readonly List Path; - - public QePathState(int iPosition, List lPath) - { - this.Position = iPosition; - this.Path = lPath; - } - } - - private static object m_objSyncInit = new object(); - private static List m_lCharTypes = null; - - private static void EnsureInitialized() - { - lock(m_objSyncInit) - { - if(m_lCharTypes == null) - { - string strSpecial = PwCharSet.PrintableAsciiSpecial; - if(strSpecial.IndexOf(' ') >= 0) { Debug.Assert(false); } - else strSpecial = strSpecial + " "; - - int nSp = strSpecial.Length; - int nHi = PwCharSet.HighAnsiChars.Length; - - m_lCharTypes = new List(); - - m_lCharTypes.Add(new QeCharType(PatternID.LowerAlpha, - PwCharSet.LowerCase, true)); - m_lCharTypes.Add(new QeCharType(PatternID.UpperAlpha, - PwCharSet.UpperCase, true)); - m_lCharTypes.Add(new QeCharType(PatternID.Digit, - PwCharSet.Digits, true)); - m_lCharTypes.Add(new QeCharType(PatternID.Special, - strSpecial, false)); - m_lCharTypes.Add(new QeCharType(PatternID.High, - PwCharSet.HighAnsiChars, false)); - m_lCharTypes.Add(new QeCharType(PatternID.Other, - 0x10000 - (2 * 26) - 10 - nSp - nHi)); - } - } - } - - /// - /// Estimate the quality of a password. - /// - /// Password to check. - /// Estimated bit-strength of the password. - public static uint EstimatePasswordBits(char[] vPasswordChars) - { - if(vPasswordChars == null) { Debug.Assert(false); return 0; } - if(vPasswordChars.Length == 0) return 0; - - EnsureInitialized(); - - int n = vPasswordChars.Length; - List[] vPatterns = new List[n]; - for(int i = 0; i < n; ++i) - { - vPatterns[i] = new List(); - - QePatternInstance piChar = new QePatternInstance(i, 1, - GetCharType(vPasswordChars[i])); - vPatterns[i].Add(piChar); - } - - FindRepetitions(vPasswordChars, vPatterns); - FindNumbers(vPasswordChars, vPatterns); - FindDiffSeqs(vPasswordChars, vPatterns); - FindPopularPasswords(vPasswordChars, vPatterns); - - // Encoders must not be static, because the entropy estimation - // may run concurrently in multiple threads and the encoders are - // not read-only - EntropyEncoder ecPattern = new EntropyEncoder(PatternID.All, 0, 1, 0); - MultiEntropyEncoder mcData = new MultiEntropyEncoder(); - for(int i = 0; i < (m_lCharTypes.Count - 1); ++i) - { - // Let m be the alphabet size. In order to ensure that two same - // characters cost at least as much as a single character, for - // the probability p and weight w of the character it must hold: - // -log(1/m) >= -2*log(p) - // <=> log(1/m) <= log(p^2) <=> 1/m <= p^2 <=> p >= sqrt(1/m); - // sqrt(1/m) = (1+w)/(m+w) - // <=> m+w = (1+w)*sqrt(m) <=> m+w = sqrt(m) + w*sqrt(m) - // <=> w*(1-sqrt(m)) = sqrt(m) - m <=> w = (sqrt(m)-m)/(1-sqrt(m)) - // <=> w = (sqrt(m)-m)*(1+sqrt(m))/(1-m) - // <=> w = (sqrt(m)-m+m-m*sqrt(m))/(1-m) <=> w = sqrt(m) - ulong uw = (ulong)Math.Sqrt((double)m_lCharTypes[i].CharCount); - - mcData.AddEncoder(m_lCharTypes[i].TypeID, new EntropyEncoder( - m_lCharTypes[i].Alphabet, 1, uw, 1)); - } - - double dblMinCost = (double)int.MaxValue; - int tStart = Environment.TickCount; - - Stack sRec = new Stack(); - sRec.Push(new QePathState(0, new List())); - while(sRec.Count > 0) - { - int tDiff = Environment.TickCount - tStart; - if(tDiff > 500) break; - - QePathState s = sRec.Pop(); - - if(s.Position >= n) - { - Debug.Assert(s.Position == n); - - double dblCost = ComputePathCost(s.Path, vPasswordChars, - ecPattern, mcData); - if(dblCost < dblMinCost) dblMinCost = dblCost; - } - else - { - List lSubs = vPatterns[s.Position]; - for(int i = lSubs.Count - 1; i >= 0; --i) - { - QePatternInstance pi = lSubs[i]; - Debug.Assert(pi.Position == s.Position); - Debug.Assert(pi.Length >= 1); - - List lNewPath = - new List(s.Path.Count + 1); - lNewPath.AddRange(s.Path); - lNewPath.Add(pi); - Debug.Assert(lNewPath.Capacity == (s.Path.Count + 1)); - - QePathState sNew = new QePathState(s.Position + - pi.Length, lNewPath); - sRec.Push(sNew); - } - } - } - - return (uint)Math.Ceiling(dblMinCost); - } - - /// - /// Estimate the quality of a password. - /// - /// Password to check, UTF-8 encoded. - /// Estimated bit-strength of the password. - public static uint EstimatePasswordBits(byte[] pbUnprotectedUtf8) - { - if(pbUnprotectedUtf8 == null) { Debug.Assert(false); return 0; } - - char[] vChars = StrUtil.Utf8.GetChars(pbUnprotectedUtf8); - uint uResult = EstimatePasswordBits(vChars); - MemUtil.ZeroArray(vChars); - - return uResult; - } - - private static QeCharType GetCharType(char ch) - { - int nTypes = m_lCharTypes.Count; - Debug.Assert((nTypes > 0) && (m_lCharTypes[nTypes - 1].CharCount > 256)); - - for(int i = 0; i < (nTypes - 1); ++i) - { - if(m_lCharTypes[i].Contains(ch)) - return m_lCharTypes[i]; - } - - return m_lCharTypes[nTypes - 1]; - } - - private static double ComputePathCost(List l, - char[] vPassword, EntropyEncoder ecPattern, MultiEntropyEncoder mcData) - { - ecPattern.Reset(); - for(int i = 0; i < l.Count; ++i) - ecPattern.Write(l[i].PatternID); - double dblPatternCost = ecPattern.GetOutputSize(); - - mcData.Reset(); - double dblDataCost = 0.0; - foreach(QePatternInstance pi in l) - { - QeCharType tChar = pi.SingleCharType; - if(tChar != null) - { - char ch = vPassword[pi.Position]; - if(!mcData.Write(tChar.TypeID, ch)) - dblDataCost += pi.Cost; - } - else dblDataCost += pi.Cost; - } - dblDataCost += mcData.GetOutputSize(); - - return (dblPatternCost + dblDataCost); - } - - private static void FindPopularPasswords(char[] vPassword, - List[] vPatterns) - { - int n = vPassword.Length; - - char[] vLower = new char[n]; - char[] vLeet = new char[n]; - for(int i = 0; i < n; ++i) - { - char ch = vPassword[i]; - - vLower[i] = char.ToLower(ch); - vLeet[i] = char.ToLower(DecodeLeetChar(ch)); - } - - char chErased = default(char); - Debug.Assert(chErased == char.MinValue); - - int nMaxLen = Math.Min(n, PopularPasswords.MaxLength); - for(int nSubLen = nMaxLen; nSubLen >= 3; --nSubLen) - { - if(!PopularPasswords.ContainsLength(nSubLen)) continue; - - char[] vSub = new char[nSubLen]; - - for(int i = 0; i <= (n - nSubLen); ++i) - { - if(Array.IndexOf(vLower, chErased, i, nSubLen) >= 0) - continue; - - Array.Copy(vLower, i, vSub, 0, nSubLen); - if(!EvalAddPopularPasswordPattern(vPatterns, vPassword, - i, vSub, 0.0)) - { - Array.Copy(vLeet, i, vSub, 0, nSubLen); - if(EvalAddPopularPasswordPattern(vPatterns, vPassword, - i, vSub, 1.5)) - { - Array.Clear(vLower, i, nSubLen); // Not vLeet - Debug.Assert(vLower[i] == chErased); - } - } - else - { - Array.Clear(vLower, i, nSubLen); - Debug.Assert(vLower[i] == chErased); - } - } - } - } - - private static bool EvalAddPopularPasswordPattern(List[] vPatterns, - char[] vPassword, int i, char[] vSub, double dblCostPerMod) - { - ulong uDictSize; - if(!PopularPasswords.IsPopularPassword(vSub, out uDictSize)) - return false; - - int n = vSub.Length; - int d = HammingDist(vSub, 0, vPassword, i, n); - - double dblCost = Log2((double)uDictSize); - - // dblCost += log2(n binom d) - int k = Math.Min(d, n - d); - for(int j = n; j > (n - k); --j) - dblCost += Log2(j); - for(int j = k; j >= 2; --j) - dblCost -= Log2(j); - - dblCost += dblCostPerMod * (double)d; - - vPatterns[i].Add(new QePatternInstance(i, n, PatternID.Dictionary, - dblCost)); - return true; - } - - private static char DecodeLeetChar(char chLeet) - { - if((chLeet >= '\u00C0') && (chLeet <= '\u00C6')) return 'a'; - if((chLeet >= '\u00C8') && (chLeet <= '\u00CB')) return 'e'; - if((chLeet >= '\u00CC') && (chLeet <= '\u00CF')) return 'i'; - if((chLeet >= '\u00D2') && (chLeet <= '\u00D6')) return 'o'; - if((chLeet >= '\u00D9') && (chLeet <= '\u00DC')) return 'u'; - if((chLeet >= '\u00E0') && (chLeet <= '\u00E6')) return 'a'; - if((chLeet >= '\u00E8') && (chLeet <= '\u00EB')) return 'e'; - if((chLeet >= '\u00EC') && (chLeet <= '\u00EF')) return 'i'; - if((chLeet >= '\u00F2') && (chLeet <= '\u00F6')) return 'o'; - if((chLeet >= '\u00F9') && (chLeet <= '\u00FC')) return 'u'; - - char ch; - switch(chLeet) - { - case '4': - case '@': - case '?': - case '^': - case '\u00AA': ch = 'a'; break; - case '8': - case '\u00DF': ch = 'b'; break; - case '(': - case '{': - case '[': - case '<': - case '\u00A2': - case '\u00A9': - case '\u00C7': - case '\u00E7': ch = 'c'; break; - case '\u00D0': - case '\u00F0': ch = 'd'; break; - case '3': - case '\u20AC': - case '&': - case '\u00A3': ch = 'e'; break; - case '6': - case '9': ch = 'g'; break; - case '#': ch = 'h'; break; - case '1': - case '!': - case '|': - case '\u00A1': - case '\u00A6': ch = 'i'; break; - case '\u00D1': - case '\u00F1': ch = 'n'; break; - case '0': - case '*': - case '\u00A4': // Currency - case '\u00B0': // Degree - case '\u00D8': - case '\u00F8': ch = 'o'; break; - case '\u00AE': ch = 'r'; break; - case '$': - case '5': - case '\u00A7': ch = 's'; break; - case '+': - case '7': ch = 't'; break; - case '\u00B5': ch = 'u'; break; - case '%': - case '\u00D7': ch = 'x'; break; - case '\u00A5': - case '\u00DD': - case '\u00FD': - case '\u00FF': ch = 'y'; break; - case '2': ch = 'z'; break; - default: ch = chLeet; break; - } - - return ch; - } - - private static int HammingDist(char[] v1, int iOffset1, - char[] v2, int iOffset2, int nLength) - { - int nDist = 0; - for(int i = 0; i < nLength; ++i) - { - if(v1[iOffset1 + i] != v2[iOffset2 + i]) ++nDist; - } - - return nDist; - } - - private static void FindRepetitions(char[] vPassword, - List[] vPatterns) - { - int n = vPassword.Length; - char[] v = new char[n]; - Array.Copy(vPassword, v, n); - - char chErased = char.MaxValue; - for(int m = (n / 2); m >= 3; --m) - { - for(int x1 = 0; x1 <= (n - (2 * m)); ++x1) - { - bool bFoundRep = false; - - for(int x2 = (x1 + m); x2 <= (n - m); ++x2) - { - if(PartsEqual(v, x1, x2, m)) - { - double dblCost = Log2(x1 + 1) + Log2(m); - vPatterns[x2].Add(new QePatternInstance(x2, m, - PatternID.Repetition, dblCost)); - - ErasePart(v, x2, m, ref chErased); - bFoundRep = true; - } - } - - if(bFoundRep) ErasePart(v, x1, m, ref chErased); - } - } - } - - private static bool PartsEqual(char[] v, int x1, int x2, int nLength) - { - for(int i = 0; i < nLength; ++i) - { - if(v[x1 + i] != v[x2 + i]) return false; - } - - return true; - } - - private static void ErasePart(char[] v, int i, int n, ref char chErased) - { - for(int j = 0; j < n; ++j) - { - v[i + j] = chErased; - --chErased; - } - } - - private static void FindNumbers(char[] vPassword, - List[] vPatterns) - { - int n = vPassword.Length; - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < n; ++i) - { - char ch = vPassword[i]; - if((ch >= '0') && (ch <= '9')) sb.Append(ch); - else - { - AddNumberPattern(vPatterns, sb.ToString(), i - sb.Length); - sb.Remove(0, sb.Length); - } - } - AddNumberPattern(vPatterns, sb.ToString(), n - sb.Length); - } - - private static void AddNumberPattern(List[] vPatterns, - string strNumber, int i) - { - if(strNumber.Length <= 2) return; - - int nZeros = 0; - for(int j = 0; j < strNumber.Length; ++j) - { - if(strNumber[j] != '0') break; - ++nZeros; - } - - double dblCost = Log2(nZeros + 1); - if(nZeros < strNumber.Length) - { - string strNonZero = strNumber.Substring(nZeros); + } + + public void Reset() + { + m_dHisto.Clear(); + } + + public void Write(char ch) + { + Debug.Assert(m_strAlph.IndexOf(ch) >= 0); + + ulong uOcc; + m_dHisto.TryGetValue(ch, out uOcc); + Debug.Assert(m_dHisto.ContainsKey(ch) || (uOcc == 0)); + m_dHisto[ch] = uOcc + 1; + } + + public double GetOutputSize() + { + ulong uTotalWeight = m_uBaseWeight * (ulong)m_strAlph.Length; + foreach (ulong u in m_dHisto.Values) + { + Debug.Assert(u >= 1); + if (u > m_uOccExclThreshold) + uTotalWeight += (u - m_uOccExclThreshold) * m_uCharWeight; + } + + double dSize = 0.0, dTotalWeight = (double)uTotalWeight; + foreach (ulong u in m_dHisto.Values) + { + ulong uWeight = m_uBaseWeight; + if (u > m_uOccExclThreshold) + uWeight += (u - m_uOccExclThreshold) * m_uCharWeight; + + dSize -= (double)u * Log2((double)uWeight / dTotalWeight); + } + + return dSize; + } + } + + private sealed class MultiEntropyEncoder + { + private readonly Dictionary m_dEncs = + new Dictionary(); + + public MultiEntropyEncoder() + { + } + + public void AddEncoder(char chTypeID, EntropyEncoder ec) + { + if (ec == null) { Debug.Assert(false); return; } + + Debug.Assert(!m_dEncs.ContainsKey(chTypeID)); + m_dEncs[chTypeID] = ec; + } + + public void Reset() + { + foreach (EntropyEncoder ec in m_dEncs.Values) { ec.Reset(); } + } + + public bool Write(char chTypeID, char chData) + { + EntropyEncoder ec; + if (!m_dEncs.TryGetValue(chTypeID, out ec)) + return false; + + ec.Write(chData); + return true; + } + + public double GetOutputSize() + { + double d = 0.0; + + foreach (EntropyEncoder ec in m_dEncs.Values) + { + d += ec.GetOutputSize(); + } + + return d; + } + } + + private sealed class QePatternInstance + { + private readonly int m_iPos; + public int Position { get { return m_iPos; } } + + private readonly int m_nLen; + public int Length { get { return m_nLen; } } + + private readonly char m_chPatternID; + public char PatternID { get { return m_chPatternID; } } + + private readonly double m_dblCost; + public double Cost { get { return m_dblCost; } } + + private readonly QeCharType m_ctSingle; + public QeCharType SingleCharType { get { return m_ctSingle; } } + + public QePatternInstance(int iPosition, int nLength, char chPatternID, + double dblCost) + { + m_iPos = iPosition; + m_nLen = nLength; + m_chPatternID = chPatternID; + m_dblCost = dblCost; + m_ctSingle = null; + } + + public QePatternInstance(int iPosition, int nLength, QeCharType ctSingle) + { + m_iPos = iPosition; + m_nLen = nLength; + m_chPatternID = ctSingle.TypeID; + m_dblCost = ctSingle.CharSize; + m_ctSingle = ctSingle; + } + } + + private sealed class QePathState + { + public readonly int Position; + public readonly List Path; + + public QePathState(int iPosition, List lPath) + { + this.Position = iPosition; + this.Path = lPath; + } + } + + private static readonly object m_objSyncInit = new object(); + private static List m_lCharTypes = null; + + private static void EnsureInitialized() + { + lock (m_objSyncInit) + { + if (m_lCharTypes == null) + { + string strSpecial = PwCharSet.PrintableAsciiSpecial; + if (strSpecial.IndexOf(' ') >= 0) { Debug.Assert(false); } + else strSpecial += " "; + + int nSp = strSpecial.Length; + int nL1S = PwCharSet.Latin1S.Length; + + m_lCharTypes = new List() + { + new QeCharType(PatternID.LowerAlpha, PwCharSet.LowerCase, true), + new QeCharType(PatternID.UpperAlpha, PwCharSet.UpperCase, true), + new QeCharType(PatternID.Digit, PwCharSet.Digits, true), + new QeCharType(PatternID.Special, strSpecial, false), + new QeCharType(PatternID.Latin1S, PwCharSet.Latin1S, false), + new QeCharType(PatternID.Other, 0x10000 - (2 * 26) - 10 - nSp - nL1S) + }; + } + } + } + + /// + /// Estimate the quality of a password. + /// + /// Password to check. + /// Estimated bit-strength of the password. + public static uint EstimatePasswordBits(char[] vPassword) + { + if (vPassword == null) { Debug.Assert(false); return 0; } + if (vPassword.Length == 0) return 0; + + EnsureInitialized(); + + int n = vPassword.Length; + List[] vPatterns = new List[n]; + for (int i = 0; i < n; ++i) + { + vPatterns[i] = new List(); + + QePatternInstance piChar = new QePatternInstance(i, 1, + GetCharType(vPassword[i])); + vPatterns[i].Add(piChar); + } + + FindRepetitions(vPassword, vPatterns); + FindNumbers(vPassword, vPatterns); + FindDiffSeqs(vPassword, vPatterns); + FindPopularPasswords(vPassword, vPatterns); + + // Encoders must not be static, because the entropy estimation + // may run concurrently in multiple threads and the encoders are + // not read-only + EntropyEncoder ecPattern = new EntropyEncoder(PatternID.All, 0, 1, 0); + MultiEntropyEncoder mcData = new MultiEntropyEncoder(); + for (int i = 0; i < (m_lCharTypes.Count - 1); ++i) + { + // Let m be the alphabet size. In order to ensure that two same + // characters cost at least as much as a single character, for + // the probability p and weight w of the character it must hold: + // -log(1/m) >= -2*log(p) + // <=> log(1/m) <= log(p^2) <=> 1/m <= p^2 <=> p >= sqrt(1/m); + // sqrt(1/m) = (1+w)/(m+w) + // <=> m+w = (1+w)*sqrt(m) <=> m+w = sqrt(m) + w*sqrt(m) + // <=> w*(1-sqrt(m)) = sqrt(m) - m <=> w = (sqrt(m)-m)/(1-sqrt(m)) + // <=> w = (sqrt(m)-m)*(1+sqrt(m))/(1-m) + // <=> w = (sqrt(m)-m+m-m*sqrt(m))/(1-m) <=> w = sqrt(m) + ulong uw = (ulong)Math.Sqrt((double)m_lCharTypes[i].CharCount); + + mcData.AddEncoder(m_lCharTypes[i].TypeID, new EntropyEncoder( + m_lCharTypes[i].Alphabet, 1, uw, 1)); + } + + double dblMinCost = (double)int.MaxValue; + int tStart = Environment.TickCount; + + Stack sRec = new Stack(); + sRec.Push(new QePathState(0, new List())); + while (sRec.Count > 0) + { + int tDiff = Environment.TickCount - tStart; + if (tDiff > 500) break; + + QePathState s = sRec.Pop(); + + if (s.Position >= n) + { + Debug.Assert(s.Position == n); + + double dblCost = ComputePathCost(s.Path, vPassword, + ecPattern, mcData); + if (dblCost < dblMinCost) dblMinCost = dblCost; + } + else + { + List lSubs = vPatterns[s.Position]; + for (int i = lSubs.Count - 1; i >= 0; --i) + { + QePatternInstance pi = lSubs[i]; + Debug.Assert(pi.Position == s.Position); + Debug.Assert(pi.Length >= 1); + + List lNewPath = + new List(s.Path.Count + 1); + lNewPath.AddRange(s.Path); + lNewPath.Add(pi); + Debug.Assert(lNewPath.Capacity == (s.Path.Count + 1)); + + QePathState sNew = new QePathState(s.Position + + pi.Length, lNewPath); + sRec.Push(sNew); + } + } + } + + return (uint)Math.Ceiling(dblMinCost); + } + + /// + /// Estimate the quality of a password. + /// + /// Password to check, UTF-8 encoded. + /// Estimated bit-strength of the password. + public static uint EstimatePasswordBits(byte[] pbUnprotectedUtf8) + { + if (pbUnprotectedUtf8 == null) { Debug.Assert(false); return 0; } + + char[] v = StrUtil.Utf8.GetChars(pbUnprotectedUtf8); + uint r; + try { r = EstimatePasswordBits(v); } + finally { MemUtil.ZeroArray(v); } + + return r; + } + + private static QeCharType GetCharType(char ch) + { + int nTypes = m_lCharTypes.Count; + Debug.Assert((nTypes > 0) && (m_lCharTypes[nTypes - 1].CharCount > 256)); + + for (int i = 0; i < (nTypes - 1); ++i) + { + if (m_lCharTypes[i].Contains(ch)) + return m_lCharTypes[i]; + } + + return m_lCharTypes[nTypes - 1]; + } + + private static double ComputePathCost(List l, + char[] vPassword, EntropyEncoder ecPattern, MultiEntropyEncoder mcData) + { + ecPattern.Reset(); + for (int i = 0; i < l.Count; ++i) + ecPattern.Write(l[i].PatternID); + double dblPatternCost = ecPattern.GetOutputSize(); + + mcData.Reset(); + double dblDataCost = 0.0; + foreach (QePatternInstance pi in l) + { + QeCharType tChar = pi.SingleCharType; + if (tChar != null) + { + char ch = vPassword[pi.Position]; + if (!mcData.Write(tChar.TypeID, ch)) + dblDataCost += pi.Cost; + } + else dblDataCost += pi.Cost; + } + dblDataCost += mcData.GetOutputSize(); + + return (dblPatternCost + dblDataCost); + } + + private static void FindPopularPasswords(char[] vPassword, + List[] vPatterns) + { + int n = vPassword.Length; + + char[] vLower = new char[n]; + char[] vLeet = new char[n]; + for (int i = 0; i < n; ++i) + { + char ch = vPassword[i]; + + vLower[i] = char.ToLower(ch); + vLeet[i] = char.ToLower(DecodeLeetChar(ch)); + } + + char chErased = default(char); // The value that Array.Clear uses + Debug.Assert(chErased == char.MinValue); + + int nMaxLen = Math.Min(n, PopularPasswords.MaxLength); + for (int nSubLen = nMaxLen; nSubLen >= 3; --nSubLen) + { + if (!PopularPasswords.ContainsLength(nSubLen)) continue; + + char[] vSub = new char[nSubLen]; + + for (int i = 0; i <= (n - nSubLen); ++i) + { + if (Array.IndexOf(vLower, chErased, i, nSubLen) >= 0) + continue; + + Array.Copy(vLower, i, vSub, 0, nSubLen); + if (!EvalAddPopularPasswordPattern(vPatterns, vPassword, + i, vSub, 0.0)) + { + Array.Copy(vLeet, i, vSub, 0, nSubLen); + if (EvalAddPopularPasswordPattern(vPatterns, vPassword, + i, vSub, 1.5)) + { + Array.Clear(vLower, i, nSubLen); // Not vLeet + Debug.Assert(vLower[i] == chErased); + } + } + else + { + Array.Clear(vLower, i, nSubLen); + Debug.Assert(vLower[i] == chErased); + } + } + + MemUtil.ZeroArray(vSub); + } + + MemUtil.ZeroArray(vLower); + MemUtil.ZeroArray(vLeet); + } + + private static bool EvalAddPopularPasswordPattern(List[] vPatterns, + char[] vPassword, int i, char[] vSub, double dblCostPerMod) + { + ulong uDictSize; + if (!PopularPasswords.IsPopularPassword(vSub, out uDictSize)) + return false; + + int n = vSub.Length; + int d = HammingDist(vSub, 0, vPassword, i, n); + + double dblCost = Log2((double)uDictSize); + + // dblCost += log2(n binom d) + int k = Math.Min(d, n - d); + for (int j = n; j > (n - k); --j) + dblCost += Log2(j); + for (int j = k; j >= 2; --j) + dblCost -= Log2(j); + + dblCost += dblCostPerMod * (double)d; + + vPatterns[i].Add(new QePatternInstance(i, n, PatternID.Dictionary, + dblCost)); + return true; + } + + private static char DecodeLeetChar(char chLeet) + { + if ((chLeet >= '\u00C0') && (chLeet <= '\u00C6')) return 'a'; + if ((chLeet >= '\u00C8') && (chLeet <= '\u00CB')) return 'e'; + if ((chLeet >= '\u00CC') && (chLeet <= '\u00CF')) return 'i'; + if ((chLeet >= '\u00D2') && (chLeet <= '\u00D6')) return 'o'; + if ((chLeet >= '\u00D9') && (chLeet <= '\u00DC')) return 'u'; + if ((chLeet >= '\u00E0') && (chLeet <= '\u00E6')) return 'a'; + if ((chLeet >= '\u00E8') && (chLeet <= '\u00EB')) return 'e'; + if ((chLeet >= '\u00EC') && (chLeet <= '\u00EF')) return 'i'; + if ((chLeet >= '\u00F2') && (chLeet <= '\u00F6')) return 'o'; + if ((chLeet >= '\u00F9') && (chLeet <= '\u00FC')) return 'u'; + + char ch; + switch (chLeet) + { + case '4': + case '@': + case '?': + case '^': + case '\u00AA': ch = 'a'; break; + case '8': + case '\u00DF': ch = 'b'; break; + case '(': + case '{': + case '[': + case '<': + case '\u00A2': + case '\u00A9': + case '\u00C7': + case '\u00E7': ch = 'c'; break; + case '\u00D0': + case '\u00F0': ch = 'd'; break; + case '3': + case '\u20AC': + case '&': + case '\u00A3': ch = 'e'; break; + case '6': + case '9': ch = 'g'; break; + case '#': ch = 'h'; break; + case '1': + case '!': + case '|': + case '\u00A1': + case '\u00A6': ch = 'i'; break; + case '\u00D1': + case '\u00F1': ch = 'n'; break; + case '0': + case '*': + case '\u00A4': // Currency + case '\u00B0': // Degree + case '\u00D8': + case '\u00F8': ch = 'o'; break; + case '\u00AE': ch = 'r'; break; + case '$': + case '5': + case '\u00A7': ch = 's'; break; + case '+': + case '7': ch = 't'; break; + case '\u00B5': ch = 'u'; break; + case '%': + case '\u00D7': ch = 'x'; break; + case '\u00A5': + case '\u00DD': + case '\u00FD': + case '\u00FF': ch = 'y'; break; + case '2': ch = 'z'; break; + default: ch = chLeet; break; + } + + return ch; + } + + private static int HammingDist(char[] v1, int iOffset1, + char[] v2, int iOffset2, int nLength) + { + int nDist = 0; + for (int i = 0; i < nLength; ++i) + { + if (v1[iOffset1 + i] != v2[iOffset2 + i]) ++nDist; + } + + return nDist; + } + + private static void FindRepetitions(char[] vPassword, + List[] vPatterns) + { + int n = vPassword.Length; + char[] v = new char[n]; + Array.Copy(vPassword, v, n); + + char chErased = char.MaxValue; + for (int m = (n / 2); m >= 3; --m) + { + for (int x1 = 0; x1 <= (n - (2 * m)); ++x1) + { + bool bFoundRep = false; + + for (int x2 = (x1 + m); x2 <= (n - m); ++x2) + { + if (PartsEqual(v, x1, x2, m)) + { + double dblCost = Log2(x1 + 1) + Log2(m); + vPatterns[x2].Add(new QePatternInstance(x2, m, + PatternID.Repetition, dblCost)); + + ErasePart(v, x2, m, ref chErased); + bFoundRep = true; + } + } + + if (bFoundRep) ErasePart(v, x1, m, ref chErased); + } + } + + MemUtil.ZeroArray(v); + } + + private static bool PartsEqual(char[] v, int x1, int x2, int nLength) + { + for (int i = 0; i < nLength; ++i) + { + if (v[x1 + i] != v[x2 + i]) return false; + } + + return true; + } + + private static void ErasePart(char[] v, int i, int n, ref char chErased) + { + for (int j = 0; j < n; ++j) + { + v[i + j] = chErased; + --chErased; + } + } + + private static void FindNumbers(char[] vPassword, + List[] vPatterns) + { + int n = vPassword.Length; + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < n; ++i) + { + char ch = vPassword[i]; + if ((ch >= '0') && (ch <= '9')) sb.Append(ch); + else + { + AddNumberPattern(vPatterns, sb, i - sb.Length); + sb.Remove(0, sb.Length); + } + } + AddNumberPattern(vPatterns, sb, n - sb.Length); + } + + private static void AddNumberPattern(List[] vPatterns, + StringBuilder sb, int i) + { + if (sb.Length <= 2) return; + string strNumber = sb.ToString(); + + int nZeros = 0; + for (int j = 0; j < strNumber.Length; ++j) + { + if (strNumber[j] != '0') break; + ++nZeros; + } + + double dblCost = Log2(nZeros + 1); + if (nZeros < strNumber.Length) + { + string strNonZero = strNumber.Substring(nZeros); #if KeePassLibSD try { dblCost += Log2(double.Parse(strNonZero)); } catch(Exception) { Debug.Assert(false); return; } #else - double d; - if(double.TryParse(strNonZero, out d)) - dblCost += Log2(d); - else { Debug.Assert(false); return; } + double d; + if (double.TryParse(strNonZero, out d)) + dblCost += Log2(d); + else { Debug.Assert(false); return; } #endif - } + } - vPatterns[i].Add(new QePatternInstance(i, strNumber.Length, - PatternID.Number, dblCost)); - } + vPatterns[i].Add(new QePatternInstance(i, strNumber.Length, + PatternID.Number, dblCost)); + } - private static void FindDiffSeqs(char[] vPassword, - List[] vPatterns) - { - int d = int.MinValue, p = 0; - string str = new string(vPassword) + new string(char.MaxValue, 1); + private static void FindDiffSeqs(char[] vPassword, + List[] vPatterns) + { + int n = vPassword.Length; + int d = int.MaxValue, p = 0; - for(int i = 1; i < str.Length; ++i) - { - int dCur = (int)str[i] - (int)str[i - 1]; - if(dCur != d) - { - if((i - p) >= 3) // At least 3 chars involved - { - QeCharType ct = GetCharType(str[p]); - double dblCost = ct.CharSize + Log2(i - p - 1); + for (int i = 1; i <= n; ++i) + { + int dCur = ((i == n) ? int.MinValue : + ((int)vPassword[i] - (int)vPassword[i - 1])); + if (dCur != d) + { + if ((i - p) >= 3) // At least 3 chars involved + { + QeCharType ct = GetCharType(vPassword[p]); + double dblCost = ct.CharSize + Log2(i - p - 1); - vPatterns[p].Add(new QePatternInstance(p, - i - p, PatternID.DiffSeq, dblCost)); - } + vPatterns[p].Add(new QePatternInstance(p, + i - p, PatternID.DiffSeq, dblCost)); + } - d = dCur; - p = i - 1; - } - } - } + d = dCur; + p = i - 1; + } + } + } - private static double Log2(double dblValue) - { + private static double Log2(double dblValue) + { #if KeePassLibSD return (Math.Log(dblValue) / Math.Log(2.0)); #else - return Math.Log(dblValue, 2.0); + return Math.Log(dblValue, 2.0); #endif - } - } + } + } } diff --git a/src/KeePassLib2Android/Delegates/Handlers.cs b/src/KeePassLib2Android/Delegates/Handlers.cs index 5e8e3646..7989e837 100644 --- a/src/KeePassLib2Android/Delegates/Handlers.cs +++ b/src/KeePassLib2Android/Delegates/Handlers.cs @@ -46,4 +46,12 @@ namespace KeePassLib.Delegates public delegate void VoidDelegate(); public delegate string StrPwEntryDelegate(string str, PwEntry pe); + + public delegate TResult GFunc(); + public delegate TResult GFunc(T o); + public delegate TResult GFunc(T1 o1, T2 o2); + public delegate TResult GFunc(T1 o1, T2 o2, T3 o3); + public delegate TResult GFunc(T1 o1, T2 o2, T3 o3, T4 o4); + public delegate TResult GFunc(T1 o1, T2 o2, T3 o3, T4 o4, T5 o5); + public delegate TResult GFunc(T1 o1, T2 o2, T3 o3, T4 o4, T5 o5, T6 o6); } diff --git a/src/KeePassLib2Android/Kp2aLog.cs b/src/KeePassLib2Android/Kp2aLog.cs index 93106e13..a32954e2 100644 --- a/src/KeePassLib2Android/Kp2aLog.cs +++ b/src/KeePassLib2Android/Kp2aLog.cs @@ -116,12 +116,23 @@ namespace keepass2android Intent sendIntent = new Intent(); sendIntent.SetAction(Intent.ActionSend); - sendIntent.PutExtra(Intent.ExtraText, File.ReadAllText(LogFilename)); + string logText = File.ReadAllText(LogFilename); + + sendIntent.PutExtra(Intent.ExtraText, logText); sendIntent.PutExtra(Intent.ExtraEmail, "crocoapps@gmail.com"); sendIntent.PutExtra(Intent.ExtraSubject, "Keepass2Android log"); sendIntent.SetType("text/plain"); - ctx.StartActivity(Intent.CreateChooser(sendIntent, "Send log to...")); - } + try + { + ctx.StartActivity(Intent.CreateChooser(sendIntent, "Send log to...")); + } + catch (Exception e) + { + Toast.MakeText(ctx, $"Error sending log of length {logText.Length} bytes: " + e.Message, ToastLength.Long)?.Show(); + + } + + } public static void LogTask(object task, string activityName) { diff --git a/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs b/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs index 930b3eaf..f1430ceb 100644 --- a/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs +++ b/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs @@ -83,6 +83,7 @@ namespace KeePassLib.Serialization if (m_bUsedOnce) throw new InvalidOperationException("Do not reuse KdbxFile objects!"); m_bUsedOnce = true; + Kp2aLog.Log("Starting to load KDBX file..."); #if KDBX_BENCHMARK Stopwatch swTime = Stopwatch.StartNew(); @@ -257,7 +258,8 @@ namespace KeePassLib.Serialization MessageService.ShowInfo("Loading KDBX took " + swTime.ElapsedMilliseconds.ToString() + " ms."); #endif - } + Kp2aLog.Log("Finished loading KDBX file."); + } private void CommonCleanUpRead(List lStreams, HashingStreamEx sHashing) { diff --git a/src/KeePassLib2Android/Utility/MemUtil.cs b/src/KeePassLib2Android/Utility/MemUtil.cs index 0fe591ff..6c44bb1b 100644 --- a/src/KeePassLib2Android/Utility/MemUtil.cs +++ b/src/KeePassLib2Android/Utility/MemUtil.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2017 Dominik Reichl + Copyright (C) 2003-2025 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 @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; #if KeePassLibSD @@ -30,762 +31,852 @@ using KeePassLibSD; using System.IO.Compression; #endif +using KeePassLib.Delegates; + namespace KeePassLib.Utility { - /// - /// Contains static buffer manipulation and string conversion routines. - /// - public static class MemUtil - { + /// + /// Buffer manipulation and conversion routines. + /// + public static class MemUtil + { public static readonly byte[] EmptyByteArray = new byte[0]; - private static readonly uint[] m_vSBox = new uint[256] { - 0xCD2FACB3, 0xE78A7F5C, 0x6F0803FC, 0xBCF6E230, - 0x3A321712, 0x06403DB1, 0xD2F84B95, 0xDF22A6E4, - 0x07CE9E5B, 0x31788A0C, 0xF683F6F4, 0xEA061F49, - 0xFA5C2ACA, 0x4B9E494E, 0xB0AB25BA, 0x767731FC, - 0x261893A7, 0x2B09F2CE, 0x046261E4, 0x41367B4B, - 0x18A7F225, 0x8F923C0E, 0x5EF3A325, 0x28D0435E, - 0x84C22919, 0xED66873C, 0x8CEDE444, 0x7FC47C24, - 0xFCFC6BA3, 0x676F928D, 0xB4147187, 0xD8FB126E, - 0x7D798D17, 0xFF82E424, 0x1712FA5B, 0xABB09DD5, - 0x8156BA63, 0x84E4D969, 0xC937FB9A, 0x2F1E5BFC, - 0x178ECA11, 0x0E71CD5F, 0x52AAC6F4, 0x71EEFC8F, - 0x7090D749, 0x21CACA31, 0x92996378, 0x0939A8A8, - 0xE9EE1934, 0xD2718616, 0xF2500543, 0xB911873C, - 0xD3CB3EEC, 0x2BA0DBEB, 0xB42D0A27, 0xECE67C0F, - 0x302925F0, 0x6114F839, 0xD39E6307, 0xE28970D6, - 0xEB982F99, 0x941B4CDF, 0xC540E550, 0x8124FC45, - 0x98B025C7, 0xE2BF90EA, 0x4F57C976, 0xCF546FE4, - 0x59566DC8, 0xE3F4360D, 0xF5F9D231, 0xD6180B22, - 0xB54E088A, 0xB5DFE6A6, 0x3637A36F, 0x056E9284, - 0xAFF8FBC5, 0x19E01648, 0x8611F043, 0xDAE44337, - 0xF61B6A1C, 0x257ACD9E, 0xDD35F507, 0xEF05CAFA, - 0x05EB4A83, 0xFC25CA92, 0x0A4728E6, 0x9CF150EF, - 0xAEEF67DE, 0xA9472337, 0x57C81EFE, 0x3E5E009F, - 0x02CB03BB, 0x2BA85674, 0xF21DC251, 0x78C34A34, - 0xABB1F5BF, 0xB95A2FBD, 0x1FB47777, 0x9A96E8AC, - 0x5D2D2838, 0x55AAC92A, 0x99EE324E, 0x10F6214B, - 0x58ABDFB1, 0x2008794D, 0xBEC880F0, 0xE75E5341, - 0x88015C34, 0x352D8FBF, 0x622B7F6C, 0xF5C59EA2, - 0x1F759D8E, 0xADE56159, 0xCC7B4C25, 0x5B8BC48C, - 0xB6BD15AF, 0x3C5B5110, 0xE74A7C3D, 0xEE613161, - 0x156A1C67, 0x72C06817, 0xEA0A6F69, 0x4CECF993, - 0xCA9D554C, 0x8E20361F, 0x42D396B9, 0x595DE578, - 0x749D7955, 0xFD1BA5FD, 0x81FC160E, 0xDB97E28C, - 0x7CF148F7, 0x0B0B3CF5, 0x534DE605, 0x46421066, - 0xD4B68DD1, 0x9E479CE6, 0xAE667A9D, 0xBC082082, - 0xB06DD6EF, 0x20F0F23F, 0xB99E1551, 0xF47A2E3A, - 0x71DA50C6, 0x67B65779, 0x2A8CB376, 0x1EA71EEE, - 0x29ABCD50, 0xB6EB0C6B, 0x23C10511, 0x6F3F2144, - 0x6AF23012, 0xF696BD9E, 0xB94099D8, 0xAD5A9C81, - 0x7A0794FA, 0x7EDF59D6, 0x1E72E574, 0x8561913C, - 0x4E4D568F, 0xEECB9928, 0x9C124D2E, 0x0848B82C, - 0xF1CA395F, 0x9DAF43DC, 0xF77EC323, 0x394E9B59, - 0x7E200946, 0x8B811D68, 0x16DA3305, 0xAB8DE2C3, - 0xE6C53B64, 0x98C2D321, 0x88A97D81, 0xA7106419, - 0x8E52F7BF, 0x8ED262AF, 0x7CCA974E, 0xF0933241, - 0x040DD437, 0xE143B3D4, 0x3019F56F, 0xB741521D, - 0xF1745362, 0x4C435F9F, 0xB4214D0D, 0x0B0C348B, - 0x5051D189, 0x4C30447E, 0x7393D722, 0x95CEDD0B, - 0xDD994E80, 0xC3D22ED9, 0x739CD900, 0x131EB9C4, - 0xEF1062B2, 0x4F0DE436, 0x52920073, 0x9A7F3D80, - 0x896E7B1B, 0x2C8BBE5A, 0xBD304F8A, 0xA993E22C, - 0x134C41A0, 0xFA989E00, 0x39CE9726, 0xFB89FCCF, - 0xE8FBAC97, 0xD4063FFC, 0x935A2B5A, 0x44C8EE83, - 0xCB2BC7B6, 0x02989E92, 0x75478BEA, 0x144378D0, - 0xD853C087, 0x8897A34E, 0xDD23629D, 0xBDE2A2A2, - 0x581D8ECC, 0x5DA8AEE8, 0xFF8AAFD0, 0xBA2BCF6E, - 0x4BD98DAC, 0xF2EDB9E4, 0xFA2DC868, 0x47E84661, - 0xECEB1C7D, 0x41705CA4, 0x5982E4D4, 0xEB5204A1, - 0xD196CAFB, 0x6414804D, 0x3ABD4B46, 0x8B494C26, - 0xB432D52B, 0x39C5356B, 0x6EC80BF7, 0x71BE5483, - 0xCEC4A509, 0xE9411D61, 0x52F341E5, 0xD2E6197B, - 0x4F02826C, 0xA9E48838, 0xD1F8F247, 0xE4957FB3, - 0x586CCA99, 0x9A8B6A5B, 0x4998FBEA, 0xF762BE4C, - 0x90DFE33C, 0x9731511E, 0x88C6A82F, 0xDD65A4D4 - }; + internal static readonly ArrayHelperEx ArrayHelperExOfChar = + new ArrayHelperEx(); - /// - /// Convert a hexadecimal string to a byte array. The input string must be - /// even (i.e. its length is a multiple of 2). - /// - /// String containing hexadecimal characters. - /// Returns a byte array. Returns null if the string parameter - /// was null or is an uneven string (i.e. if its length isn't a - /// multiple of 2). - /// Thrown if - /// is null. - public static byte[] HexStringToByteArray(string strHex) - { - if(strHex == null) { Debug.Assert(false); throw new ArgumentNullException("strHex"); } - - int nStrLen = strHex.Length; - if((nStrLen & 1) != 0) { Debug.Assert(false); return null; } - - byte[] pb = new byte[nStrLen / 2]; - byte bt; - char ch; - - for(int i = 0; i < nStrLen; i += 2) - { - ch = strHex[i]; - - if((ch >= '0') && (ch <= '9')) - bt = (byte)(ch - '0'); - else if((ch >= 'a') && (ch <= 'f')) - bt = (byte)(ch - 'a' + 10); - else if((ch >= 'A') && (ch <= 'F')) - bt = (byte)(ch - 'A' + 10); - else { Debug.Assert(false); bt = 0; } - - bt <<= 4; - - ch = strHex[i + 1]; - if((ch >= '0') && (ch <= '9')) - bt += (byte)(ch - '0'); - else if((ch >= 'a') && (ch <= 'f')) - bt += (byte)(ch - 'a' + 10); - else if((ch >= 'A') && (ch <= 'F')) - bt += (byte)(ch - 'A' + 10); - else { Debug.Assert(false); } - - pb[i >> 1] = bt; - } - - return pb; - } - - /// - /// Convert a byte array to a hexadecimal string. - /// - /// Input byte array. - /// Returns the hexadecimal string representing the byte - /// array. Returns null, if the input byte array was null. Returns - /// an empty string, if the input byte array has length 0. - public static string ByteArrayToHexString(byte[] pbArray) - { - if(pbArray == null) return null; - - int nLen = pbArray.Length; - if(nLen == 0) return string.Empty; - - StringBuilder sb = new StringBuilder(); - - byte bt, btHigh, btLow; - for(int i = 0; i < nLen; ++i) - { - bt = pbArray[i]; - btHigh = bt; btHigh >>= 4; - btLow = (byte)(bt & 0x0F); - - if(btHigh >= 10) sb.Append((char)('A' + btHigh - 10)); - else sb.Append((char)('0' + btHigh)); - - if(btLow >= 10) sb.Append((char)('A' + btLow - 10)); - else sb.Append((char)('0' + btLow)); - } - - return sb.ToString(); - } - - /// - /// Decode Base32 strings according to RFC 4648. - /// - public static byte[] ParseBase32(string str) - { - if((str == null) || ((str.Length % 8) != 0)) - { - Debug.Assert(false); - return null; - } - - ulong uMaxBits = (ulong)str.Length * 5UL; - List l = new List((int)(uMaxBits / 8UL) + 1); - Debug.Assert(l.Count == 0); - - for(int i = 0; i < str.Length; i += 8) - { - ulong u = 0; - int nBits = 0; - - for(int j = 0; j < 8; ++j) - { - char ch = str[i + j]; - if(ch == '=') break; - - ulong uValue; - if((ch >= 'A') && (ch <= 'Z')) - uValue = (ulong)(ch - 'A'); - else if((ch >= 'a') && (ch <= 'z')) - uValue = (ulong)(ch - 'a'); - else if((ch >= '2') && (ch <= '7')) - uValue = (ulong)(ch - '2') + 26UL; - else { Debug.Assert(false); return null; } - - u <<= 5; - u += uValue; - nBits += 5; - } - - int nBitsTooMany = (nBits % 8); - u >>= nBitsTooMany; - nBits -= nBitsTooMany; - Debug.Assert((nBits % 8) == 0); - - int idxNewBytes = l.Count; - while(nBits > 0) - { - l.Add((byte)(u & 0xFF)); - u >>= 8; - nBits -= 8; - } - l.Reverse(idxNewBytes, l.Count - idxNewBytes); - } - - return l.ToArray(); - } - - /// - /// Set all bytes in a byte array to zero. - /// - /// Input array. All bytes of this array - /// will be set to zero. + private const MethodImplOptions MioNoOptimize = #if KeePassLibSD - [MethodImpl(MethodImplOptions.NoInlining)] + MethodImplOptions.NoInlining; #else - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] + (MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining); #endif - public static void ZeroByteArray(byte[] pbArray) - { - Debug.Assert(pbArray != null); - if(pbArray == null) throw new ArgumentNullException("pbArray"); - - Array.Clear(pbArray, 0, pbArray.Length); - } - - /// - /// Set all elements of an array to the default value. - /// - /// Input array. -#if KeePassLibSD - [MethodImpl(MethodImplOptions.NoInlining)] -#else - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] -#endif - public static void ZeroArray(T[] v) - { - if(v == null) { Debug.Assert(false); throw new ArgumentNullException("v"); } - - Array.Clear(v, 0, v.Length); - } - - /// - /// Convert 2 bytes to a 16-bit unsigned integer (little-endian). - /// - public static ushort BytesToUInt16(byte[] pb) - { - Debug.Assert((pb != null) && (pb.Length == 2)); - if(pb == null) throw new ArgumentNullException("pb"); - if(pb.Length != 2) throw new ArgumentOutOfRangeException("pb"); - - return (ushort)((ushort)pb[0] | ((ushort)pb[1] << 8)); - } - - /// - /// Convert 2 bytes to a 16-bit unsigned integer (little-endian). - /// - public static ushort BytesToUInt16(byte[] pb, int iOffset) - { - if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } - if((iOffset < 0) || ((iOffset + 1) >= pb.Length)) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("iOffset"); - } - - return (ushort)((ushort)pb[iOffset] | ((ushort)pb[iOffset + 1] << 8)); - } - - /// - /// Convert 4 bytes to a 32-bit unsigned integer (little-endian). - /// - public static uint BytesToUInt32(byte[] pb) - { - Debug.Assert((pb != null) && (pb.Length == 4)); - if(pb == null) throw new ArgumentNullException("pb"); - if(pb.Length != 4) throw new ArgumentOutOfRangeException("pb"); - - return ((uint)pb[0] | ((uint)pb[1] << 8) | ((uint)pb[2] << 16) | - ((uint)pb[3] << 24)); - } - - /// - /// Convert 4 bytes to a 32-bit unsigned integer (little-endian). - /// - public static uint BytesToUInt32(byte[] pb, int iOffset) - { - if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } - if((iOffset < 0) || ((iOffset + 3) >= pb.Length)) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("iOffset"); - } - - return ((uint)pb[iOffset] | ((uint)pb[iOffset + 1] << 8) | - ((uint)pb[iOffset + 2] << 16) | ((uint)pb[iOffset + 3] << 24)); - } - - /// - /// Convert 8 bytes to a 64-bit unsigned integer (little-endian). - /// - public static ulong BytesToUInt64(byte[] pb) - { - Debug.Assert((pb != null) && (pb.Length == 8)); - if(pb == null) throw new ArgumentNullException("pb"); - if(pb.Length != 8) throw new ArgumentOutOfRangeException("pb"); - - return ((ulong)pb[0] | ((ulong)pb[1] << 8) | ((ulong)pb[2] << 16) | - ((ulong)pb[3] << 24) | ((ulong)pb[4] << 32) | ((ulong)pb[5] << 40) | - ((ulong)pb[6] << 48) | ((ulong)pb[7] << 56)); - } - - /// - /// Convert 8 bytes to a 64-bit unsigned integer (little-endian). - /// - public static ulong BytesToUInt64(byte[] pb, int iOffset) - { - if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } - if((iOffset < 0) || ((iOffset + 7) >= pb.Length)) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("iOffset"); - } - - // if(BitConverter.IsLittleEndian) - // return BitConverter.ToUInt64(pb, iOffset); - - return ((ulong)pb[iOffset] | ((ulong)pb[iOffset + 1] << 8) | - ((ulong)pb[iOffset + 2] << 16) | ((ulong)pb[iOffset + 3] << 24) | - ((ulong)pb[iOffset + 4] << 32) | ((ulong)pb[iOffset + 5] << 40) | - ((ulong)pb[iOffset + 6] << 48) | ((ulong)pb[iOffset + 7] << 56)); - } - - public static int BytesToInt32(byte[] pb) - { - return (int)BytesToUInt32(pb); - } - - public static int BytesToInt32(byte[] pb, int iOffset) - { - return (int)BytesToUInt32(pb, iOffset); - } - - public static long BytesToInt64(byte[] pb) - { - return (long)BytesToUInt64(pb); - } - - public static long BytesToInt64(byte[] pb, int iOffset) - { - return (long)BytesToUInt64(pb, iOffset); - } - - /// - /// Convert a 16-bit unsigned integer to 2 bytes (little-endian). - /// - public static byte[] UInt16ToBytes(ushort uValue) - { - byte[] pb = new byte[2]; - - unchecked - { - pb[0] = (byte)uValue; - pb[1] = (byte)(uValue >> 8); - } - - return pb; - } - - /// - /// Convert a 32-bit unsigned integer to 4 bytes (little-endian). - /// - public static byte[] UInt32ToBytes(uint uValue) - { - byte[] pb = new byte[4]; - - unchecked - { - pb[0] = (byte)uValue; - pb[1] = (byte)(uValue >> 8); - pb[2] = (byte)(uValue >> 16); - pb[3] = (byte)(uValue >> 24); - } - - return pb; - } - - /// - /// Convert a 32-bit unsigned integer to 4 bytes (little-endian). - /// - public static void UInt32ToBytesEx(uint uValue, byte[] pb, int iOffset) - { - if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } - if((iOffset < 0) || ((iOffset + 3) >= pb.Length)) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("iOffset"); - } - - unchecked - { - pb[iOffset] = (byte)uValue; - pb[iOffset + 1] = (byte)(uValue >> 8); - pb[iOffset + 2] = (byte)(uValue >> 16); - pb[iOffset + 3] = (byte)(uValue >> 24); - } - } - - /// - /// Convert a 64-bit unsigned integer to 8 bytes (little-endian). - /// - public static byte[] UInt64ToBytes(ulong uValue) - { - byte[] pb = new byte[8]; - - unchecked - { - pb[0] = (byte)uValue; - pb[1] = (byte)(uValue >> 8); - pb[2] = (byte)(uValue >> 16); - pb[3] = (byte)(uValue >> 24); - pb[4] = (byte)(uValue >> 32); - pb[5] = (byte)(uValue >> 40); - pb[6] = (byte)(uValue >> 48); - pb[7] = (byte)(uValue >> 56); - } - - return pb; - } - - /// - /// Convert a 64-bit unsigned integer to 8 bytes (little-endian). - /// - public static void UInt64ToBytesEx(ulong uValue, byte[] pb, int iOffset) - { - if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } - if((iOffset < 0) || ((iOffset + 7) >= pb.Length)) - { - Debug.Assert(false); - throw new ArgumentOutOfRangeException("iOffset"); - } - - unchecked - { - pb[iOffset] = (byte)uValue; - pb[iOffset + 1] = (byte)(uValue >> 8); - pb[iOffset + 2] = (byte)(uValue >> 16); - pb[iOffset + 3] = (byte)(uValue >> 24); - pb[iOffset + 4] = (byte)(uValue >> 32); - pb[iOffset + 5] = (byte)(uValue >> 40); - pb[iOffset + 6] = (byte)(uValue >> 48); - pb[iOffset + 7] = (byte)(uValue >> 56); - } - } - - public static byte[] Int32ToBytes(int iValue) - { - return UInt32ToBytes((uint)iValue); - } - - public static byte[] Int64ToBytes(long lValue) - { - return UInt64ToBytes((ulong)lValue); - } - - public static uint RotateLeft32(uint u, int nBits) - { - return ((u << nBits) | (u >> (32 - nBits))); - } - - public static uint RotateRight32(uint u, int nBits) - { - return ((u >> nBits) | (u << (32 - nBits))); - } - - public static ulong RotateLeft64(ulong u, int nBits) - { - return ((u << nBits) | (u >> (64 - nBits))); - } - - public static ulong RotateRight64(ulong u, int nBits) - { - return ((u >> nBits) | (u << (64 - nBits))); - } - - public static bool ArraysEqual(byte[] x, byte[] y) - { - // Return false if one of them is null (not comparable)! - if((x == null) || (y == null)) { Debug.Assert(false); return false; } - - if(x.Length != y.Length) return false; - - for(int i = 0; i < x.Length; ++i) - { - if(x[i] != y[i]) return false; - } - - return true; - } - - public static void XorArray(byte[] pbSource, int iSourceOffset, - byte[] pbBuffer, int iBufferOffset, int cb) - { - if(pbSource == null) throw new ArgumentNullException("pbSource"); - if(iSourceOffset < 0) throw new ArgumentOutOfRangeException("iSourceOffset"); - if(pbBuffer == null) throw new ArgumentNullException("pbBuffer"); - if(iBufferOffset < 0) throw new ArgumentOutOfRangeException("iBufferOffset"); - if(cb < 0) throw new ArgumentOutOfRangeException("cb"); - if(iSourceOffset > (pbSource.Length - cb)) - throw new ArgumentOutOfRangeException("cb"); - if(iBufferOffset > (pbBuffer.Length - cb)) - throw new ArgumentOutOfRangeException("cb"); - - for(int i = 0; i < cb; ++i) - pbBuffer[iBufferOffset + i] ^= pbSource[iSourceOffset + i]; - } - - /// - /// Fast hash that can be used e.g. for hash tables. - /// The algorithm might change in the future; do not store - /// the hashes for later use. - /// - public static uint Hash32(byte[] v, int iStart, int iLength) - { - uint u = 0x326F637B; - - if(v == null) { Debug.Assert(false); return u; } - if(iStart < 0) { Debug.Assert(false); return u; } - if(iLength < 0) { Debug.Assert(false); return u; } - - int m = iStart + iLength; - if(m > v.Length) { Debug.Assert(false); return u; } - - for(int i = iStart; i < m; ++i) - { - u ^= m_vSBox[v[i]]; - u *= 3; - } - - return u; - } - - public static void CopyStream(Stream sSource, Stream sTarget) - { - Debug.Assert((sSource != null) && (sTarget != null)); - if(sSource == null) throw new ArgumentNullException("sSource"); - if(sTarget == null) throw new ArgumentNullException("sTarget"); - - const int nBufSize = 4096; - byte[] pbBuf = new byte[nBufSize]; - - while(true) - { - int nRead = sSource.Read(pbBuf, 0, nBufSize); - if(nRead == 0) break; - - sTarget.Write(pbBuf, 0, nRead); - } - - // Do not close any of the streams - } - - public static byte[] Read(Stream s, int nCount) - { - if(s == null) throw new ArgumentNullException("s"); - if(nCount < 0) throw new ArgumentOutOfRangeException("nCount"); - - byte[] pb = new byte[nCount]; - int iOffset = 0; - while(nCount > 0) - { - int iRead = s.Read(pb, iOffset, nCount); - if(iRead == 0) break; - - iOffset += iRead; - nCount -= iRead; - } - - if(iOffset != pb.Length) - { - byte[] pbPart = new byte[iOffset]; - Array.Copy(pb, pbPart, iOffset); - return pbPart; - } - - return pb; - } - - public static void Write(Stream s, byte[] pbData) - { - if(s == null) { Debug.Assert(false); return; } - if(pbData == null) { Debug.Assert(false); return; } - - Debug.Assert(pbData.Length >= 0); - if(pbData.Length > 0) s.Write(pbData, 0, pbData.Length); - } - - public static byte[] Compress(byte[] pbData) - { - if(pbData == null) throw new ArgumentNullException("pbData"); - if(pbData.Length == 0) return pbData; - - byte[] pbCompressed; - using(MemoryStream msSource = new MemoryStream(pbData, false)) - { - using(MemoryStream msCompressed = new MemoryStream()) - { - using(GZipStream gz = new GZipStream(msCompressed, - CompressionMode.Compress)) - { - MemUtil.CopyStream(msSource, gz); - } - - pbCompressed = msCompressed.ToArray(); - } - } - - return pbCompressed; - } - - public static byte[] Decompress(byte[] pbCompressed) - { - if(pbCompressed == null) throw new ArgumentNullException("pbCompressed"); - if(pbCompressed.Length == 0) return pbCompressed; - - byte[] pbData; - using(MemoryStream msData = new MemoryStream()) - { - using(MemoryStream msCompressed = new MemoryStream(pbCompressed, false)) - { - using(GZipStream gz = new GZipStream(msCompressed, - CompressionMode.Decompress)) - { - MemUtil.CopyStream(gz, msData); - } - } - - pbData = msData.ToArray(); - } - - return pbData; - } - - public static int IndexOf(T[] vHaystack, T[] vNeedle) - where T : IEquatable - { - if(vHaystack == null) throw new ArgumentNullException("vHaystack"); - if(vNeedle == null) throw new ArgumentNullException("vNeedle"); - if(vNeedle.Length == 0) return 0; - - for(int i = 0; i <= (vHaystack.Length - vNeedle.Length); ++i) - { - bool bFound = true; - for(int m = 0; m < vNeedle.Length; ++m) - { - if(!vHaystack[i + m].Equals(vNeedle[m])) - { - bFound = false; - break; - } - } - if(bFound) return i; - } - - return -1; - } - - public static T[] Mid(T[] v, int iOffset, int iLength) - { - if(v == null) throw new ArgumentNullException("v"); - if(iOffset < 0) throw new ArgumentOutOfRangeException("iOffset"); - if(iLength < 0) throw new ArgumentOutOfRangeException("iLength"); - if((iOffset + iLength) > v.Length) throw new ArgumentException(); - - T[] r = new T[iLength]; - Array.Copy(v, iOffset, r, 0, iLength); - return r; - } - - public static IEnumerable Union(IEnumerable a, IEnumerable b, - IEqualityComparer cmp) - { - if(a == null) throw new ArgumentNullException("a"); - if(b == null) throw new ArgumentNullException("b"); - - Dictionary d = ((cmp != null) ? - (new Dictionary(cmp)) : (new Dictionary())); - - foreach(T ta in a) - { - if(d.ContainsKey(ta)) continue; // Prevent duplicates - - d[ta] = true; - yield return ta; - } - - foreach(T tb in b) - { - if(d.ContainsKey(tb)) continue; // Prevent duplicates - - d[tb] = true; - yield return tb; - } - - yield break; - } - - public static IEnumerable Intersect(IEnumerable a, IEnumerable b, - IEqualityComparer cmp) - { - if(a == null) throw new ArgumentNullException("a"); - if(b == null) throw new ArgumentNullException("b"); - - Dictionary d = ((cmp != null) ? - (new Dictionary(cmp)) : (new Dictionary())); - - foreach(T tb in b) { d[tb] = true; } - - foreach(T ta in a) - { - if(d.Remove(ta)) // Prevent duplicates - yield return ta; - } - - yield break; - } - - public static IEnumerable Except(IEnumerable a, IEnumerable b, - IEqualityComparer cmp) - { - if(a == null) throw new ArgumentNullException("a"); - if(b == null) throw new ArgumentNullException("b"); - - Dictionary d = ((cmp != null) ? - (new Dictionary(cmp)) : (new Dictionary())); - - foreach(T tb in b) { d[tb] = true; } - - foreach(T ta in a) - { - if(d.ContainsKey(ta)) continue; - - d[ta] = true; // Prevent duplicates - yield return ta; - } - - yield break; - } + + /// + /// Convert a hexadecimal string to a byte array. The input string must be + /// even (i.e. its length is a multiple of 2). + /// + /// String containing hexadecimal characters. + /// Returns a byte array. Returns null if the string parameter + /// was null or is an uneven string (i.e. if its length isn't a + /// multiple of 2). + /// Thrown if + /// is null. + public static byte[] HexStringToByteArray(string strHex) + { + if (strHex == null) { Debug.Assert(false); throw new ArgumentNullException("strHex"); } + + int nStrLen = strHex.Length; + if ((nStrLen & 1) != 0) { Debug.Assert(false); return null; } + + byte[] pb = new byte[nStrLen / 2]; + byte bt; + char ch; + + for (int i = 0; i < nStrLen; i += 2) + { + ch = strHex[i]; + + if ((ch >= '0') && (ch <= '9')) + bt = (byte)(ch - '0'); + else if ((ch >= 'a') && (ch <= 'f')) + bt = (byte)(ch - 'a' + 10); + else if ((ch >= 'A') && (ch <= 'F')) + bt = (byte)(ch - 'A' + 10); + else { Debug.Assert(false); bt = 0; } + + bt <<= 4; + + ch = strHex[i + 1]; + if ((ch >= '0') && (ch <= '9')) + bt |= (byte)(ch - '0'); + else if ((ch >= 'a') && (ch <= 'f')) + bt |= (byte)(ch - 'a' + 10); + else if ((ch >= 'A') && (ch <= 'F')) + bt |= (byte)(ch - 'A' + 10); + else { Debug.Assert(false); } + + pb[i >> 1] = bt; + } + + return pb; + } + + /// + /// Convert a byte array to a hexadecimal string. + /// + /// Input byte array. + /// Returns the hexadecimal string representing the byte + /// array. Returns null, if the input byte array was null. Returns + /// an empty string, if the input byte array has length 0. + public static string ByteArrayToHexString(byte[] pbArray) + { + if (pbArray == null) return null; + + int nLen = pbArray.Length; + if (nLen == 0) return string.Empty; + + StringBuilder sb = new StringBuilder(); + + byte bt, btHigh, btLow; + for (int i = 0; i < nLen; ++i) + { + bt = pbArray[i]; + btHigh = bt; btHigh >>= 4; + btLow = (byte)(bt & 0x0F); + + if (btHigh >= 10) sb.Append((char)('A' + btHigh - 10)); + else sb.Append((char)('0' + btHigh)); + + if (btLow >= 10) sb.Append((char)('A' + btLow - 10)); + else sb.Append((char)('0' + btLow)); + } + + return sb.ToString(); + } + + /// + /// Decode Base32 strings according to RFC 4648. + /// + public static byte[] ParseBase32(string str) + { + if ((str == null) || ((str.Length % 8) != 0)) + { + Debug.Assert(false); + return null; + } + + ulong uMaxBits = (ulong)str.Length * 5UL; + List l = new List((int)(uMaxBits / 8UL) + 1); + Debug.Assert(l.Count == 0); + + for (int i = 0; i < str.Length; i += 8) + { + ulong u = 0; + int nBits = 0; + + for (int j = 0; j < 8; ++j) + { + char ch = str[i + j]; + if (ch == '=') break; + + ulong uValue; + if ((ch >= 'A') && (ch <= 'Z')) + uValue = (ulong)(ch - 'A'); + else if ((ch >= 'a') && (ch <= 'z')) + uValue = (ulong)(ch - 'a'); + else if ((ch >= '2') && (ch <= '7')) + uValue = (ulong)(ch - '2') + 26UL; + else { Debug.Assert(false); return null; } + + u <<= 5; + u += uValue; + nBits += 5; + } + + int nBitsTooMany = (nBits % 8); + u >>= nBitsTooMany; + nBits -= nBitsTooMany; + Debug.Assert((nBits % 8) == 0); + + int idxNewBytes = l.Count; + while (nBits > 0) + { + l.Add((byte)(u & 0xFF)); + u >>= 8; + nBits -= 8; + } + l.Reverse(idxNewBytes, l.Count - idxNewBytes); + } + + return l.ToArray(); + } + + internal static byte[] ParseBase32(string str, bool bAutoPad) + { + if (str == null) { Debug.Assert(false); return null; } + + // https://sourceforge.net/p/keepass/discussion/329220/thread/59b61fddea/ + if (bAutoPad && ((str.Length % 8) != 0)) + str = str.PadRight((str.Length & ~7) + 8, '='); + + return ParseBase32(str); + } + + /// + /// Set all bytes in a byte array to zero. + /// + /// Input array. All bytes of this array + /// will be set to zero. + [MethodImpl(MioNoOptimize)] + public static void ZeroByteArray(byte[] pbArray) + { + if (pbArray == null) { Debug.Assert(false); return; } + + Array.Clear(pbArray, 0, pbArray.Length); + } + + /// + /// Set all elements of an array to the default value. + /// + /// Input array. + [MethodImpl(MioNoOptimize)] + public static void ZeroArray(T[] v) + { + if (v == null) { Debug.Assert(false); return; } + + Array.Clear(v, 0, v.Length); + } + + private static byte[] g_pbZero = null; + [MethodImpl(MioNoOptimize)] + public static void ZeroMemory(IntPtr pb, long cb) + { + if (pb == IntPtr.Zero) { Debug.Assert(false); return; } + if (cb < 0) { Debug.Assert(false); return; } + + byte[] pbZero = g_pbZero; + if (pbZero == null) + { + pbZero = new byte[4096]; + g_pbZero = pbZero; + } + + long cbZero = pbZero.Length; + + while (cb != 0) + { + long cbBlock = Math.Min(cb, cbZero); + + Marshal.Copy(pbZero, 0, pb, (int)cbBlock); + + pb = AddPtr(pb, cbBlock); + cb -= cbBlock; + } + } + + /// + /// Convert 2 bytes to a 16-bit unsigned integer (little-endian). + /// + public static ushort BytesToUInt16(byte[] pb) + { + Debug.Assert((pb != null) && (pb.Length == 2)); + if (pb == null) throw new ArgumentNullException("pb"); + if (pb.Length != 2) throw new ArgumentOutOfRangeException("pb"); + + return (ushort)((ushort)pb[0] | ((ushort)pb[1] << 8)); + } + + /// + /// Convert 2 bytes to a 16-bit unsigned integer (little-endian). + /// + public static ushort BytesToUInt16(byte[] pb, int iOffset) + { + if (pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } + if ((iOffset < 0) || ((iOffset + 1) >= pb.Length)) + { + Debug.Assert(false); + throw new ArgumentOutOfRangeException("iOffset"); + } + + return (ushort)((ushort)pb[iOffset] | ((ushort)pb[iOffset + 1] << 8)); + } + + /// + /// Convert 4 bytes to a 32-bit unsigned integer (little-endian). + /// + public static uint BytesToUInt32(byte[] pb) + { + Debug.Assert((pb != null) && (pb.Length == 4)); + if (pb == null) throw new ArgumentNullException("pb"); + if (pb.Length != 4) throw new ArgumentOutOfRangeException("pb"); + + return ((uint)pb[0] | ((uint)pb[1] << 8) | ((uint)pb[2] << 16) | + ((uint)pb[3] << 24)); + } + + /// + /// Convert 4 bytes to a 32-bit unsigned integer (little-endian). + /// + public static uint BytesToUInt32(byte[] pb, int iOffset) + { + if (pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } + if ((iOffset < 0) || ((iOffset + 3) >= pb.Length)) + { + Debug.Assert(false); + throw new ArgumentOutOfRangeException("iOffset"); + } + + return ((uint)pb[iOffset] | ((uint)pb[iOffset + 1] << 8) | + ((uint)pb[iOffset + 2] << 16) | ((uint)pb[iOffset + 3] << 24)); + } + + /// + /// Convert 8 bytes to a 64-bit unsigned integer (little-endian). + /// + public static ulong BytesToUInt64(byte[] pb) + { + Debug.Assert((pb != null) && (pb.Length == 8)); + if (pb == null) throw new ArgumentNullException("pb"); + if (pb.Length != 8) throw new ArgumentOutOfRangeException("pb"); + + return ((ulong)pb[0] | ((ulong)pb[1] << 8) | ((ulong)pb[2] << 16) | + ((ulong)pb[3] << 24) | ((ulong)pb[4] << 32) | ((ulong)pb[5] << 40) | + ((ulong)pb[6] << 48) | ((ulong)pb[7] << 56)); + } + + /// + /// Convert 8 bytes to a 64-bit unsigned integer (little-endian). + /// + public static ulong BytesToUInt64(byte[] pb, int iOffset) + { + if (pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } + if ((iOffset < 0) || ((iOffset + 7) >= pb.Length)) + { + Debug.Assert(false); + throw new ArgumentOutOfRangeException("iOffset"); + } + + // if(BitConverter.IsLittleEndian) + // return BitConverter.ToUInt64(pb, iOffset); + + return ((ulong)pb[iOffset] | ((ulong)pb[iOffset + 1] << 8) | + ((ulong)pb[iOffset + 2] << 16) | ((ulong)pb[iOffset + 3] << 24) | + ((ulong)pb[iOffset + 4] << 32) | ((ulong)pb[iOffset + 5] << 40) | + ((ulong)pb[iOffset + 6] << 48) | ((ulong)pb[iOffset + 7] << 56)); + } + + public static int BytesToInt32(byte[] pb) + { + return (int)BytesToUInt32(pb); + } + + public static int BytesToInt32(byte[] pb, int iOffset) + { + return (int)BytesToUInt32(pb, iOffset); + } + + public static long BytesToInt64(byte[] pb) + { + return (long)BytesToUInt64(pb); + } + + public static long BytesToInt64(byte[] pb, int iOffset) + { + return (long)BytesToUInt64(pb, iOffset); + } + + /// + /// Convert a 16-bit unsigned integer to 2 bytes (little-endian). + /// + public static byte[] UInt16ToBytes(ushort uValue) + { + return new byte[2] { (byte)uValue, (byte)(uValue >> 8) }; + } + + /// + /// Convert a 32-bit unsigned integer to 4 bytes (little-endian). + /// + public static byte[] UInt32ToBytes(uint uValue) + { + return new byte[4] { (byte)uValue, (byte)(uValue >> 8), + (byte)(uValue >> 16), (byte)(uValue >> 24) }; + } + + /// + /// Convert a 32-bit unsigned integer to 4 bytes (little-endian). + /// + public static void UInt32ToBytesEx(uint uValue, byte[] pb, int iOffset) + { + if (pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } + if ((iOffset < 0) || (iOffset >= (pb.Length - 3))) + { + Debug.Assert(false); + throw new ArgumentOutOfRangeException("iOffset"); + } + + pb[iOffset] = (byte)uValue; + pb[iOffset + 1] = (byte)(uValue >> 8); + pb[iOffset + 2] = (byte)(uValue >> 16); + pb[iOffset + 3] = (byte)(uValue >> 24); + } + + /// + /// Convert a 64-bit unsigned integer to 8 bytes (little-endian). + /// + public static byte[] UInt64ToBytes(ulong uValue) + { + return new byte[8] { (byte)uValue, (byte)(uValue >> 8), + (byte)(uValue >> 16), (byte)(uValue >> 24), + (byte)(uValue >> 32), (byte)(uValue >> 40), + (byte)(uValue >> 48), (byte)(uValue >> 56) }; + } + + /// + /// Convert a 64-bit unsigned integer to 8 bytes (little-endian). + /// + public static void UInt64ToBytesEx(ulong uValue, byte[] pb, int iOffset) + { + if (pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } + if ((iOffset < 0) || (iOffset >= (pb.Length - 7))) + { + Debug.Assert(false); + throw new ArgumentOutOfRangeException("iOffset"); + } + + pb[iOffset] = (byte)uValue; + pb[iOffset + 1] = (byte)(uValue >> 8); + pb[iOffset + 2] = (byte)(uValue >> 16); + pb[iOffset + 3] = (byte)(uValue >> 24); + pb[iOffset + 4] = (byte)(uValue >> 32); + pb[iOffset + 5] = (byte)(uValue >> 40); + pb[iOffset + 6] = (byte)(uValue >> 48); + pb[iOffset + 7] = (byte)(uValue >> 56); + } + + public static byte[] Int32ToBytes(int iValue) + { + return UInt32ToBytes((uint)iValue); + } + + public static void Int32ToBytesEx(int iValue, byte[] pb, int iOffset) + { + UInt32ToBytesEx((uint)iValue, pb, iOffset); + } + + public static byte[] Int64ToBytes(long lValue) + { + return UInt64ToBytes((ulong)lValue); + } + + public static void Int64ToBytesEx(long lValue, byte[] pb, int iOffset) + { + UInt64ToBytesEx((ulong)lValue, pb, iOffset); + } + + public static uint RotateLeft32(uint u, int nBits) + { + return ((u << nBits) | (u >> (32 - nBits))); + } + + public static uint RotateRight32(uint u, int nBits) + { + return ((u >> nBits) | (u << (32 - nBits))); + } + + public static ulong RotateLeft64(ulong u, int nBits) + { + return ((u << nBits) | (u >> (64 - nBits))); + } + + public static ulong RotateRight64(ulong u, int nBits) + { + return ((u >> nBits) | (u << (64 - nBits))); + } + + private static void AddVersionComponent(ref ulong uVersion, int iValue) + { + if (iValue < 0) iValue = 0; + else if (iValue > 0xFFFF) { Debug.Assert(false); iValue = 0xFFFF; } + + uVersion = (uVersion << 16) | (uint)iValue; + } + + internal static ulong VersionToUInt64(Version v) + { + if (v == null) { Debug.Assert(false); return 0; } + + ulong u = 0; + AddVersionComponent(ref u, v.Major); + AddVersionComponent(ref u, v.Minor); + AddVersionComponent(ref u, v.Build); + AddVersionComponent(ref u, v.Revision); + return u; + } + + public static bool ArraysEqual(byte[] x, byte[] y) + { + // Return false if one of them is null (not comparable)! + if ((x == null) || (y == null)) { Debug.Assert(false); return false; } + + int cb = x.Length; + if (cb != y.Length) return false; + + for (int i = 0; i < cb; ++i) + { + if (x[i] != y[i]) return false; + } + + return true; + } + + public static void XorArray(byte[] pbSource, int iSourceOffset, + byte[] pbBuffer, int iBufferOffset, int cb) + { + if (pbSource == null) throw new ArgumentNullException("pbSource"); + if (iSourceOffset < 0) throw new ArgumentOutOfRangeException("iSourceOffset"); + if (pbBuffer == null) throw new ArgumentNullException("pbBuffer"); + if (iBufferOffset < 0) throw new ArgumentOutOfRangeException("iBufferOffset"); + if (cb < 0) throw new ArgumentOutOfRangeException("cb"); + if (iSourceOffset > (pbSource.Length - cb)) + throw new ArgumentOutOfRangeException("cb"); + if (iBufferOffset > (pbBuffer.Length - cb)) + throw new ArgumentOutOfRangeException("cb"); + + for (int i = 0; i < cb; ++i) + pbBuffer[iBufferOffset + i] ^= pbSource[iSourceOffset + i]; + } + + /// + /// Fast 32-bit hash (e.g. for hash tables). + /// The algorithm might change in the future; do not store + /// the hashes for later use. + /// + public static uint Hash32(byte[] pb, int iOffset, int cb) + { + const ulong hI = 0x4295DC458269ED9DUL; + const uint hI32 = (uint)(hI >> 32); + + if (pb == null) { Debug.Assert(false); return hI32; } + if (iOffset < 0) { Debug.Assert(false); return hI32; } + if (cb < 0) { Debug.Assert(false); return hI32; } + + int m = iOffset + cb; + if ((m < 0) || (m > pb.Length)) { Debug.Assert(false); return hI32; } + + int m4 = iOffset + (cb & ~3), cbR = cb & 3; + ulong h = hI; + + for (int i = iOffset; i < m4; i += 4) + h = (pb[i] ^ ((ulong)pb[i + 1] << 8) ^ ((ulong)pb[i + 2] << 16) ^ + ((ulong)pb[i + 3] << 24) ^ h) * 0x5EA4A1E35C8ACDA3UL; + + switch (cbR) + { + case 1: + Debug.Assert(m4 == (m - 1)); + h = (pb[m4] ^ h) * 0x54A1CC5970AF27BBUL; + break; + case 2: + Debug.Assert(m4 == (m - 2)); + h = (pb[m4] ^ ((ulong)pb[m4 + 1] << 8) ^ h) * + 0x6C45CB2537A4271DUL; + break; + case 3: + Debug.Assert(m4 == (m - 3)); + h = (pb[m4] ^ ((ulong)pb[m4 + 1] << 8) ^ + ((ulong)pb[m4 + 2] << 16) ^ h) * 0x59B8E8939E19695DUL; + break; + default: + Debug.Assert(m4 == m); + break; + } + + Debug.Assert((cb != 0) || ((uint)(h >> 32) == hI32)); + return (uint)(h >> 32); + } + + internal static uint Hash32Ex(T[] v, int iOffset, int c) + { + const ulong hI = 0x4295DC458269ED9DUL; + const uint hI32 = (uint)(hI >> 32); + + if (v == null) { Debug.Assert(false); return hI32; } + if (iOffset < 0) { Debug.Assert(false); return hI32; } + if (c < 0) { Debug.Assert(false); return hI32; } + + int m = iOffset + c; + if ((m < 0) || (m > v.Length)) { Debug.Assert(false); return hI32; } + + ulong h = hI; + + for (int i = iOffset; i < m; ++i) + h = (h ^ (uint)v[i].GetHashCode()) * 0x5EA4A1E35C8ACDA3UL; + + Debug.Assert((c != 0) || ((uint)(h >> 32) == hI32)); + return (uint)(h >> 32); + } + + internal static ulong Hash64(int[] v, int iOffset, int ci) + { + ulong h = 0x4295DC458269ED9DUL; + + if (v == null) { Debug.Assert(false); return h; } + if (iOffset < 0) { Debug.Assert(false); return h; } + if (ci < 0) { Debug.Assert(false); return h; } + + int m = iOffset + ci; + if ((m < 0) || (m > v.Length)) { Debug.Assert(false); return h; } + + for (int i = iOffset; i < m; ++i) + h = (h ^ (uint)v[i]) * 0x5EA4A1E35C8ACDA3UL; + + return ((h ^ (h >> 32)) * 0x59B8E8939E19695DUL); + } + + public static void CopyStream(Stream sSource, Stream sTarget) + { + Debug.Assert((sSource != null) && (sTarget != null)); + if (sSource == null) throw new ArgumentNullException("sSource"); + if (sTarget == null) throw new ArgumentNullException("sTarget"); + + const int cbBuf = 4096; + byte[] pbBuf = new byte[cbBuf]; + + while (true) + { + int cbRead = sSource.Read(pbBuf, 0, cbBuf); + if (cbRead == 0) break; + + sTarget.Write(pbBuf, 0, cbRead); + } + + // Do not close any of the streams + } + + public static byte[] Read(Stream s) + { + if (s == null) throw new ArgumentNullException("s"); + + using (MemoryStream ms = new MemoryStream()) + { + CopyStream(s, ms); + return ms.ToArray(); + } + } + + public static byte[] Read(Stream s, int nCount) + { + if (s == null) throw new ArgumentNullException("s"); + if (nCount < 0) throw new ArgumentOutOfRangeException("nCount"); + + byte[] pb = new byte[nCount]; + int iOffset = 0; + while (nCount > 0) + { + int iRead = s.Read(pb, iOffset, nCount); + if (iRead == 0) break; + + iOffset += iRead; + nCount -= iRead; + } + + if (iOffset != pb.Length) + { + byte[] pbPart = new byte[iOffset]; + Array.Copy(pb, pbPart, iOffset); + return pbPart; + } + + return pb; + } + + internal static string ReadString(Stream s, Encoding enc) + { + if (s == null) throw new ArgumentNullException("s"); + if (enc == null) throw new ArgumentNullException("enc"); + + using (StreamReader sr = new StreamReader(s, enc, true)) + { + return sr.ReadToEnd(); + } + } + + public static void Write(Stream s, byte[] pbData) + { + if (s == null) { Debug.Assert(false); return; } + if (pbData == null) { Debug.Assert(false); return; } + + Debug.Assert(pbData.Length >= 0); + if (pbData.Length > 0) s.Write(pbData, 0, pbData.Length); + } + + public static byte[] Compress(byte[] pbData) + { + if (pbData == null) throw new ArgumentNullException("pbData"); + if (pbData.Length == 0) return pbData; + + using (MemoryStream msSource = new MemoryStream(pbData, false)) + { + using (MemoryStream msCompressed = new MemoryStream()) + { + using (GZipStream gz = new GZipStream(msCompressed, + CompressionMode.Compress)) + { + CopyStream(msSource, gz); + } + + return msCompressed.ToArray(); + } + } + } + + public static byte[] Decompress(byte[] pbCompressed) + { + if (pbCompressed == null) throw new ArgumentNullException("pbCompressed"); + if (pbCompressed.Length == 0) return pbCompressed; + + using (MemoryStream msData = new MemoryStream()) + { + using (MemoryStream msCompressed = new MemoryStream(pbCompressed, false)) + { + using (GZipStream gz = new GZipStream(msCompressed, + CompressionMode.Decompress)) + { + CopyStream(gz, msData); + } + } + + return msData.ToArray(); + } + } + + public static int IndexOf(T[] vHaystack, T[] vNeedle) + where T : IEquatable + { + if (vHaystack == null) throw new ArgumentNullException("vHaystack"); + if (vNeedle == null) throw new ArgumentNullException("vNeedle"); + if (vNeedle.Length == 0) return 0; + + int cN = vNeedle.Length; + int iMax = vHaystack.Length - cN; + + for (int i = 0; i <= iMax; ++i) + { + bool bFound = true; + for (int m = 0; m < cN; ++m) + { + if (!vHaystack[i + m].Equals(vNeedle[m])) + { + bFound = false; + break; + } + } + if (bFound) return i; + } + + return -1; + } + + public static T[] Mid(T[] v, int iOffset, int iLength) + { + if (v == null) throw new ArgumentNullException("v"); + if (iOffset < 0) throw new ArgumentOutOfRangeException("iOffset"); + if (iLength < 0) throw new ArgumentOutOfRangeException("iLength"); + if ((iOffset + iLength) > v.Length) throw new ArgumentException(); + + T[] r = new T[iLength]; + Array.Copy(v, iOffset, r, 0, iLength); + return r; + } + + public static IEnumerable Union(IEnumerable a, IEnumerable b, + IEqualityComparer cmp) + { + if (a == null) throw new ArgumentNullException("a"); + if (b == null) throw new ArgumentNullException("b"); + + Dictionary d = ((cmp != null) ? + (new Dictionary(cmp)) : (new Dictionary())); + + foreach (T ta in a) + { + if (d.ContainsKey(ta)) continue; // Prevent duplicates + + d[ta] = true; + yield return ta; + } + + foreach (T tb in b) + { + if (d.ContainsKey(tb)) continue; // Prevent duplicates + + d[tb] = true; + yield return tb; + } + + yield break; + } + + public static IEnumerable Intersect(IEnumerable a, IEnumerable b, + IEqualityComparer cmp) + { + if (a == null) throw new ArgumentNullException("a"); + if (b == null) throw new ArgumentNullException("b"); + + Dictionary d = ((cmp != null) ? + (new Dictionary(cmp)) : (new Dictionary())); + + foreach (T tb in b) { d[tb] = true; } + + foreach (T ta in a) + { + if (d.Remove(ta)) // Prevent duplicates + yield return ta; + } + + yield break; + } + + public static IEnumerable Except(IEnumerable a, IEnumerable b, + IEqualityComparer cmp) + { + if (a == null) throw new ArgumentNullException("a"); + if (b == null) throw new ArgumentNullException("b"); + + Dictionary d = ((cmp != null) ? + (new Dictionary(cmp)) : (new Dictionary())); + + foreach (T tb in b) { d[tb] = true; } + + foreach (T ta in a) + { + if (d.ContainsKey(ta)) continue; + + d[ta] = true; // Prevent duplicates + yield return ta; + } + + yield break; + } + + internal static IEnumerable Distinct(IEnumerable s, + GFunc fGetKey, bool bPreferLast) + { + if (s == null) throw new ArgumentNullException("s"); + if (fGetKey == null) throw new ArgumentNullException("fGetKey"); + + Dictionary d = new Dictionary(); + + if (bPreferLast) + { + List l = new List(s); + int n = l.Count; + bool[] v = new bool[n]; + + for (int i = n - 1; i >= 0; --i) + { + TKey k = fGetKey(l[i]); + if (!d.ContainsKey(k)) { d[k] = true; v[i] = true; } + } + + for (int i = 0; i < n; ++i) + { + if (v[i]) yield return l[i]; + } + } + else + { + foreach (T t in s) + { + TKey k = fGetKey(t); + if (!d.ContainsKey(k)) { d[k] = true; yield return t; } + } + } + + yield break; + } + internal static bool ListsEqual(List a, List b) where T : class, IEquatable { @@ -809,5 +900,164 @@ namespace KeePassLib.Utility return true; } - } + + internal static int Count(byte[] pb, byte bt) + { + if (pb == null) { Debug.Assert(false); return 0; } + + int cb = pb.Length, r = 0; + for (int i = 0; i < cb; ++i) + { + if (pb[i] == bt) ++r; + } + + return r; + } + + [MethodImpl(MioNoOptimize)] + internal static void DisposeIfPossible(object o) + { + if (o == null) { Debug.Assert(false); return; } + + IDisposable d = (o as IDisposable); + if (d != null) d.Dispose(); + } + + internal static object GetEnumValue(Type tEnum, string strName) + { + if (tEnum == null) { Debug.Assert(false); return null; } + if (!tEnum.IsEnum) { Debug.Assert(false); return null; } + if (string.IsNullOrEmpty(strName)) { Debug.Assert(false); return null; } + + return ((Array.IndexOf(Enum.GetNames(tEnum), strName) >= 0) ? + Enum.Parse(tEnum, strName) : null); + } + + internal static T ConvertObject(object o, T tDefault) + { + if (o == null) return tDefault; + + try + { + if (o is T) return (T)o; + return (T)Convert.ChangeType(o, typeof(T)); + } + catch (Exception) { Debug.Assert(false); } + + try { return (T)o; } + catch (Exception) { Debug.Assert(false); } + + return tDefault; + } + + internal static T BytesToStruct(byte[] pb, int iOffset) + where T : struct + { + if (pb == null) throw new ArgumentNullException("pb"); + if (iOffset < 0) throw new ArgumentOutOfRangeException("iOffset"); + + int cb = Marshal.SizeOf(typeof(T)); + if (cb <= 0) { Debug.Assert(false); return default(T); } + + if (iOffset > (pb.Length - cb)) throw new ArgumentOutOfRangeException("iOffset"); + + IntPtr p = Marshal.AllocCoTaskMem(cb); + if (p == IntPtr.Zero) throw new OutOfMemoryException(); + + object o; + try + { + Marshal.Copy(pb, iOffset, p, cb); + o = Marshal.PtrToStructure(p, typeof(T)); + } + finally { Marshal.FreeCoTaskMem(p); } + + return (T)o; + } + + internal static byte[] StructToBytes(ref T t) + where T : struct + { + int cb = Marshal.SizeOf(typeof(T)); + if (cb <= 0) { Debug.Assert(false); return MemUtil.EmptyByteArray; } + + byte[] pb = new byte[cb]; + + IntPtr p = Marshal.AllocCoTaskMem(cb); + if (p == IntPtr.Zero) throw new OutOfMemoryException(); + + try + { + Marshal.StructureToPtr(t, p, false); + Marshal.Copy(p, pb, 0, cb); + } + finally { Marshal.FreeCoTaskMem(p); } + + return pb; + } + + internal static IntPtr AddPtr(IntPtr p, long cb) + { + // IntPtr.operator+ and IntPtr.Add are not available in .NET 2.0 + + if (IntPtr.Size >= 8) + return new IntPtr(unchecked(p.ToInt64() + cb)); + return new IntPtr(unchecked(p.ToInt32() + (int)cb)); + } + + // Cf. Array.Empty() of .NET 4.6 + private static class EmptyArrayEx + { + internal static readonly T[] Instance = new T[0]; + } + internal static T[] EmptyArray() + { + return EmptyArrayEx.Instance; + } + } + + internal sealed class ArrayHelperEx : IEqualityComparer, IComparer + where T : IEquatable, IComparable + { + public int GetHashCode(T[] obj) + { + if (obj == null) { Debug.Assert(false); throw new ArgumentNullException("obj"); } + + return (int)MemUtil.Hash32Ex(obj, 0, obj.Length); + } + + public bool Equals(T[] x, T[] y) + { + if (object.ReferenceEquals(x, y)) return true; + if ((x == null) || (y == null)) return false; + + int n = x.Length; + if (n != y.Length) return false; + + for (int i = 0; i < n; ++i) + { + if (!x[i].Equals(y[i])) return false; + } + + return true; + } + + public int Compare(T[] x, T[] y) + { + if (object.ReferenceEquals(x, y)) return 0; + if (x == null) return -1; + if (y == null) return 1; + + int n = x.Length, m = y.Length; + if (n != m) return ((n < m) ? -1 : 1); + + for (int i = 0; i < n; ++i) + { + T tX = x[i], tY = y[i]; + if (!tX.Equals(tY)) return tX.CompareTo(tY); + } + + return 0; + } + } } diff --git a/src/Kp2aAutofillParser.Tests/AutofillTest.cs b/src/Kp2aAutofillParser.Tests/AutofillTest.cs index eeefc2f1..95261e7b 100644 --- a/src/Kp2aAutofillParser.Tests/AutofillTest.cs +++ b/src/Kp2aAutofillParser.Tests/AutofillTest.cs @@ -95,7 +95,7 @@ namespace Kp2aAutofillParserTest StructureParserBase parser = new StructureParserBase(new TestLogger(), new TestDalSourceTrustAll()); - var result = parser.ParseForFill(false, autofillView); + var result = parser.ParseForFill(autofillView); if (expectedPackageName != null) Assert.Equal(expectedPackageName, result.PackageName); if (expectedWebDomain != null) diff --git a/src/Kp2aAutofillParser.Tests/com-servicenet-mobile-no-focus.json b/src/Kp2aAutofillParser.Tests/com-servicenet-mobile-no-focus.json index 50d7fb20..28893ff0 100644 --- a/src/Kp2aAutofillParser.Tests/com-servicenet-mobile-no-focus.json +++ b/src/Kp2aAutofillParser.Tests/com-servicenet-mobile-no-focus.json @@ -58,7 +58,8 @@ "IsFocused": false, "InputType": 97, "HtmlInfoTag": null, - "HtmlInfoTypeAttribute": null + "HtmlInfoTypeAttribute": null, + "ExpectedAssignedHints": [ "username" ] }, { "IdEntry": "password_text_input_layout", @@ -81,6 +82,7 @@ "InputType": 129, "HtmlInfoTag": null, "HtmlInfoTypeAttribute": null, + "ExpectedAssignedHints": [ "password" ] }, { diff --git a/src/Kp2aAutofillParser/AutofillParser.cs b/src/Kp2aAutofillParser/AutofillParser.cs index 3271b6b7..f8f80823 100644 --- a/src/Kp2aAutofillParser/AutofillParser.cs +++ b/src/Kp2aAutofillParser/AutofillParser.cs @@ -476,8 +476,16 @@ namespace Kp2aAutofillParser foreach (var field in autofillFields.HintMap.Values.Distinct()) { + if (field == null || field.AutofillHints == null) + { + continue; + } foreach (var hint in field.AutofillHints) { + if (hint == null) + { + continue; + } if (GetPartitionIndex(hint) == partitionIndex) { filteredCollection.Add(field); @@ -793,14 +801,14 @@ namespace Kp2aAutofillParser } } - public AutofillTargetId ParseForFill(bool isManual, AutofillView autofillView) + public AutofillTargetId ParseForFill(AutofillView autofillView) { - return Parse(true, isManual, autofillView); + return Parse(true, autofillView); } public AutofillTargetId ParseForSave(AutofillView autofillView) { - return Parse(false, true, autofillView); + return Parse(false, autofillView); } /// @@ -808,8 +816,7 @@ namespace Kp2aAutofillParser /// /// The parse. /// If set to true for fill. - /// - protected virtual AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView autofillView) + protected virtual AutofillTargetId Parse(bool forFill, AutofillView autofillView) { AutofillTargetId result = new AutofillTargetId() { @@ -876,8 +883,9 @@ namespace Kp2aAutofillParser } - //for "heuristic determination" we demand that one of the filled fields is focused: - if (passwordFields.Concat(usernameFields).Any(f => f.IsFocused)) + //for "heuristic determination" we demand that there is a password field or one of the username fields is focused: + //Note that "IsFocused" might be false even when tapping the field. It might require long-press to autofill. + if (passwordFields.Any() || usernameFields.Any(f => f.IsFocused)) { foreach (var uf in usernameFields) AddFieldToHintMap(uf, new string[] { AutofillHintsHelper.AutofillHintUsername }); diff --git a/src/Kp2aBusinessLogic/IKp2aApp.cs b/src/Kp2aBusinessLogic/IKp2aApp.cs index d4602a17..9a8357f8 100644 --- a/src/Kp2aBusinessLogic/IKp2aApp.cs +++ b/src/Kp2aBusinessLogic/IKp2aApp.cs @@ -29,6 +29,14 @@ namespace keepass2android } + + public enum MessageSeverity + { + Info, + Warning, + Error + } + /// /// Interface through which Activities and the logic layer can access some app specific functionalities and Application static data /// @@ -102,10 +110,13 @@ namespace keepass2android Context ctx, string messageSuffix = ""); - /// - /// Returns a Handler object which can run tasks on the UI thread - /// - Handler UiThreadHandler { get; } + void ShowMessage(Context ctx, int resourceId, MessageSeverity severity); + void ShowMessage(Context ctx, string text, MessageSeverity severity); + + /// + /// Returns a Handler object which can run tasks on the UI thread + /// + Handler UiThreadHandler { get; } IProgressDialog CreateProgressDialog(Context ctx); diff --git a/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs b/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs index f47b777e..77a411bc 100644 --- a/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs @@ -13,7 +13,7 @@ using Android.Content.PM; using Android.OS; using Android.Preferences; using Java.IO; - +using KeePass.Util; using KeePassLib.Serialization; using KeePassLib.Utility; using File = System.IO.File; @@ -121,7 +121,7 @@ namespace keepass2android.Io var response = ex.Response as HttpWebResponse; if ((response != null) && (response.StatusCode == HttpStatusCode.NotFound)) { - throw new FileNotFoundException(ex.Message, ioc.Path, ex); + throw new FileNotFoundException(ExceptionUtil.GetErrorMessage(ex), ioc.Path, ex); } if (ex.Status == WebExceptionStatus.TrustFailure) { diff --git a/src/Kp2aBusinessLogic/Io/DropboxFileStorageKeysDummy.cs b/src/Kp2aBusinessLogic/Io/DropboxFileStorageKeysDummy.cs deleted file mode 100644 index 924f7c50..00000000 --- a/src/Kp2aBusinessLogic/Io/DropboxFileStorageKeysDummy.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace keepass2android.Io -{ - public partial class DropboxFileStorage - { - private const string AppKey = "dummy"; - private const string AppSecret = "dummy"; - } - public partial class DropboxAppFolderFileStorage - { - private const string AppKey = "dummy"; - private const string AppSecret = "dummy"; - } -} diff --git a/src/Kp2aBusinessLogic/Io/GenerateSecrets.targets b/src/Kp2aBusinessLogic/Io/GenerateSecrets.targets new file mode 100644 index 00000000..4d964fbf --- /dev/null +++ b/src/Kp2aBusinessLogic/Io/GenerateSecrets.targets @@ -0,0 +1,27 @@ + + + + + + + + + namespace keepass2android.Io { + public partial class DropboxFileStorage { + private const string AppKey = "$(DropboxAppKey)"; + private const string AppSecret = "$(DropboxAppSecret)"; + } + public partial class DropboxAppFolderFileStorage { + private const string AppKey = "$(DropboxAppFolderAppKey)"; + private const string AppSecret = "$(DropboxAppFolderAppSecret)"; + } + } + + + \ No newline at end of file diff --git a/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs b/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs index f0429e11..e526928e 100644 --- a/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs @@ -13,6 +13,7 @@ using Keepass2android.Javafilestorage; #endif using Exception = System.Exception; using FileNotFoundException = Java.IO.FileNotFoundException; +using KeePass.Util; namespace keepass2android.Io { @@ -42,7 +43,7 @@ namespace keepass2android.Io } catch (FileNotFoundException e) { - throw new System.IO.FileNotFoundException(e.Message, e); + throw new System.IO.FileNotFoundException(ExceptionUtil.GetErrorMessage(e), e); } catch (Java.Lang.Exception e) { @@ -195,7 +196,7 @@ namespace keepass2android.Io } catch (FileNotFoundException e) { - throw new System.IO.FileNotFoundException(e.Message, e); + throw new System.IO.FileNotFoundException(ExceptionUtil.GetErrorMessage(e), e); } catch (Java.Lang.Exception e) { @@ -214,7 +215,7 @@ namespace keepass2android.Io } catch (FileNotFoundException e) { - throw new System.IO.FileNotFoundException(e.Message, e); + throw new System.IO.FileNotFoundException(ExceptionUtil.GetErrorMessage(e), e); } catch (Java.Lang.Exception e) { @@ -244,7 +245,7 @@ namespace keepass2android.Io } catch (FileNotFoundException e) { - throw new System.IO.FileNotFoundException(e.Message, e); + throw new System.IO.FileNotFoundException(ExceptionUtil.GetErrorMessage(e), e); } catch (Java.Lang.Exception e) { diff --git a/src/Kp2aBusinessLogic/Io/NetFtpFileStorage.cs b/src/Kp2aBusinessLogic/Io/NetFtpFileStorage.cs index b6226829..46ea23da 100644 --- a/src/Kp2aBusinessLogic/Io/NetFtpFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/NetFtpFileStorage.cs @@ -9,6 +9,7 @@ using Android.OS; using FluentFTP; using FluentFTP.Exceptions; using FluentFTP.GnuTLS; +using KeePass.Util; using KeePassLib; using KeePassLib.Serialization; using KeePassLib.Utility; @@ -128,7 +129,7 @@ namespace keepass2android.Io var ftpEx = (FtpCommandException) exception; if (ftpEx.CompletionCode == "550") - throw new FileNotFoundException(exception.Message, exception); + throw new FileNotFoundException(ExceptionUtil.GetErrorMessage(exception), exception); } return exception; diff --git a/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs b/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs index 96ad7679..132981dd 100644 --- a/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs @@ -3,6 +3,7 @@ using System.Reflection; using System.Text; using Android.Content; using Android.Util; +using KeePass.Util; using keepass2android.Io.ItemLocation; using KeePassLib.Serialization; using KeePassLib.Utility; @@ -522,10 +523,10 @@ namespace keepass2android.Io { if (e.IsMatch(GraphErrorCode.ItemNotFound.ToString())) - return new FileNotFoundException(e.Message); + return new FileNotFoundException(ExceptionUtil.GetErrorMessage(e)); if (e.Message.Contains("\n\n404 : ") ) //hacky solution to check for not found. errorCode was null in my tests so I had to find a workaround. - return new FileNotFoundException(e.Message); + return new FileNotFoundException(ExceptionUtil.GetErrorMessage(e)); return e; } diff --git a/src/Kp2aBusinessLogic/Io/OneDriveFileStorage.cs b/src/Kp2aBusinessLogic/Io/OneDriveFileStorage.cs index a6da1c7d..7a0be85a 100644 --- a/src/Kp2aBusinessLogic/Io/OneDriveFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/OneDriveFileStorage.cs @@ -16,20 +16,32 @@ namespace keepass2android.Io /// public class OneDriveFileStorage: IFileStorage { - - public IEnumerable SupportedProtocols + public OneDriveFileStorage(IKp2aApp app) + { + _app = app; + } + + private readonly IKp2aApp _app; + + public IEnumerable SupportedProtocols { get { yield return "skydrive"; yield return "onedrive"; - } + } } - private Exception GetDeprecatedMessage() + string GetDeprecatedMessage() + { + return + "You have opened your file through a deprecated Microsoft API. Please select Change database, Open Database and then select OneDrive again."; + } + + private Exception GetDeprecatedException() { return new Exception( - "You have opened your file through a deprecated Microsoft API. Please select Change database, Open Database and then select One Drive again."); + GetDeprecatedMessage()); } public bool UserShouldBackup @@ -39,133 +51,132 @@ namespace keepass2android.Io public void Delete(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public string GetCurrentFileVersionFast(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public Stream OpenFileForRead(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public string GetFileExtension(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public bool RequiresCredentials(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + return false; } public void CreateDirectory(IOConnectionInfo ioc, string newDirName) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public IEnumerable ListContents(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public FileDescription GetFileDescription(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public bool RequiresSetup(IOConnectionInfo ioConnection) { - throw GetDeprecatedMessage(); + return false; } public string IocToPath(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId) { - throw GetDeprecatedMessage(); + } public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode, bool alwaysReturnSuccess) { - throw GetDeprecatedMessage(); + _app.ShowMessage(activity.Activity, GetDeprecatedMessage(), MessageSeverity.Error); + } public void PrepareFileUsage(Context ctx, IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + } public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState) { - throw GetDeprecatedMessage(); + } public void OnResume(IFileStorageSetupActivity activity) { - throw GetDeprecatedMessage(); + } public void OnStart(IFileStorageSetupActivity activity) { - throw GetDeprecatedMessage(); } public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data) { - throw GetDeprecatedMessage(); } public string GetDisplayName(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + return "File using deprecated Microsoft API. Please update."; } public string CreateFilePath(string parent, string newFilename) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public IOConnectionInfo GetParentPath(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public bool IsPermanentLocation(IOConnectionInfo ioc) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } public bool IsReadOnly(IOConnectionInfo ioc, OptionalOut reason = null) { - throw GetDeprecatedMessage(); + throw GetDeprecatedException(); } } } diff --git a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj index af0e5d8b..4321e252 100644 --- a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj +++ b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj @@ -4,31 +4,44 @@ 21 enable enable + NO_QR_SCANNER;EXCLUDE_JAVAFILESTORAGE;NoNet - - - - - + + + + + - + - - - + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs b/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs index df1277bb..7be0ed5d 100644 --- a/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs +++ b/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs @@ -4,6 +4,7 @@ using Android.Content; using Android.OS; using Android.Widget; using Java.Net; +using KeePass.Util; using KeePassLib.Serialization; using keepass2android.Io; @@ -94,15 +95,12 @@ namespace keepass2android } if ((resultCode == Result.Canceled) && (data != null) && (data.HasExtra("EXTRA_ERROR_MESSAGE"))) { - ShowToast(data.GetStringExtra("EXTRA_ERROR_MESSAGE")); + ShowErrorToast(data.GetStringExtra("EXTRA_ERROR_MESSAGE")); } if (resultCode == Result.Ok) { - Kp2aLog.Log("FileSelection returned "+data.DataString); - //TODO: don't try to extract filename if content URI string filename = IntentToFilename(data); - Kp2aLog.Log("FileSelection returned filename " + filename); if (filename != null) { if (filename.StartsWith("file://")) @@ -150,7 +148,7 @@ namespace keepass2android protected abstract void StartFileChooser(string path, int requestCode, bool isForSave); - protected abstract void ShowToast(string text); + protected abstract void ShowErrorToast(string text); protected abstract void ShowInvalidSchemeMessage(string dataString); @@ -208,7 +206,7 @@ namespace keepass2android { return () => { - ShowToast(_app.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message); + ShowErrorToast(_app.GetResourceString(UiStringKey.ErrorOcurred) + " " + ExceptionUtil.GetErrorMessage(e)); ReturnCancel(); }; } diff --git a/src/Kp2aBusinessLogic/Utils/ExceptionUtil.cs b/src/Kp2aBusinessLogic/Utils/ExceptionUtil.cs new file mode 100644 index 00000000..07905f2f --- /dev/null +++ b/src/Kp2aBusinessLogic/Utils/ExceptionUtil.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + +namespace KeePass.Util +{ + public class ExceptionUtil + { + + public static string GetErrorMessage(Exception e) + { + string errorMessage = e.Message; + if (e is Java.Lang.Exception javaException) + { + try + { + errorMessage = javaException.LocalizedMessage ?? javaException.Message ?? errorMessage; + } + finally + { + + } + } + + return errorMessage; + } + + } +} \ No newline at end of file diff --git a/src/Kp2aBusinessLogic/database/CheckDatabaseForChanges.cs b/src/Kp2aBusinessLogic/database/CheckDatabaseForChanges.cs index 0986dfea..9924774f 100644 --- a/src/Kp2aBusinessLogic/database/CheckDatabaseForChanges.cs +++ b/src/Kp2aBusinessLogic/database/CheckDatabaseForChanges.cs @@ -5,6 +5,7 @@ using System.Security.Cryptography; using System.Text; using Android.App; using Android.Content; +using KeePass.Util; using KeePassLib.Cryptography; using KeePassLib.Serialization; using KeePassLib.Utility; @@ -65,7 +66,7 @@ namespace keepass2android } catch (Exception e) { - Finish(false, e.Message); + Finish(false, ExceptionUtil.GetErrorMessage(e)); } } diff --git a/src/Kp2aBusinessLogic/database/Database.cs b/src/Kp2aBusinessLogic/database/Database.cs index f62572cd..1e97c166 100644 --- a/src/Kp2aBusinessLogic/database/Database.cs +++ b/src/Kp2aBusinessLogic/database/Database.cs @@ -90,9 +90,12 @@ namespace keepass2android PwDatabase pwDatabase = new PwDatabase(); IFileStorage fileStorage = _app.GetFileStorage(iocInfo); - Stream s = databaseData ?? fileStorage.OpenFileForRead(iocInfo); - var fileVersion = _app.GetFileStorage(iocInfo).GetCurrentFileVersionFast(iocInfo); - PopulateDatabaseFromStream(pwDatabase, s, iocInfo, compositeKey, status, databaseFormat); + Kp2aLog.Log("LoadData: Retrieving stream"); + Stream s = databaseData ?? fileStorage.OpenFileForRead(iocInfo); + Kp2aLog.Log("LoadData: GetCurrentFileVersion"); + var fileVersion = _app.GetFileStorage(iocInfo).GetCurrentFileVersionFast(iocInfo); + Kp2aLog.Log("LoadData: PopulateDatabaseFromStream"); + PopulateDatabaseFromStream(pwDatabase, s, iocInfo, compositeKey, status, databaseFormat); LastFileVersion = fileVersion; status.UpdateSubMessage(""); diff --git a/src/Kp2aBusinessLogic/database/KdbDatabaseFormat.cs b/src/Kp2aBusinessLogic/database/KdbDatabaseFormat.cs index d8e0199d..e9d0ca6b 100644 --- a/src/Kp2aBusinessLogic/database/KdbDatabaseFormat.cs +++ b/src/Kp2aBusinessLogic/database/KdbDatabaseFormat.cs @@ -10,6 +10,7 @@ using Com.Keepassdroid.Database.Exception; #endif using Com.Keepassdroid.Database.Save; using Java.Util; +using KeePass.Util; using KeePassLib; using KeePassLib.Cryptography; using KeePassLib.Cryptography.Cipher; @@ -82,15 +83,14 @@ namespace keepass2android catch (Java.IO.FileNotFoundException e) { throw new FileNotFoundException( - e.Message, e); + ExceptionUtil.GetErrorMessage(e), e); } catch (Java.Lang.Exception e) { if (e.Message == "Invalid key!") throw new InvalidCompositeKeyException(); - throw new Exception(e.LocalizedMessage ?? - e.Message ?? - e.GetType().Name, e); + throw new Exception(ExceptionUtil.GetErrorMessage(e) ?? + e.GetType().Name, e); } HashOfLastStream = hashingStream.Hash; diff --git a/src/Kp2aBusinessLogic/database/SynchronizeCachedDatabase.cs b/src/Kp2aBusinessLogic/database/SynchronizeCachedDatabase.cs index ad58a493..16a78d03 100644 --- a/src/Kp2aBusinessLogic/database/SynchronizeCachedDatabase.cs +++ b/src/Kp2aBusinessLogic/database/SynchronizeCachedDatabase.cs @@ -6,6 +6,7 @@ using Android.App; using Android.Content; using KeePassLib.Serialization; using keepass2android.Io; +using KeePass.Util; namespace keepass2android { @@ -109,7 +110,7 @@ namespace keepass2android catch (Exception e) { Kp2aLog.LogUnexpectedError(e); - Finish(false, e.Message); + Finish(false, ExceptionUtil.GetErrorMessage(e)); } } diff --git a/src/Kp2aBusinessLogic/database/edit/LoadDB.cs b/src/Kp2aBusinessLogic/database/edit/LoadDB.cs index 3c476abd..d76e3502 100644 --- a/src/Kp2aBusinessLogic/database/edit/LoadDB.cs +++ b/src/Kp2aBusinessLogic/database/edit/LoadDB.cs @@ -21,6 +21,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Android.App; +using KeePass.Util; using keepass2android.database.edit; using KeePassLib; using KeePassLib.Keys; @@ -103,10 +104,10 @@ namespace keepass2android } catch (AggregateException e) { - string message = e.Message; + string message = ExceptionUtil.GetErrorMessage(e); foreach (var innerException in e.InnerExceptions) { - message = innerException.Message; + message = ExceptionUtil.GetErrorMessage(innerException); // Override the message shown with the last (hopefully most recent) inner exception Kp2aLog.LogUnexpectedError(innerException); } @@ -116,14 +117,14 @@ namespace keepass2android catch (DuplicateUuidsException e) { Kp2aLog.Log(e.ToString()); - Finish(false, _app.GetResourceString(UiStringKey.DuplicateUuidsError) + " " + e.Message + _app.GetResourceString(UiStringKey.DuplicateUuidsErrorAdditional), false, Exception); + Finish(false, _app.GetResourceString(UiStringKey.DuplicateUuidsError) + " " + ExceptionUtil.GetErrorMessage(e) + _app.GetResourceString(UiStringKey.DuplicateUuidsErrorAdditional), false, Exception); return; } catch (Exception e) { if (!(e is InvalidCompositeKeyException)) Kp2aLog.LogUnexpectedError(e); - Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + (e.Message ?? (e is FileNotFoundException ? _app.GetResourceString(UiStringKey.FileNotFound) : "")), false, Exception); + Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + (ExceptionUtil.GetErrorMessage(e) ?? (e is FileNotFoundException ? _app.GetResourceString(UiStringKey.FileNotFound) : "")), false, Exception); return; } @@ -137,6 +138,7 @@ namespace keepass2android Database TryLoad(MemoryStream databaseStream) { + Kp2aLog.Log("LoadDb: Copying database in memory"); //create a copy of the stream so we can try again if we get an exception which indicates we should change parameters //This is not optimal in terms of (short-time) memory usage but is hard to avoid because the Keepass library closes streams also in case of errors. //Alternatives would involve increased traffic (if file is on remote) and slower loading times, so this seems to be the best choice. @@ -145,8 +147,9 @@ namespace keepass2android workingCopy.Seek(0, SeekOrigin.Begin); //reset stream if we need to reuse it later: databaseStream.Seek(0, SeekOrigin.Begin); - //now let's go: - try + Kp2aLog.Log("LoadDb: Ready to start loading"); + //now let's go: + try { Database newDb = _app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _format, _makeCurrent); Kp2aLog.Log("LoadDB OK"); diff --git a/src/Kp2aBusinessLogic/database/edit/OnFinish.cs b/src/Kp2aBusinessLogic/database/edit/OnFinish.cs index 455e3a53..7c3071e8 100644 --- a/src/Kp2aBusinessLogic/database/edit/OnFinish.cs +++ b/src/Kp2aBusinessLogic/database/edit/OnFinish.cs @@ -130,24 +130,24 @@ namespace keepass2android if ( !String.IsNullOrEmpty(message) ) { Kp2aLog.Log("OnFinish message: " + message); if (makeDialog && ctx != null) - { - try - { - MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ctx); - - builder.SetMessage(message) - .SetPositiveButton(Android.Resource.String.Ok, (sender, args) => ((Dialog)sender).Dismiss()) - .Show(); + { + try + { + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ctx); + + builder.SetMessage(message) + .SetPositiveButton(Android.Resource.String.Ok, (sender, args) => ((Dialog)sender).Dismiss()) + .Show(); } catch (Exception) - { - Toast.MakeText(ctx, message, ToastLength.Long).Show(); - } - } + { + Toast.MakeText(ctx, message, ToastLength.Long).Show(); + } + } else Toast.MakeText(ctx ?? Application.Context, message, ToastLength.Long).Show(); - } + } } } } diff --git a/src/Kp2aBusinessLogic/database/edit/SaveDB.cs b/src/Kp2aBusinessLogic/database/edit/SaveDB.cs index c432d416..ae39ea82 100644 --- a/src/Kp2aBusinessLogic/database/edit/SaveDB.cs +++ b/src/Kp2aBusinessLogic/database/edit/SaveDB.cs @@ -29,6 +29,7 @@ using KeePassLib.Utility; using keepass2android.Io; using Debug = System.Diagnostics.Debug; using Exception = System.Exception; +using KeePass.Util; namespace keepass2android { @@ -187,7 +188,7 @@ namespace keepass2android } */ Kp2aLog.LogUnexpectedError(e); - Finish(false, e.Message); + Finish(false, ExceptionUtil.GetErrorMessage(e)); return; } } @@ -222,8 +223,8 @@ namespace keepass2android catch (Exception e) { Kp2aLog.LogUnexpectedError(e); - Kp2aLog.Log("Error in worker thread of SaveDb: " + e); - Finish(false, e.Message); + Kp2aLog.Log("Error in worker thread of SaveDb: " + ExceptionUtil.GetErrorMessage(e)); + Finish(false, ExceptionUtil.GetErrorMessage(e)); } }); @@ -233,7 +234,7 @@ namespace keepass2android { Kp2aLog.LogUnexpectedError(e); Kp2aLog.Log("Error starting worker thread of SaveDb: "+e); - Finish(false, e.Message); + Finish(false, ExceptionUtil.GetErrorMessage(e)); } } diff --git a/src/build-scripts/build-java.sh b/src/build-scripts/build-java.sh new file mode 100755 index 00000000..fb9337a7 --- /dev/null +++ b/src/build-scripts/build-java.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -e + +#unset ANDROID_NDK_HOME ANDROID_NDK + +pushd ../java/ + +pushd JavaFileStorageTest-AS +./gradlew assemble +popd + +pushd KP2ASoftkeyboard_AS +./gradlew assemble +popd + +pushd Keepass2AndroidPluginSDK2 +./gradlew assemble +popd + +pushd KP2AKdbLibrary +./gradlew assemble +popd + +popd diff --git a/src/build-scripts/build-native.sh b/src/build-scripts/build-native.sh new file mode 100755 index 00000000..32bb8361 --- /dev/null +++ b/src/build-scripts/build-native.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e + +pushd ../java/argon2 +ndk-build +popd diff --git a/src/build-scripts/linux-build.md b/src/build-scripts/linux-build.md new file mode 100644 index 00000000..4fd0cb9d --- /dev/null +++ b/src/build-scripts/linux-build.md @@ -0,0 +1,28 @@ +## Setup build environment +* install Android SDK +* install Android NDK +* install dotnet8 + +``` + +#from https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-8.0.407-linux-x64-binaries +wget https://download.visualstudio.microsoft.com/download/pr/9d07577e-f7bc-4d60-838d-f79c50b5c11a/459ef339396783db369e0432d6dc3d7e/dotnet-sdk-8.0.407-linux-x64.tar.gz +mkdir -p $HOME/dotnet && tar zxf dotnet-sdk-8.0.407-linux-x64.tar.gz -C $HOME/dotnet +export DOTNET_ROOT=$HOME/dotnet +export PATH=$PATH:$HOME/dotnet + +``` + +## Build Keepass2Android + +``` +git clone --recurse-submodules https://github.com/PhilippC/keepass2android.git +cd keepass2android/src/build-scripts +./build-java.sh && ./build-native.sh +cd .. +cd keepass2android-app +ln -s Manifests/AndroidManifest_debug.xml AndroidManifest.xml +dotnet workload restore +dotnet restore +dotnet build +``` diff --git a/src/build-scripts/rename-output-apks.sh b/src/build-scripts/rename-output-apks.sh new file mode 100644 index 00000000..2fb213f9 --- /dev/null +++ b/src/build-scripts/rename-output-apks.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +BASE_DIR="${1}" + +for arch_dir in "$BASE_DIR"/android-*/; do + arch=$(basename "$arch_dir") + arch=${arch#android-} + APK_DIR="${arch_dir}publish" + if [[ -d "$APK_DIR" ]]; then + apk_path=$(find "$APK_DIR" -maxdepth 1 -type f -name "*.apk" | head -n1) + if [[ -n "$apk_path" ]]; then + base=$(basename "$apk_path" .apk) + new_path="$APK_DIR/${base}-${arch}.apk" + mv "$apk_path" "$new_path" + echo "Renamed $apk_path to $new_path" + else + echo "No APK found in $APK_DIR" + fi + else + echo "Directory $APK_DIR does not exist" + fi +done \ No newline at end of file diff --git a/src/java/JavaFileStorageTest-AS/app/src/main/AndroidManifest.xml b/src/java/JavaFileStorageTest-AS/app/src/main/AndroidManifest.xml index bbc22be0..5d203748 100644 --- a/src/java/JavaFileStorageTest-AS/app/src/main/AndroidManifest.xml +++ b/src/java/JavaFileStorageTest-AS/app/src/main/AndroidManifest.xml @@ -6,8 +6,7 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:supportsRtl="true" - android:theme="@style/AppTheme"> + android:supportsRtl="true"> diff --git a/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java b/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java index f46fb622..dbf96499 100644 --- a/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java +++ b/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java @@ -64,8 +64,6 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { @Override public boolean onCreate() { - Log.d("KP2A_FC_P", "onCreate"); - BaseFileProviderUtils.registerProviderInfo(_ID, getAuthority()); @@ -222,12 +220,12 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { try { checkConnection(uri); - Log.d("KP2A_FC_P", "checking connection for " + uri + " ok."); + if (Utils.doLog()) Log.d("KP2A_FC_P", "checking connection for " + uri + " ok."); return null; } catch (Exception e) { - Log.d("KP2A_FC_P","Check connection failed with: " + e.toString()); + if (Utils.doLog()) Log.d("KP2A_FC_P","Check connection failed with: " + e.toString()); MatrixCursor matrixCursor = new MatrixCursor(BaseFileProviderUtils.CONNECTION_CHECK_CURSOR_COLUMNS); RowBuilder newRow = matrixCursor.newRow(); @@ -255,7 +253,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { } catch (FileNotFoundException ex) { - Log.d("KP2A_FC_P","File not found. Ignore."); + if (Utils.doLog()) Log.d("KP2A_FC_P","File not found. Ignore."); return; } @@ -276,8 +274,8 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { MatrixCursor matrixCursor = null; String lastPathSegment = uri.getLastPathSegment(); - - Log.d("KP2A_FC_P", "lastPathSegment:" + lastPathSegment); + + if (Utils.doLog()) Log.d("KP2A_FC_P", "lastPathSegment:" + lastPathSegment); if (BaseFile.CMD_CANCEL.equals(lastPathSegment)) { int taskId = ProviderUtils.getIntQueryParam(uri, @@ -361,7 +359,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { } else if (BaseFile.CMD_CHECK_CONNECTION.equals(lastPathSegment)) { - Log.d("KP2A_FC_P","Check connection..."); + if (Utils.doLog()) Log.d("KP2A_FC_P","Check connection..."); return getCheckConnectionCursor(uri); } @@ -470,7 +468,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { String displayName = getFileEntryCached(dirName).displayName; newRow.add(displayName); - Log.d(CLASSNAME, "Returning name " + displayName+" for " +dirName); + if (Utils.doLog()) Log.d(CLASSNAME, "Returning name " + displayName+" for " +dirName); } } @@ -690,7 +688,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { } catch (Exception e) { - Log.d("KP2A_FC_P", "sortFiles() >> "+e); + if (Utils.doLog()) Log.d("KP2A_FC_P", "sortFiles() >> "+e); throw e; } }// sortFiles() @@ -777,14 +775,14 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { path = removeTrailingSlash(path); if (path.indexOf("://") == -1) { - Log.d("KP2A_FC_P", "invalid path: " + path); + if (Utils.doLog()) Log.d("KP2A_FC_P", "invalid path: " + path); return null; } String pathWithoutProtocol = path.substring(path.indexOf("://") + 3); int lastSlashPos = path.lastIndexOf("/"); if (pathWithoutProtocol.indexOf("/") == -1) { - Log.d("KP2A_FC_P", "parent of " + path + " is null"); + if (Utils.doLog()) Log.d("KP2A_FC_P", "parent of " + path + " is null"); return null; } else @@ -793,7 +791,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { if (params != null) { parent += params; } - Log.d("KP2A_FC_P", "parent of " + path +" is " + parent); + if (Utils.doLog()) Log.d("KP2A_FC_P", "parent of " + path +" is " + parent); return parent; } } diff --git a/src/java/android-filechooser-AS/app/src/main/res/values-it/strings.xml b/src/java/android-filechooser-AS/app/src/main/res/values-it/strings.xml index afbfa095..7836c3ef 100644 --- a/src/java/android-filechooser-AS/app/src/main/res/values-it/strings.xml +++ b/src/java/android-filechooser-AS/app/src/main/res/values-it/strings.xml @@ -56,15 +56,15 @@ Ordina per… Ieri - Scegli la cartella… - Scegli le cartelle… + Scegli cartella... + Scegli le cartelle... - Scegli il file… - Scegli i file… + Scegli il file + Scegli i file - Scegli file/ cartella… - Scegli file/ cartelle… + Scegli file/cartella + Scegli file/cartelle diff --git a/src/java/android-filechooser-AS/app/src/main/res/values-ro/strings.xml b/src/java/android-filechooser-AS/app/src/main/res/values-ro/strings.xml index 2754b206..a1979ed2 100644 --- a/src/java/android-filechooser-AS/app/src/main/res/values-ro/strings.xml +++ b/src/java/android-filechooser-AS/app/src/main/res/values-ro/strings.xml @@ -55,4 +55,19 @@ Dimensiune Sortează după… Ieri + + Alege dosarul… + Alege dosarele… + Alege dosarele… + + + Alege fișierul… + Alege fișierele… + Alege fișierele… + + + Alege fișierul/dosarul… + Alege fișierele/dosarele… + Alege fișierele/dosarele… + diff --git a/src/keepass2android-app/AboutDialog.cs b/src/keepass2android-app/AboutDialog.cs index 203a34c0..421311c3 100644 --- a/src/keepass2android-app/AboutDialog.cs +++ b/src/keepass2android-app/AboutDialog.cs @@ -59,7 +59,7 @@ namespace keepass2android } catch (ActivityNotFoundException) { - Toast.MakeText(Context, Resource.String.no_url_handler, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(Context, Resource.String.no_url_handler, MessageSeverity.Error); } }; @@ -71,7 +71,7 @@ namespace keepass2android } catch (ActivityNotFoundException) { - Toast.MakeText(Context, Resource.String.no_url_handler, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(Context, Resource.String.no_url_handler, MessageSeverity.Error); } }; FindViewById(Resource.Id.translate).Click += delegate @@ -82,7 +82,7 @@ namespace keepass2android } catch (ActivityNotFoundException) { - Toast.MakeText(Context, Resource.String.no_url_handler, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(Context, Resource.String.no_url_handler, MessageSeverity.Error); } }; FindViewById(Resource.Id.donate).Click += delegate { diff --git a/src/keepass2android-app/AppKilledInfo.cs b/src/keepass2android-app/AppKilledInfo.cs index 6d017bee..36b14a8a 100644 --- a/src/keepass2android-app/AppKilledInfo.cs +++ b/src/keepass2android-app/AppKilledInfo.cs @@ -14,7 +14,7 @@ using keepass2android; namespace keepass2android { - [Activity(Label = AppNames.AppName)] + [Activity(Label = AppNames.AppName, Theme = "@style/Kp2aTheme_BlueNoActionBar")] public class AppKilledInfo : Activity, IDialogInterfaceOnDismissListener { protected override void OnCreate(Bundle bundle) diff --git a/src/keepass2android-app/Assets/MostPopularPasswords.txt b/src/keepass2android-app/Assets/MostPopularPasswords.txt new file mode 100644 index 00000000..97841b8a --- /dev/null +++ b/src/keepass2android-app/Assets/MostPopularPasswords.txt @@ -0,0 +1,10183 @@ +& +& +**** +***** +****** +????? +?????? +0.0.0.000 +0.0.000 +0000 +00000 +000000 +0000007 +000001 +000007 +0001 +0007 +0069 +007007 +007bond +0101 +010101 +010203 +0123 +012345 +0123456 +01234567 +0123456789 +020202 +030303 +0311 +0420 +050505 +063dyjuy +0660 +070462 +0815 +085tzzqi +090909 +0911 +0987 +098765 +09876543 +0987654321 +1000 +100000 +1001 +100100 +1002 +1003 +1004 +1005 +1007 +1008 +1009 +1010 +101010 +10101010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +102030 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +102938 +1030 +1031 +1066 +11001001 +1101 +1102 +1103 +1104 +1107 +1111 +11111 +111111 +1111111 +11111111 +11112222 +1112 +111222 +1113 +1114 +1115 +1117 +1120 +1121 +1122 +112211 +112233 +11223344 +1123 +112358 +11235813 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1134 +1138 +1200 +1201 +1202 +1204 +1205 +120676 +1207 +1208 +1209 +1210 +1211 +1212 +121212 +12121212 +1213 +121314 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +123098 +1231 +123123 +12312312 +123123123 +1233 +123321 +1234 +12341234 +1234321 +12344321 +12345 +123456 +1234567 +12345678 +123456789 +1234567890 +12345678910 +12345679 +123456a +123457 +12345a +1234abcd +1234qwer +1235 +1236 +123654 +123789 +123987 +123aaa +123abc +123asd +123qwe +124038 +1245 +124578 +1269 +12locked +12qwaszx +1313 +131313 +13131313 +1331 +134679 +1357 +13576479 +13579 +135790 +1369 +1411 +1414 +141414 +14141414 +142536 +142857 +143143 +1432 +1469 +147147 +147258 +14725836 +1478 +147852 +1478963 +14789632 +1492 +1515 +151515 +151nxjmt +154ugeiu +159159 +159357 +159753 +159951 +1616 +161616 +1624 +1664 +1701 +17011701 +1717 +171717 +17171717 +1776 +1812 +1818 +181818 +18436572 +187187 +1900 +1911 +1911a1 +1914 +1919 +191919 +1941 +1942 +1943 +1944 +1945 +1946 +1947 +1948 +1949 +1950 +1951 +1952 +1953 +1954 +1955 +1956 +1957 +1958 +1959 +1960 +1961 +1962 +1963 +1964 +1965 +1966 +1967 +1968 +1969 +19691969 +196969 +1970 +1971 +1972 +1973 +1974 +19741974 +1975 +1976 +1977 +1978 +19781978 +1979 +1980 +1981 +1982 +1983 +1984 +19841984 +1985 +1986 +1987 +1988 +1989 +1990 +1991 +1992 +1993 +1994 +1995 +1996 +1997 +1998 +1999 +199999 +1a2b3c +1a2b3c4d +1bitch +1chris +1dallas +1dragon +1fuck +1kitty +1letmein +1love +1master +1michael +1million +1monkey +1passwor +1pussy +1q2w3e +1q2w3e4r +1q2w3e4r5t +1qaz +1qaz2wsx +1qazxsw2 +1qwerty +1ranger +1test +1x2zkg8w +2000 +200000 +20002000 +2001 +20012001 +2002 +2003 +2004 +2005 +2010 +201jedlz +2020 +202020 +20202020 +2055 +20spanks +2112 +21122112 +2121 +212121 +21212121 +2211 +2222 +22222 +222222 +2222222 +22222222 +222333 +222777 +2233 +223344 +2244 +2255 +2277 +2323 +232323 +23232323 +2345 +234567 +2369 +23skidoo +2424 +242424 +24242424 +2468 +24680 +246810 +24682468 +2469 +2500 +2501 +2525 +252525 +25252525 +2580 +25802580 +2626 +262626 +2663 +2727 +272727 +2828 +282828 +2929 +292929 +2fast4u +2fchbg +2hot4u +2kids +3000 +3000gt +3006 +3030 +303030 +311311 +3131 +313131 +314159 +31415926 +321123 +321321 +321654 +3232 +323232 +3234412 +332211 +3333 +33333 +333333 +3333333 +33333333 +333666 +336699 +3434 +343434 +3535 +353535 +362436 +3636 +363636 +368ejhih +369369 +3728 +3737 +373737 +380zliki +3825 +383838 +383pdjvl +393939 +3ip76k2 +3ki42x +3mpz4r +3qvqod +3some +3tmnej +3way +3x7pxr +4040 +404040 +4121 +4128 +414141 +4200 +420000 +420247 +420420 +4226 +4242 +424242 +426hemi +4271 +427900 +4321 +4343 +434343 +4417 +4444 +44444 +444444 +4444444 +44444444 +445566 +4545 +454545 +456123 +456321 +456456 +456654 +4567 +456789 +464646 +4711 +4747 +474747 +474jdvff +484848 +4949 +494949 +49ers +4ever +4mnveh +4ng62t +4runner +4snz9g +4tlved +4wcqjn +4wwvte +4you +4zqauf +5000 +5050 +505050 +50cent +50spanks +5150 +515000 +515051 +51505150 +5151 +515151 +5232 +5252 +525252 +5291 +5329 +5353 +535353 +5401 +5424 +5432 +54321 +543210 +5454 +545454 +551scasi +554uzpad +5551212 +5555 +55555 +555555 +5555555 +55555555 +555666 +55bgates +5656 +565656 +5678 +567890 +5683 +56qhxs +5757 +575757 +57chevy +57np39 +5858 +585858 +5lyedn +5rxypn +5wr2i7h8 +606060 +616161 +616913 +626262 +635241 +636363 +6464 +646464 +654321 +655321 +656565 +6666 +66666 +666666 +6666666 +66666666 +666777 +6669 +666999 +676767 +6789 +686868 +6969 +696969 +69696969 +6996 +69camaro +6bjvpe +6chid8 +6uldv8 +7007 +717171 +727272 +72d5tn +737373 +741852 +7474 +747474 +753159 +753951 +757575 +7654321 +766rglqy +7676 +767676 +7734 +7777 +77777 +777777 +7777777 +77777777 +7779311 +778899 +7878 +787878 +7890 +789123 +7894 +789456 +78945612 +789654 +789789 +789987 +797979 +7bgiqk +7dwarfs +7grout +7kbe9d +7uftyx +7xm5rq +818181 +81fukkc +83y6pv +8520 +852456 +8543852 +863abgsg +8675309 +868686 +87654321 +878787 +8888 +88888 +888888 +8888888 +88888888 +8989 +898989 +8dihc6 +8inches +8j4ye3uz +8uiazp +8vjzus +90210 +902100 +909090 +911911 +911turbo +951753 +963852 +969696 +987456 +9876 +98765 +987654 +98765432 +987654321 +987987 +9898 +989898 +9999 +99999 +999999 +9999999 +99999999 +999999999 +9skw5g +a12345 +a123456 +a1234567 +a1b2c3 +a1b2c3d4 +aaa111 +aaa340 +aaaa +aaaaa +aaaaa1 +aaaaaa +aaaaaa1 +aaaaaaa +aaaaaaa1 +aaaaaaaa +aaabbb +aaliyah +aardvark +aaron +aaron1 +abacab +abacus +abba +abbey1 +abbott +abby +abc123 +abc1234 +abc12345 +abcabc +abcd +abcd123 +abcd1234 +abcde +abcdef +abcdefg +abcdefg1 +abcdefgh +aberdeen +abgrtyu +abigail +abnormal +abracadabra +abraham +abraxas +absolut +absolute +absolutely +abstr +academia +academic +acapulco +access +access1 +access14 +access99 +accord +account +acdc +aceace +aceman +acer +achilles +achtung +acid +acidburn +acls2h +acropolis +action +active +acura +adam +adam12 +adam25 +adams +addict +addison +address +adelaide +adidas +admin +admin1 +admiral +adonis +adrian +adriana +adrianna +adrienne +adult +adults +advance +advent +aerobics +aerosmit +africa +again +agent +aggie +aggies +agyvorc +aikido +aikman +aileen +aimee +airborne +airbus +aircraft +airforce +airman +airplane +airport +airwolf +aisan +ajax +akira +al9agd +alabama +aladin +alain +alan +alanis +alaska +alatam +albany +albatros +albert +alberta +alberto +albino +albion +alcat +alchemy +alcohol +alec +alejandr +alejandra +alejandro +alert +alessand +alex +alexa +alexalex +alexande +alexander +alexandr +alexandra +alexia +alexis +alfa +alfarome +alfred +alfredo +algebra +alibaba +alice +alice1 +alicia +alien +aliens +alina +aline +alisa +alisha +alison +alissa +alive +all4one +allan +allday +allegro +allen +allen1 +alley +alleycat +allgood +alliance +allie +allison +allison1 +allman +allmine +allnight +allsop +allstar +allstate +almighty +almond +aloha +alone +alpha +alpha1 +alpha123 +alphabet +alpina +alpine +alright +altec +althea +althor +altima +altoids +alucard +alvin +always +alyson +alyssa +amadeus +amanda +amanda1 +amateur +amateurs +amatuers +amature +amazing +amazon +amber +amber1 +ambers +ambrose +ambrosia +amelia +america +america1 +american +ameteur +amethyst +ametuer +amiga +amigo +amigos +amonra +amor +amstel +amsterda +amsterdam +anaconda +anakin +anal +analog +analsex +anarchy +anastasi +anchor +anders +andersen +anderson +andre +andrea +andrea1 +andreas +andres +andrew +andrew1 +andrews +andrey +andromed +andromeda +andy +andyandy +andyod22 +anfield +angel +angel1 +angela +angela1 +angeles +angelica +angelika +angelina +angelo +angels +angelus +angie +angus +angus1 +animal +animals +animated +anime +anita +anna +annabell +anne +annette +annie +annie1 +annika +annmarie +another +answer +antares +antelope +anthony +anthony1 +anthony7 +anthrax +antoine +anton +antonia +antonio +antony +anubis +anything +anytime +aol123 +aolsucks +apache +apollo +apollo1 +apollo13 +apple +apple1 +apple123 +applepie +apples +apricot +april +april1 +aprilia +aptiva +aquarius +aragon +aragorn +aramis +arcadia +arch +archange +archer +archery +archie +architec +arctic +area51 +argentin +ariana +ariane +arianna +ariel +aries +arizona +arizona1 +arkansas +arlene +armada +armand +armando +armani +armored +armstron +army +arnold +around +arrow +arrows +arse +arsenal +arsenal1 +artemis +arthur +artist +arturo +asasas +asd123 +asdasd +asdf +asdf12 +asdf123 +asdf1234 +asdfasdf +asdfg +asdfgh +asdfgh1 +asdfghj +asdfghjk +asdfghjkl +asdfjkl +asdzxc +asgard +ashlee +ashleigh +ashley +ashley1 +ashton +asia +asian +asians +aside +asimov +askim +aspen +aspire +assass +assassin +asscock +asses +assfuck +asshole +asshole1 +assholes +assman +asswipe +assword +asterix +asthma +astra +astral +astrid +astro +astro1 +astros +athena +athens +athlon +athome +atlanta +atlantic +atlantis +atlas +atmosphere +atomic +atreides +attack +atticus +attila +attitude +attorney +attract +aubrey +auburn +auckland +audi +audia4 +audio +auditt +audrey +auggie +august +augusta +augustus +aurora +aussie +austin +austin1 +austin31 +australi +australia +austria +auto +autumn +avalanch +avalon +avatar +avenger +avenue +aviation +away +awesome +awful +awnyce +axeman +axio +azazel +azerty +azertyui +azrael +azsxdc +aztnm +azure +azzer +b929ezzh +baba +babe +baberuth +babes +babies +baboon +baby +babybaby +babyblue +babyboy +babycake +babydoll +babyface +babygirl +babylon +babylon5 +babylove +bacardi +bacchus +bach +back +backbone +backdoor +backup +bacon +badabing +badass +badboy +badboy1 +baddest +baddog +badger +badgers +badgirl +badman +bagels +baggies +baggins +baggio +bagpuss +bahamas +bahamut +bailey +bailey1 +baker +baker1 +balance +balboa +baldwin +ball +baller +ballet +ballin +balloon +balloons +balls +balls1 +baltimor +bama +bambam +bambi +bamboo +banana +banana1 +bananas +banane +band +bandit +bang +bangbang +banger +bangkok +bank +banker +banks +banner +banshee +banzai +barb +barbados +barbara +barber +barbie +barcelon +barcelona +barefeet +barefoot +barfly +baritone +barker +barkley +barks +barley +barnes +barney +barney1 +baron +barrage +barrett +barron +barry +barry1 +bart +bartman +bartok +barton +base +basebal1 +baseball +baseball1 +basement +basher +basic +basil +basket +basketba +basketball +bass +basset +bassman +bassoon +bastard +bastards +bathing +batman +batman1 +battery +battle +bauhaus +baura +baxter +bayern +baylor +bball +bbb747 +bbbb +bbbbb +bbbbb1 +bbbbbb +bbbbbb1 +bbbbbbb +bbbbbbbb +bbking +bcfields +bdsm +beach +beach1 +beaches +beacon +beagle +beaker +beamer +bean +beanbag +beaner +beanie +beans +bear +bear1 +bearbear +bearcat +bearcats +beardog +bears +bears1 +beast +beast1 +beastie +beat +beater +beating +beatle +beatles +beatles1 +beatrice +beau +beautifu +beautiful +beauty +beaver +beavers +beavis +beavis1 +bebe +because +becca +beck +becker +beckham +becky +becky1 +bedford +bedlam +beebee +beech +beef +beefcake +beelch +beemer +beer +beerbeer +beerman +beerme +beethove +beethoven +beetle +beezer +belair +belgium +believe +belinda +belize +belkin +bell +bella +bella1 +bellaco +bellagio +belle +belly +belmont +beloved +benben +bender +bendover +benfica +beng +bengal +bengals +benito +benjamin +benji +bennett +bennie +benny +benny1 +benoit +benson +bentley +benton +benz +beowulf +beretta +berger +bergkamp +berkeley +berlin +bermuda +bernard +bernie +berry +bert +bertha +bertie +bertram +bessie +best +bestbuy +bestfriend +beta +beth +bethany +betsy +better +bettina +betty +bettyboo +beverly +beyonce +bian +bianca +biao +biatch +bibi +bicycle +big1 +bigal +bigass +bigbad +bigballs +bigbear +bigben +bigbig +bigbird +bigblack +bigblock +bigblue +bigbob +bigboobs +bigbooty +bigboss +bigboy +bigbucks +bigbutt +bigcat +bigcock +bigd +bigdad +bigdaddy +bigdawg +bigdick +bigdick1 +bigdicks +bigdog +bigdog1 +bigfish +bigfoot +bigger +biggie +biggles +biggun +bigguns +bigguy +bighead +bigjim +bigjohn +bigmac +bigman +bigmike +bigmoney +bignuts +bigone +bigones +bigpenis +bigpimp +bigpoppa +bigred +bigred1 +bigsexy +bigshow +bigtime +bigtit +bigtits +bigtruck +biguns +biit +bike +biker +bikers +bikini +bilbo +bill +bill1 +billabon +billbill +billie +billows +bills +billy +billy1 +billybob +billyboy +bimbo +bimmer +binder +bing +bingo +bingo1 +binky +binladen +biology +bird +bird33 +birddog +birdie +birdman +birgit +birthday +birthday1 +birthday4 +biscuit +bishop +bismark +bitch +bitch1 +bitchass +bitches +bitchy +bite +biteme +biteme1 +bitter +bizkit +bizzare +bjhgfi +blabla +black +black1 +blackbir +blackcat +blackcoc +blackdog +blackhaw +blackice +blackie +blackjac +blackjack +blacklab +blackman +blackout +blacks +blacky +blade +blade1 +blades +blaine +blair +blake +blake1 +blam +blanca +blanche +blanco +blank +blanked +blast +blaster +blaze +blazer +blazers +bledsoe +blender +blessed +blessing +blind +blink +blink182 +blinky +bliss +blitz +blizzard +blobby +block +bloke +blond +blonde +blondes +blondie +blonds +blondy +blood +bloody +blossom +blow +blowfish +blowjob +blowme +blubber +blue +blue1 +blue11 +blue12 +blue123 +blue1234 +blue22 +blue23 +blue32 +blue42 +blue99 +blueball +bluebell +blueberr +bluebird +blueblue +blueboy +bluedog +blueeyes +bluefish +bluejay +bluejays +bluemoon +blues +blues1 +bluesky +bluesman +blunt +blunts +bmw325 +bmwbmw +board +boat +boater +boating +boats +bob123 +bobafett +bobb +bobbie +bobbob +bobby +bobby1 +bobcat +bobdole +bobdylan +bobo +bobobo +body +boeing +bogart +bogey +bogota +bogus +bohica +boiler +boingo +bolitas +bollocks +bollox +bologna +bolton +bomb +bombay +bomber +bombers +bonanza +bonbon +bond +bond007 +bondage +bone +bonehead +boner +boners +bones +bong +bonghit +bongo +bonita +bonjour +bonjovi +bonkers +bonner +bonnie +bonovox +bonsai +bonzai +bonzo +boob +boobear +boobed +boobie +boobies +booboo +booboo1 +boobs +booger +booger1 +boogers +boogie +book +booker +bookie +books +bookworm +boom +boomer +boomer1 +booper +booster +boot +bootie +bootleg +boots +bootsie +bootsy +booty +bootys +booyah +boozer +bopper +borabora +bordeaux +border +borders +boricua +boris +borussia +bosco +bosco1 +boss +bosshog +bossman +boston +boston1 +bottle +bottom +boulder +bounce +bouncer +bounty +bourbon +bowie +bowl +bowler +bowling +bowman +bowser +bowtie +bowwow +boxcar +boxer +boxers +boxing +boxster +boyboy +boys +boytoy +boyz +bozo +bp2002 +br0d3r +br549 +brad +bradford +bradley +brady +brain +brains +branch +branden +brandi +brando +brandon +brandon1 +brandy +brandy1 +brasil +braves +braves1 +bravo +bravo1 +brazil +bread +break +breaker +breanna +breast +breasts +breath +breeze +bremen +brenda +brenda1 +brendan +brenna +brennan +brent +brent1 +brest +brett +brewer +brewster +brian +brian1 +briana +brianna +brick +bricks +bridge +bridget +briggs +bright +brighton +brigitte +brisbane +bristol +british +britney +britt +brittany +brittney +broad +broadway +brodie +broken +broker +bronco +broncos +broncos1 +bronson +bronze +brook +brooke +brooklyn +brooks +brother +brothers +brown +brown1 +brownie +browning +browns +bruce +bruce1 +brucelee +bruins +bruiser +bruno +bruno1 +brutus +bryan +bryan1 +bryant +bryce +btnjey +bubba +bubba1 +bubba123 +bubba2 +bubba69 +bubbas +bubble +bubbles +bubbles1 +buceta +buck +buckaroo +bucker +bucket +buckeye +buckeyes +buckley +bucks +buckshot +bucky +budapest +budd +buddah +buddha +buddie +buddies +buddy +buddy1 +buddy123 +buddy2 +buddyboy +buddys +budgie +budlight +budman +buds +budweise +buff +buffa +buffalo +buffalo1 +buffet +buffett +buffy +buffy1 +buford +bugger +bugman +bugs +buick +builder +building +bukkake +bukowski +bull +bulldawg +bulldog +bulldog1 +bulldogs +bullet +bulletin +bullfrog +bullock +bulls +bulls1 +bulls23 +bullseye +bullshit +bullwink +bully +bumble +bummer +bumper +bundy +bunghole +bungle +bunker +bunnies +bunny +bunny1 +burger +burly +burn +burner +burning +burnout +burns +burrito +burton +bush +bushido +business +businessbabe +busted +buster +buster1 +bustle +busty +butch +butch1 +butcher +butkus +butler +butt +butter +buttercu +butterfl +butterfly +butters +buttfuck +butthead +butthole +buttman +button +buttons +butts +buzz +buzzard +buzzer +byebye +byron +byteme +c7lrwu +cabbage +cabernet +cable +cabrio +cabron +caca +cactus +caddy +cadillac +caesar +cafc91 +caitlin +cajun +cake +caldwell +caleb +calendar +calgary +cali +calibra +calico +caliente +californ +california +caligula +calimero +call +callaway +callie +calling +callisto +callum +calvin +calvin1 +calypso +camaro +camaro1 +camaross +camber +cambridg +camden +came11 +camel +camel1 +camelot +camels +cameltoe +camera +camero +camero1 +cameron +cameron1 +camila +camilla +camille +camp +campbell +camper +camping +canada +canada1 +canadian +cancel +cancer +cancun +candace +candice +candle +candy +candy1 +candyass +candyman +candys +cang +canine +cannabis +cannon +canon +cantona +cantor +canuck +canucks +canyon +capcom +capecod +capetown +capital +capitals +capone +caprice +capricor +capslock +captain +captain1 +caracas +caramel +caravan +carbon +card +cardiff +cardinal +cardinals +cards +care1839 +carebear +carina +carl +carla +carlito +carlitos +carlo +carlos +carlos1 +carlton +carman +carmel +carmen +carmex2 +carnage +carnival +carol +carola +carole +carolina +caroline +carolyn +carpedie +carpente +carpet +carrera +carrie +carroll +carrot +carrots +cars +carson +carsten +carter +cartman +cartman1 +cartoon +cartoons +carver +casanova +cascade +case +casey +casey1 +cash +cashflow +cashmone +casino +casio +casper +casper1 +cassandr +cassandra +cassidy +cassie +caster +castillo +castle +castor +castro +cat123 +catalina +catalog +catcat +catch22 +catcher +catdog +catfight +catfish +catfood +catherin +catherine +cathy +catman +catnip +cats +catter +cattle +catwoman +caught +cavalier +caveman +cayman +cazzo +cbr600 +cbr900 +cbr900rr +ccbill +cccc +ccccc +ccccc1 +cccccc +cccccc1 +ccccccc +cccccccc +ceasar +cecile +cecilia +cedric +celeb +celebrity +celeron +celeste +celica +celine +celtic +celtics +cement +ceng +center +central +century +cerberus +cessna +cezer121 +ch5nmk +chacha +chachi +chad +chadwick +chai +chains +chainsaw +chair +challeng +challenge +chamber +chambers +champ +champ1 +champion +champs +chan +chance +chance1 +chandler +chandra +chanel +chang +change +changeme +changes +channel +chantal +chao +chaos +chaos1 +chapman +chappy +charge +charger +chargers +charisma +charity +charlene +charles +charles1 +charley +charlie +charlie1 +charlie123 +charlie2 +charlott +charlotte +charlton +charly +charmed +charming +charon +charter +chas +chase +chase1 +chaser +chat +chateau +chatham +chavez +cheater +check +checker +checkers +checkmat +cheddar +cheeba +cheech +cheeks +cheeky +cheerleader +cheerleaers +cheers +cheese +cheese1 +cheesy +cheetah +chef +chelle +chelsea +chelsea1 +chemical +chemist +chemistry +chen +cheng +cherie +cherokee +cherries +cherry +cherry1 +cheryl +cheshire +chess +chessie +chester +chester1 +chestnut +chevelle +chevrole +chevrolet +chevy +chevy1 +chevys +chewbacc +chewey +chewie +chewy +cheyenne +chicago +chicago1 +chichi +chick +chicken +chicken1 +chickens +chicks +chico +chief +chiefs +chiks +child +children +chill +chilli +chillin +chilly +chimera +china +chinese +chino +chinook +chip +chipmunk +chipper +chippy +chips +chiquita +chitown +chivas +chloe +chloe1 +chocha +chocolat +chocolate +choice +choke +chong +chooch +choochoo +chopin +chopper +chou +chowder +chris +chris1 +chris123 +chrisbln +chriss +chrissy +christ +christa +christi +christia +christian +christie +christin +christina +christine +christma +christmas +christo +christop +christoph +christopher +christy +chrome +chronic +chrono +chronos +chrysler +chuai +chuan +chuang +chubby +chuck +chuck1 +chuckie +chuckles +chucky +chui +chun +chunky +chuo +church +churchil +ciccio +cicero +cigar +cigars +cinder +cinderella +cindy +cindy1 +cinema +cinnamon +circle +circuit +circus +cirrus +cisco +citadel +citation +citizen +citroen +city +civic +civicsi +civilwar +claire +clancy +clapton +clarence +clarinet +clarissa +clark +clarke +clarkie +class +classic +classics +classroom +claude +claudia +claudia1 +claudio +clay +claymore +clayton +clean +cleaner +clement +clemente +clemson +cleo +cleopatr +clevelan +cleveland +clever +click +cliff +clifford +clifton +climax +climber +climbing +clint +clinton +clipper +clippers +clips +clit +clitoris +clock +close +closer +closeup +close-up +cloud +cloud9 +clouds +cloudy +clover +clovis +clown +clowns +clticic +club +clueless +cluster +clusters +clutch +clyde +cmfnpu +cn42qj +coach +coach1 +coaster +cobain +cobalt +cobra +cobra1 +cobras +cocacola +cocaine +cock +cocker +cocks +cocksuck +cocksucker +cocktail +coco +cocoa +cococo +coconut +code +codered +cody +coffee +cohiba +coke +cola +cold +coldbeer +coldplay +cole +coleman +colin +collect +colleen +college +collie +collin +collins +colnago +colombia +colonel +colonial +colony +color +colorado +colors +colt +colt45 +colton +coltrane +colts +columbia +columbus +comanche +combat +comcast +come +comedy +comein +comet +comets +comfort +comics +coming +command +commande +commander +commando +comment +common +comp +compact +company +compaq +compaq1 +compass +complete +compton +computer +comrade +comrades +conan +concept +concord +concorde +concrete +condom +condor +confused +cong +connect +conner +connie +connor +conover +conquest +conrad +console +constant +consult +consumer +contact +contains +content +contest +contortionist +contour +contract +control +conway +coochie +cook +cookie +cookie1 +cookies +cooking +cool +coolcat +coolcool +cooldude +cooler +coolguy +coolhand +coolio +coolman +coolness +cooper +cooper1 +coors +cooter +copenhag +copper +coral +corbin +core +corey +corina +corinna +corinne +corky +corleone +corn +corndog +cornelius +cornell +corner +cornflake +cornhole +cornwall +corolla +corona +corps +corrado +corsair +corvet07 +corvette +corwin +cory +cosmic +cosmo +cosmos +costello +cosworth +cottage +cotton +coucou +cougar +cougars +counter +country +county +couples +courage +courier +court +courtney +coventry +cowboy +cowboy1 +cowboys +cowboys1 +cowgirl +cows +coyote +cq2kph +crack +cracker +craft +craig +cramps +crane +crap +crappy +crash +crash1 +crave +craven +craving +crawford +crazy +crazy1 +crazybab +crazyman +cream +creampie +creamy +create +creation +creative +creature +credit +creed +creepers +creepy +crescent +crew +cricket +cricket1 +criminal +crimson +crispy +crissy +cristian +cristina +critter +cromwell +crosby +cross +crow +crown +cruise +cruiser +crumbs +crunch +crusader +crusher +crusty +crystal +crystal1 +csfbr5yy +cthulhu +cuan +cubbies +cubs +cubswin +cuddles +cuervo +culinary +cumcum +cumm +cummer +cumming +cummins +cumshot +cumslut +cunt +cunts +cupcake +cupoi +curious +current +curtis +custer +custom +customer +cute +cutie +cutiepie +cutlass +cutter +cuxldv +cwoui +cyber +cybersex +cyborg +cyclone +cyclones +cyclops +cygnus +cygnusx1 +cynthia +cypher +cypress +cyprus +cyrano +cyrus +cyzkhw +d6o8pm +d6wnro +d9ebk7 +d9ungl +dabears +dabomb +dabulls +dad2ownu +dada +dadada +daddy +daddy1 +daddyo +daddys +daedalus +daemon +daewoo +daffy +dagger +dagmar +daily +daisey +daisy +daisy1 +daisydog +dakota +dakota1 +dale +dalejr +dallas +dallas1 +dalshe +dalton +damage +daman +damian +damien +dammit +damn +damned +damnit +damon +dana +dance +dancer +dancer1 +dancing +dandan +dandfa +dandy +dang +danger +dani +daniel +daniel1 +daniela +daniele +danielle +daniels +dank +danman +danni +danny +danny1 +dannyboy +dante +dante1 +danzig +daphne +dapzu455 +daredevi +darian +darius +dark +darkange +darkangel +darklord +darkman +darkness +darkone +darkside +darkstar +darlene +darling +darrel +darrell +darren +darryl +darth +darthvad +darwin +dasani +data +database +datsun +daughter +dave +dave1 +davecole +davedave +david +david1 +davidb +davide +davids +davidson +davies +davinci +davis +dawg +dawgs +dawn +dawson +daylight +days +dayton +daytona +dddd +ddddd +ddddd1 +dddddd +dddddd1 +ddddddd +dddddddd +de7mdf +deacon +dead +deadhead +deadly +deadman +deadpool +deadspin +deal +dealer +dean +deanna +death +death1 +death666 +deaths +debbie +debbie1 +deborah +debra +december +decimal +decker +dede +deedee +deejay +deep +deeper +deepthroat +deer +deerhunt +deeznuts +deeznutz +default +defender +defense +defiant +deftones +dehpye +dejavu +delaney +delaware +delboy +delete +delight +delilah +deliver +dell +delldell +delmar +delphi +delpiero +delta +delta1 +deltas +deluxe +demo +demon +demons +dempsey +denali +deng +denied +deniro +denise +denmark +dennis +density +dental +dentist +denver +depeche +deputy +derek +derf +derick +derrick +descent +desert +design +designer +desire +desiree +deskjet +desktop +desmond +destin +destiny +destiny1 +destroy +details +detect +detectiv +detroit +deuce +deutsch +develop +device +devil +devil666 +devildog +deville +devilman +devils +devin +devine +devlt4 +devo +devon +dewalt +dexter +dga9la +dharma +dhip6a +diablo +diablo2 +diamond +diamond1 +diamonds +dian +diana +diane +dianne +diao +diaper +diapers +dick +dick1 +dickdick +dickens +dicker +dickhead +dickie +dicks +dicky +diego +diehard +diesel +dietcoke +dieter +digger +diggler +digimon +digital +digital1 +dilbert +dilbert1 +dildo +dilligaf +dillon +dima +dimas +dimples +ding +dingbat +dingdong +dinger +dingle +dingo +dinner +dino +dinosaur +dipper +dipshit +dipstick +direct +director +dirk +dirt +dirtbike +dirty +dirty1 +dirtydog +disaster +disco +discover +discovery +discus +disney +disney1 +ditto +diva +dive +diver +diver1 +divers +divine +diving +division +divorce +divx1 +dixie +dixie1 +dizzy +django +dnsadm +doberman +doctor +dodge +dodge1 +dodger +dodgeram +dodgers +dodgers1 +dodo +dododo +dog123 +dogbert +dogbone +dogboy +dogcat +dogdog +dogface +dogfart +dogfood +dogg +dogger +dogggg +doggie +doggies +doggy +doggy1 +doghouse +dogman +dogmeat +dogpound +dogs +dogshit +dogwood +doit +doitnow +dolemite +doll +dollar +dollars +dolly +dolores +dolphin +dolphin1 +dolphins +domain +dome +domingo +dominic +dominick +dominik +dominion +dominiqu +dominique +domino +donald +dondon +done +dong +donjuan +donkey +donna +donna1 +donner +donnie +donovan +dontknow +donut +donuts +doobie +doodle +doodles +doodoo +doofus +doogie +dookie +dooley +doom +doomsday +door +doors +dope +doqvq3 +doreen +dorian +doris +dork +dorothy +dotcom +dottie +double +doubled +douche +doudou +doug +dougal +doughboy +doughnut +dougie +douglas +down +downer +downhill +downtown +draco +dracula +draft +drag0n +dragon +dragon1 +dragon12 +dragon69 +dragonba +dragonball +dragonfl +dragonfly +dragons +dragoon +dragster +drake +draven +dream +dreamcas +dreamer +dreamer1 +dreaming +dreams +dresden +drevil +drew +drifter +driller +drinker +drinks +dripping +drive +driven +driver +drizzt +droopy +drop +drowssap +drpepper +drum +drummer +drummer1 +drums +drunk +drywall +dshade +dte4uw +duan +duane +dublin +ducati +duchess +duck +duckie +duckman +ducks +ducky +dude +dudedude +dudeman +dudes +dudley +duffer +duffman +duffy +duke +dukeduke +dumb +dumbass +dummy +dunbar +duncan +dundee +dungeon +dunhill +dunlop +dupont +durango +durham +dust +duster +dustin +dusty +dusty1 +dutch +dutchess +dvader +dwayne +dwight +dylan +dylan1 +dynamic +dynamite +dynamo +dynasty +e5pftu +eagle +eagle1 +eagle2 +eagles +eagles1 +earl +earnhard +earth +earthlin +earthlink +east +easter +eastern +easton +eastside +eastwood +easy +eating +eatme +eatme1 +eatme69 +eatmenow +eatpussy +eatshit +ebony +echo +eclipse +eclipse1 +eddie +eddie1 +eddy +eded +edgar +edge +edgewise +edinburgh +edison +edition +editor +edmonton +edthom +eduard +eduardo +edward +edward1 +edwards +edwin +eeee +eeeee +eeeee1 +eeeeee +eeeeee1 +eeeeeee +eeeeeeee +eeyore +efyreg +egghead +eggman +eggplant +eight +eighteen +eighty +eileen +einstein +ejaculation +ekim +elaine +elcamino +eldiablo +eldorado +eleanor +electra +electric +electro +electron +elefant +elektra +element +elephant +eleven +elijah +elisabet +elite +elizabet +elizabeth +ella +ellen +ellie +elliot +elliott +ellis +elmer +elmo +elodie +eloise +elpaso +elvira +elvis +elvis1 +elvisp +elway +elway7 +elwood +email +e-mail +embalmer +emerald +emerson +emilia +emilie +emilio +emily +emily1 +eminem +emma +emmanuel +emmett +emmitt +emperor +empire +encore +ender +energy +enforcer +engage +engine +engineer +england +england1 +english +enigma +enjoy +enough +enrico +enrique +enter +enter1 +enterme +enternow +enterpri +enterprise +enters +entrance +entropy +entry +envelope +epsilon +epson +epvjb6 +equinox +eraser +erasure +erection +eric +eric1 +erica +ericsson +erik +erika +erin +ernest +ernesto +ernie +erotic +erotica +errors +erwin +escalade +escape +escort +eskimo +espana +espresso +esquire +estate +estelle +esther +estrella +eternal +eternity +ethan +etvww4 +euclid +eugene +eureka +europa +europe +evan +evangeli +evans +evelyn +everest +everett +everlast +everton +evil +evilone +evolutio +ewtosi +ewyuza +excalibu +excalibur +excel +excess +exchange +excite +exeter +exodus +exotic +experience +experienced +expert +explore +explorer +export +express +express1 +extensa +extension +extra +extreme +eyes +eyphed +f**k +f00tball +fabian +face +facial +factory +faculty +faggot +fairlane +faith +faith1 +faithful +falcon +falcon1 +falcons +fallen +falling +fallon +fallout +family +famous +fanatic +fandango +fang +fanny +fantasia +fantasies +fantasy +farley +farm +farmboy +farmer +farrell +farscape +farside +fart +fartman +fashion +fast +fastball +faster +fatass +fatcat +father +fatima +fatluvr69 +fatman +fatty +faust +favorite +favorite2 +favorite6 +fdm7ed +fdsa +fear +fearless +feather +feathers +february +federal +federico +feedback +feelgood +feeling +feet +felicia +feline +felipe +felix +felix1 +fellatio +fellow +female +females +fender +fender1 +feng +fenris +fenway +fergie +fergus +ferguson +fermat +fernando +ferrari +ferrari1 +ferret +ferris +fester +festival +fetish +fettish +fever +ffff +fffff +fffff1 +ffffff +ffffff1 +fffffff +ffffffff +ffvdj474 +fick +ficken +fiction +fiddle +fidelio +fidelity +field +fields +fiesta +figaro +fight +fighter +fighting +figure +fihdfv +film +films +films+pic+galeries +filter +filthy +final +finally +finance +finder +fine +finger +fingerig +fingers +finish +finite +finland +fire +fire1 +fireball +firebird +fireblad +firedog +firefigh +firefire +firefly +firefox +firehawk +fireman +firenze +firewall +first +fischer +fish +fishbone +fishcake +fisher +fisherma +fishes +fishfish +fishhead +fishin +fishing +fishing1 +fishman +fishon +fishtank +fishy +fist +fister +fisting +fitness +fitter +five +flame +flames +flamingo +flanders +flange +flanker +flash +flash1 +flasher +flashman +flathead +fleming +flesh +fletch +fletcher +fleurs +flex +flexible +flicks +flight +flint +flip +flipflop +flipmode +flipper +float +floppy +florence +flores +florian +florida +florida1 +flounder +flow +flower +flower1 +flower2 +flowers +floyd +flubber +fluff +fluffy +flyboy +flyer +flyers +flyers88 +flyfish +flying +fmale +focus +follow +foobar +food +fool +foolish +foot +football +football1 +footjob +forbes +force +ford +fordf150 +foreman +foreplay +foreskin +forest +forever +forfun +forget +forgetit +forgot +forlife +format +forme +formula +formula1 +forrest +forsaken +fortress +fortuna +fortune +fortune12 +forum +forumwp +forward +fossil +foster +fosters +fountain +four +fourier +fowler +foxfire +foxtrot +foxy +foxylady +fozzie +fqkw5m +frame +fran +france +frances +francesc +francine +francis +franco +francois +frank +frank1 +frankfurt +frankie +frankie1 +franklin +franks +franky +fraser +frazier +freak +freaked +freaks +freaky +freckles +fred +freddie +freddy +freddy1 +frederic +fredfred +fredrick +free +freedom +freedom1 +freee +freefall +freefree +freeman +freepass +freeporn +freesex +freeuser +freeway +freewill +freeze +french +frenchie +frenchy +fresh +fresno +friday +fridge +friend +friendly +friends +friendship +fright +fringe +frisbee +frisco +frisky +fritz +frodo +frodo1 +frog +frogfrog +frogger +froggie +froggy +frogman +frogs +front242 +frontier +frosch +frost +frosty +frozen +fruit +fruity +fuaqz4 +fubar +fubar1 +fucing +fuck +fuck_inside +fuck1 +fuck123 +fuck69 +fucked +fucker +fucker1 +fuckers +fuckface +fuckfuck +fuckhead +fuckher +fuckin +fucking +fuckinside +fuckit +fuckme +fuckme1 +fuckme2 +fuckoff +fuckoff1 +fucks +fuckthis +fucku +fucku2 +fuckyou +fuckyou1 +fuckyou2 +fucmy69 +fudge +fugazi +fuking +fulham +full +fullback +fuller +fullmoon +function +funfun +fungus +funk +funky +funny +funny1 +funstuff +funtime +funtimes +furball +furious +fusion +fussball +futbol +future +fuzzball +fuzzy +fuzzy1 +fwsadn +fx3tuo +fzappa +g3ujwg +g9zns4 +gabber +gabby +gabriel +gabriel1 +gabriela +gabriell +gadget +gaelic +gagged +gagging +galant +galary +galaxy +galeries +galileo +gallaries +galore +galway +gambit +gamble +gambler +game +gameboy +gamecock +gamecube +gameover +games +gamma +gandalf +gandalf1 +ganesh +gang +gangbang +gangbanged +gangsta +gangster +ganja +garage +garbage +garcia +garden +gardner +gareth +garfield +gargoyle +garion +garland +garlic +garner +garnet +garrett +garrison +gary +gasman +gaston +gate +gates +gateway +gateway1 +gateway2 +gator +gator1 +gatorade +gators +gators1 +gatsby +gauss +gavin +gawker +gayboy +gaymen +gbhcf2 +gecko +geezer +geheim +geil +gemini +gene +general +general1 +generals +generator +generic +genesis +genesis1 +geneva +geneviev +geng +genius +gentle +geoffrey +george +george1 +georgia +georgie +gerald +gerard +gerber +gerbil +gerhard +gerhardt +german +germany +geronimo +gerry +gertrude +geryfe +gesperrt +getit +getmoney +getoff +getout +getsdown +getsome +getting +gforce +gfxqx686 +gggg +ggggg +ggggg1 +gggggg +gggggg1 +ggggggg +gggggggg +ghetto +ghost +ghost1 +ghosts +gianni +giant +giants +giants1 +gibson +gibson1 +gideon +gidget +giggle +giggles +gigi +gilbert +gilles +gillian +gilligan +gilmore +gina +ginger +ginger1 +ginscoot +giorgio +giovanna +giovanni +giraffe +girfriend +girl +girlie +girlies +girls +girls1 +girsl +giuseppe +giveitup +giveme +gizmo +gizmo1 +gizmodo +gizmodo1 +gizzmo +glacier +gladiato +gladiator +gladys +glasgow +glass +glasses +gldmeo +glen +glenda +glendale +glenn +glennwei +glitter +global +glock +gloria +glory +glotest +glover +gloves +glow +gman +gmoney +gnasher23 +goal +goalie +goat +goats +goaway +gobears +goblin +goblue +gobucks +gocats +gocubs +godboy +goddess +godfathe +godfather +godiva +godsmack +godspeed +godzilla +goethe +gofast +gofish +goforit +gogators +gogo +gogogo +gohan +gohome +goirish +goku +gold +goldberg +golden +golden1 +goldeney +goldfing +goldfish +goldie +goldstar +goldwing +golf +golf1 +golfball +golfer +golfer1 +golfgolf +golfgti +golfing +golfman +golfnut +golfpro +goliath +gollum +gomets +gomez +gonavy +gone +gong +gonzales +gonzalez +gonzo +gonzo1 +goober +goochi +good +goodboy +goodbye +goodday +goodfell +goodgirl +goodie +goodluck +goodman +goodsex +goodtime +goodyear +goofball +goofy +goofy1 +google +googoo +gooner +goose +goose1 +gooseman +gopack +gopher +gordo +gordon +gordon24 +gore +gorgeous +gorilla +gotcha +goten +gotenks +goth +gotham +gothic +gotmilk +gotohell +gotribe +gotyoass +govols +grace +grace1 +gracie +graduate +graham +gramma +grammy +granada +grand +grandam +grande +grandma +grandpa +granite +granny +grant +grapes +graphic +graphics +grass +grateful +gratis +graves +gravity +gray +graywolf +grease +great +great1 +greatest +greatone +greece +greedy +greek +green +green1 +green123 +greenbay +greenday +greene +greenman +greens +greg +gregor +gregory +gregory1 +gremlin +grendel +gretchen +gretel +gretzky +greywolf +griffey +griffin +griffith +grils +grimace +grinch +grinder +gringo +grizzly +gromit +groove +groovy +groucho +ground +groups +grover +grumpy +grunt +gryphon +gspot +gstring +gsxr1000 +gsxr750 +guai +guan +guang +guard +guardian +gubber +gucci +guess +guest +guido +guiness +guinness +guitar +guitar1 +guitars +gumbo +gumby +gundam +gunnar +gunner +gunners +guns +gunther +guru +gustav +gustavo +gutter +guyver +gwju3g +gymnast +gymnastic +gypsy +h2slca +ha8fyp +hack +hacker +haggis +haha +hahaha +hahahaha +hailey +hair +hairball +hairy +hakr +hal9000 +haley +halflife +halifax +hall +hallie +hallo +hallowee +halloween +hambone +hamburg +hamilton +hamish +hamlet +hammer +hammer1 +hammers +hammond +hamper +hampton +hamster +hancock +hand +handball +handsome +handyman +hang +hank +hanna +hannah +hannah1 +hannes +hannibal +hans +hansen +hansolo +hanson +happines +happy +happy1 +happy123 +happy2 +happyday +happydog +happyman +harald +harbor +harcore +hard +hardball +hardcock +hardcore +harddick +harder +hardon +hardone +hardrock +hardware +hardwood +hardy +harlem +harley +harley1 +harman +harmony +harold +harper +harpoon +harrier +harriet +harris +harrison +harry +harry1 +harrypotter +hart +hartford +hartley +harvard +harvest +harvey +hassan +hastings +hate +hatred +hatter +hattrick +havana +havefun +having +hawaii +hawaii50 +hawaiian +hawk +hawkeye +hawkeyes +hawkins +hawks +hawks1 +hawkwind +hawthorn +hayabusa +hayden +hayley +hazard +hazmat +hcleeb +head +health +heart +hearts +heat +heater +heather +heather1 +heaven +heavy +hector +hedgehog +hedges +heeled +heels +hehehe +heidi +heidi1 +heineken +heinrich +heka6w2 +helen +helena +helene +helium +hell +hellas +hellfire +hellno +hello +hello1 +hello123 +hello2 +hellohel +helloo +hellos +hellyeah +helmet +helmut +help +helper +helpme +hemlock +hendrix +heng +henrik +henry +henry1 +hentai +henti +herbert +herbie +hercules +here +heretic +herewego +heritage +herman +hermes +hero +heroes +herring +hershey +hester +hetfield +hevnm4 +hewitt +hewlett +heyhey +heynow +heyyou +hgfdsa +hhhh +hhhhh +hhhhh1 +hhhhhh +hhhhhh1 +hhhhhhh +hhhhhhhh +hidden +higgins +high +highbury +higher +highheel +highland +highlander +highlife +highway +hihihi +hihje863 +hiking +hilary +hilbert +hill +hillary +hillbill +hills +hillside +hilltop +hilton +hiphop +hippie +hippo +history +hitachi +hithere +hitler +hitman +hitter +hiziad +hjkl +hobbes +hobbit +hockey +hockey1 +hoes +hoffman +hogan +hogtied +hohoho +hokies +hola +holden +hole +holein1 +holes +holger +holiday +holidays +holla +holland +hollie +hollow +holly +holly1 +hollywoo +hollywood +holmes +holycow +holyshit +home +homeboy +homely +homemade +homepage +homepage- +homer +homer1 +homerj +homers +homerun +homework +honda +honda1 +hondas +honesty +honey +honey1 +honeybee +honeydew +honeys +hong +hongkong +honolulu +honor +hoochie +hook +hookem +hooker +hookers +hookup +hooligan +hooper +hoops +hoosier +hoosiers +hooter +hooters +hooters1 +hootie +hoover +hooyah +hope +hopeful +hopeless +hopkins +hopper +horace +hores +horizon +horn +horndog +hornet +hornets +horney +horny +horny1 +hornyman +horror +horse +horse1 +horseman +horsemen +horses +horton +hose +hoser +hotass +hotbox +hotboy +hotdog +hotel +hotel6 +hotgirl +hotgirls +hothot +hotlegs +hotlips +hotmail +hotmail0 +hotmail1 +hotone +hotpussy +hotrats +hotred +hotrod +hotsex +hotshot +hotspur +hotstuff +hott +hotter +hottest +hottie +hotties +houdini +houhou +hound +hounddog +hounds +house +house1 +houses +housewife +housewifes +houston +houston1 +hover +howard +howdy +howell +howie +hpk2qc +hr3ytm +hrfzlz +huai +huan +huang +hubert +hudson +hufmqw +huge +hugetits +hughes +hugo +hugohugo +hulk +humbug +hummer +humphrey +hun999 +hung +hungry +hunt +hunter +hunter1 +hunting +hurley +hurrican +hurricane +husband +husker +huskers +huskers1 +huskies +husky +hustler +hybrid +hydro +hyperion +hzze929b +i62gbq +iamgod +iawgk2 +ib6ub9 +ibanez +ibilltes +ibxnsm +iceberg +icecream +icecube +icehouse +iceland +iceman +iceman1 +icu812 +idefix +idiot +idontkno +idontknow +idunno +iforget +iforgot +igor +iguana +ihateyou +iiii +iiiii +iiiiii +iiiiii1 +iiiiiii +iiiiiiii +ilikeit +illini +illinois +illmatic +illusion +ilovegod +iloveit +ilovejesus +iloveme +ilovesex +iloveu +iloveyou +iloveyou! +iloveyou1 +iloveyou2 +image +imagine +imation +imback +imissyou +immortal +impact +impala +imperial +implants +impreza +incest +include +incubus +indain +india +indian +indiana +indians +indigo +indon +indonesia +indy +indycar +infantry +inferno +infinite +infiniti +infinity +info +ingrid +innocent +insane +insanity +insert +insertion +insertions +inside +insider +insight +insomnia +inspiron +install +instant +instinct +integra +integral +intel +inter +interacial +intercourse +interest +intern +internal +internet +intj3a +intrepid +intruder +invest +invis +iomega +ipswich +iqzzt580 +ireland +irene +irish +irish1 +irishman +iron +ironman +irving +isaac +isabel +isabella +isabelle +isacs155 +isaiah +iscool +ishmael +island +islander +israel +istanbul +istheman +italia +italian +italiano +italy +itsme +ivan +iverson +iverson3 +iwantu +jabber +jabroni +jachin +jack +jack1 +jackal +jackass +jackass1 +jacket +jackie +jackjack +jackoff +jackpot +jackson +jackson1 +jackson5 +jacob +jacob1 +jacobs +jacques +jade +jaeger +jagger +jaguar +jaguar1 +jaguars +jaime +jakarta +jake +jakejake +jamaica +james +james007 +james1 +jamesbon +jamesbond +jameson +jamess +jamie +jamie1 +jammer +jammin +jane +janelle +janet +janice +janine +january +japan +japanees +japanes +japanese +jared +jarhead +jarjar +jarrett +jarrod +jarvis +jasmin +jasmine +jasmine1 +jason +jason1 +jasons +jasper +java +javelin +javier +jaybird +jayden +jayhawk +jayhawks +jayjay +jayman +jayson +jazz +jazzman +jazzy +jean +jeanette +jeanne +jeannie +jedi +jediknig +jeep +jeeper +jeepers +jeepjeep +jeepster +jeff +jefferso +jeffery +jeffjeff +jeffrey +jello +jelly +jellybea +jenifer +jenjen +jenkins +jenn +jenna +jennaj +jennie +jennifer +jennings +jenny +jenny1 +jensen +jeremiah +jeremy +jeremy1 +jericho +jerk +jerkoff +jerky +jermaine +jerome +jerry +jerry1 +jersey +jess +jesse +jesse1 +jessica +jessica1 +jessie +jester +jesus +jesus1 +jesuschrist +jeter2 +jethro +jets +jetski +jetta +jewel +jewell +jewels +jewish +jezebel +jian +jiang +jiao +jigga +jiggaman +jill +jillian +jimbeam +jimbo +jimbo1 +jimbob +jimi +jimjim +jimmie +jimmy +jimmy1 +jimmys +jing +jingle +jingles +jiong +jjjj +jjjjj +jjjjj1 +jjjjjj +jjjjjj1 +jjjjjjj +jjjjjjjj +jo9k2jw2 +joan +joanna +joanne +jocelyn +jockey +joe123 +joeblow +joebob +joecool +joejoe +joel +joelle +joemama +joey +johann +johanna +johannes +john +john1 +john123 +john316 +johnboy +johndeer +johndoe +johngalt +johnjohn +johnmish +johnnie +johnny +johnny1 +johnny5 +johnson +johnson1 +johnston +jojo +jojojo +jojojojo +joke +joker +joker1 +jokers +jolene +jolly +jomama +jonas +jonathan +jonathon +jonboy +jones +jones1 +jonesy +jonjon +jonny +jordan +jordan1 +jordan23 +jordon +jorge +jose +joseph +joseph1 +josephin +josh +joshua +joshua1 +josiah +josie +joung +journey +joyce +joyjoy +joystick +jsbach +juan +juanita +jubilee +judge +judith +judy +juggalo +jughead +juice +juicy +juju +jules +julia +julian +juliana +julie +julie1 +julien +juliet +juliette +julio +julius +july +jumbo +jump +jumper +june +juneau +junebug +jungle +junior +junior1 +juniper +junk +junkie +junkmail +jupiter +jupiter1 +jupiter2 +jurassic +just4fun +just4me +justdoit +justice +justin +justin1 +justine +justme +justus +juventus +jys6wz +k2trix +kaboom +kahlua +kahuna +kaiser +kaitlyn +kajak +kamikaze +kane +kang +kangaroo +kansas +kappa +kara +karachi +karaoke +karate +karen +karen1 +karin +karina +karine +karl +karma +kashmir +kasper +katana +katarina +kate +katherin +katherine +kathleen +kathryn +kathy +kathy1 +katie +katie1 +katrin +katrina +kawasaki +kayla +kaylee +kayleigh +kcchiefs +kcj9wx5n +keegan +keenan +keepass +keeper +keepout +keisha +keith +keith1 +keksa12 +keller +kelley +kellie +kelly +kelly1 +kelsey +kelvin +kendall +kendra +keng +kenken +kennedy +kenneth +kenny +kenny1 +kenobi +kenshin +kent +kentucky +kenwood +kenworth +kenzie +kermit +kermit1 +kernel +kerouac +kerry +kerstin +kestrel +ketchup +kevin +kevin1 +keyboard +keypass +keystone +keywest +khan +kick +kicker +kidney +kidrock +kids +kieran +kiki +kikiki +kikimora +kill +killa +killah +killbill +killer +killer1 +killers +killian +killjoy +killkill +killme +kilroy +kimball +kimber +kimberly +kimkim +kimmie +kimmy +kinder +king +kingdom +kingfish +kingkong +kingpin +kingrich +kings +kingston +kinky +kipper +kirby +kirk +kirkland +kirsten +kirsty +kismet +kiss +kisses +kissing +kisskiss +kissme +kitchen +kiteboy +kitkat +kitten +kittens +kittie +kitty +kitty1 +kittycat +kittykat +kittys +kiwi +kkkk +kkkkk +kkkkkk +kkkkkkk +kkkkkkkk +klaatu +klaus +kleenex +klingon +klondike +knickerless +knickers +knicks +knife +knight +knight1 +knights +knock +knockers +knuckles +knulla +koala +kobe +kodiak +kojak +koko +kokoko +kokomo +komodo +kong +konyor +kool +koolaid +kordell1 +korean +korn +kotaku +kram +kramer +kris +krishna +krissy +krista +kristen +kristi +kristian +kristie +kristin +kristin1 +kristina +kristine +kristy +kronos +krusty +krypton +krystal +kswbdu +kuai +kuan +kuang +kubrick +kugm7b +kume +kungfu +kurt +kyle +l2g7k3 +l8v53x +labia +labrador +labtec +lacrosse +ladder +laddie +ladies +lady +ladyboy +ladybug +laetitia +lager +lagnaf +laguna +lake +lakers +lakers1 +lakeside +lakewood +lakota +lala +lalakers +lalala +lalalala +lambda +lambert +lamer +lamont +lance +lancelot +lancer +lancia +land +lander +landmark +landon +lane +lang +lansing +lantern +laptop +lara +large +larissa +larkin +larry +larry1 +larson +laser +laser1 +laserjet +lassie +last +lasvegas +latex +latin +latina +latinas +latino +laughing +laura +laura1 +laurel +lauren +lauren1 +laurence +laurent +laurie +lavalamp +lawman +lawrence +lawson +lawyer +lazarus +lazy +lback +leader +leanne +leather +lebowski +ledzep +leeann +leeds +leedsutd +leelee +left +lefty +legacy +legal +legend +legends +legion +legman +legolas +legos +legs +leigh +leinad +lekker +leland +lemans +lemmein +lemon +lemonade +lemons +leng +lennon +lennox +lenny +leon +leonard +leonardo +leopard +leroy +lesbain +lesbean +lesbens +lesbian +lesbians +lesbos +lesley +leslie +lespaul +lestat +lester +lethal +letme1n +letmein +letmein1 +letmein2 +letmein22 +letmeinn +letmesee +letsdoit +letsgo +letter +letters +lewis +lexingky +lexmark +lexus +lgnu9d +lian +liang +liao +liberty +library +libre +lick +licker +licking +lickit +lickme +life +lifehack +lifetime +light +light1 +lighter +lighthou +lighting +lightnin +lightning +lights +lilbit +lilian +lilith +lillian +lillie +lilly +lily +limewire +limited +limpone +lincoln +lincoln1 +linda +linda1 +linden +lindros +lindsay +lindsey +line +ling +link +linkin +links +linux +lion +lionel +lionhear +lionking +lions +lipgloss +lips +lipstick +liquid +lisa +lisalisa +lissabon +list +listen +lister +lite +lithium +litle +little +little1 +littlema +live +liverpoo +liverpool +lives +living +lizard +lizzard +lizzie +lizzy +lkjh +lkjhg +lkjhgf +lkjhgfds +llamas +llll +lllll +llllll +lllllll +llllllll +lloyd +load +loaded +lobo +lobster +lock +lockdown +lockerroom +lockout +locks +loco +locust +locutus +logan +logan1 +logger +logical +logitech +loki +lola +lolipop +lolita +lollipop +lollol +lollypop +lolo +lololo +loloxx +lombard +london +london1 +lonely +lonesome +lonestar +lonewolf +long +longbow +longdong +longer +longhair +longhorn +longjohn +longshot +lonnie +look +looker +lookin +looking +lookout +loomis +looney +loop +loose +looser +lopez +lord +lorena +lorenzo +loretta +lori +lorraine +losangel +loser +loser1 +losers +lost +lotion +lottie +lotus +loud +louie +louis +louise +loulou +lounge +love +love1 +love12 +love123 +love69 +lovebug +loveit +lovejoy +lovelife +lovelove +lovely +loveme +lover +lover1 +loverboy +loverman +lovers +loves +lovesex +loveya +loveyou +loving +lowell +lowrider +loyola +luan +lucas +lucas1 +lucifer +lucille +luck +lucky +lucky1 +lucky13 +lucky7 +luckydog +luckyone +luckys +lucy +ludwig +luetdi +luft4 +luis +luke +lulu +lululu +lumber +lumina +luna +lunatic +lunchbox +lust +luther +luv2epus +lydia +lynn +m5wkqf +macaroni +macbeth +macdaddy +macgyver +machine +macintos +macintosh +mack +mackie +macleod +macmac +macman +macross +madcat +madcow +madden +maddie +maddog +maddux +madeline +madison +madison1 +madmad +madman +madmax +madness +madonna +madrid +maestro +mafia +magazine +magelan +magellan +magenta +maggie +maggie1 +maggot +magic +magic1 +magic32 +magical +magician +magick +magicman +magnet +magneto +magnolia +magnum +magnus +magpie +magpies +mahalo +mahler +maiden +mail +mailman +maine +mainland +majestic +major +makaveli +makayla +maker +malachi +malaka +malcolm +malibu +malice +mallard +mallorca +mallory +mallrats +malone +mama +mamacita +mamas +mammoth +management +manager +manchest +manchester +mancity +mandarin +manders +mandingo +mandrake +mandy +mandy1 +manfred +mang +manga +mango +mangos +manhatta +maniac +manila +mankind +manman +mann +manning +mannn +manny +manolo +manowar +manson +mantis +mantle +mantra +manu +manuel +manuela +manutd +maple +maradona +marathon +marauder +marble +marbles +marc +marcel +marcello +march +marcia +marcius2 +marco +marcos +marcus +margaret +margaux +margie +maria +maria1 +mariah +marian +mariana +marianne +marie +marie1 +marijuan +marilyn +marina +marine +marine1 +mariner +mariners +marines +marines1 +marino +marino13 +mario +mario1 +mario66 +marion +mariposa +marisa +marissa +marius +marjorie +mark +mark1 +marker +market +markie +markus +marlboro +marlene +marley +marlin +marlins +marlon +marma +marquis +marriage +married +mars +marsh +marsha +marshal +marshall +mart +martha +martian +martin +martin1 +martina +martine +martinez +martini +marty +marvel +marvin +mary +maryann +maryjane +maryland +masamune +maserati +mash4077 +mason +mason1 +massage +massimo +massive +master +master1 +master12 +masterbaiting +masterbate +masterbating +masterp +masters +masturbation +matador +matchbox +mate +material +mathew +matilda +matrix +matrix1 +matt +matteo +matter +matthew +matthew1 +matthews +matthias +mattie +matty +mature +maureen +maurice +maverick +max123 +maxdog +maxell +maxi +maxim +maxima +maxime +maximo +maximum +maximus +maxine +maxmax +maxwell +maxwell1 +maxx +maxxxx +maya +mayday +mayfair +mayhem +maynard +mazda +mazda6 +mazda626 +mazdarx7 +mccabe +mccarthy +mcdonald +mckenzie +mclaren +mdogg +meadow +meagan +meat +meatball +meathead +meatloaf +mechanic +media +medic +medic1 +medical +medicine +medina +medusa +meeting +mega +megadeth +megaman +megan +megan1 +megane +megapass +megatron +meggie +meghan +meier +meister +melanie +melanie1 +melina +melinda +melissa +melissa1 +mellon +mellow +melody +melons +melrose +melvin +member +members +meme +mememe +memorex +memory +memphis +menace +meng +mensuck +mental +menthol +mentor +meow +meowmeow +mephisto +mercedes +mercer +merchant +mercury +mercury1 +merde +meredith +meridian +merlin +merlin1 +merlot +merlyn +mermaid +merrill +message +messiah +messier +met2002 +metal +metal1 +metallic +metallica +meteor +method +methos +metoo +metro +mets +mexican +mexico +miami +miami1 +mian +miao +michael +michael1 +michael2 +michaela +michaels +micheal +michel +michele +michelle +michigan +mick +mickey +mickey1 +micky +micro +micron +microsof +microsoft +middle +midget +midland +midnight +midnite +midori +midway +mierda +mighty +miguel +mike +mike1 +mike123 +mike23 +mike69 +mikemike +mikey +mikey1 +milamber +milano +mildred +miles +miles1 +milfnew +military +milk +milkman +millenium +miller +miller1 +millie +million +millions +millwall +milo +milton +mimi +mind +mindy +mine +minemine +minerva +ming +mingus +mini +minime +minimoni +minimum +ministry +minnesot +minnie +minute +miracle +mirage +miranda +miriam +mirror +mischief +misery +misfit +misfit99 +misfits +misha +misses +mission +mississi +missouri +missy +missy1 +mister +mistral +mistress +misty +misty1 +mitch +mitchell +mittens +mizuno +mizzou +mmmm +mmmmm +mmmmmm +mmmmmmm +mmmmmmmm +mnbv +mnbvc +mnbvcx +mnbvcxz +mobile +mobydick +mocha +model +models +modelsne +modem +modena +modern +modles +mogwai +mohamed +mohammad +mohammed +mohawk +mojave +mojo +mollie +molly +molly1 +mollydog +molson +mommy +mommy1 +momo +momomo +momoney +momsuck +mona +monaco +monalisa +monarch +monday +monday1 +mondeo +mone +money +money1 +money123 +moneyman +moneys +mongo +mongoose +monica +monica1 +monies +monika +monique +monitor +monk +monkey +monkey1 +monkey12 +monkeybo +monkeys +monopoly +monroe +monsoon +monster +monster1 +monsters +montag +montana +montana1 +monte +montecar +monterey +month +montreal +montrose +monty +monty1 +moocow +mookie +moomoo +moon +moonbeam +moondog +mooney +moonligh +moonlight +moonman +moonshin +moore +moose +moose1 +mooses +mopar +morales +mordor +more +moreno +morgan +morgan1 +morgana +morgoth +moritz +morning +moron +morpheus +morris +morrison +morrow +mortal +morten +mortgage +morticia +mortimer +mortis +morton +moscow +moses +mother +mother1 +motherfucker +mothers +motion +motley +moto +motocros +motor +motorola +motors +motown +mounta1n +mountain +mouse +mouse1 +mouser +mouses +mousey +mouth +movie +movies +mozart +mozilla +mp8o6d +mpegs +mrbill +msnxbi +mudvayne +mufasa +muff +muffdive +muffin +muffin1 +muffy +mulder +mullet +mulligan +munch +munchkin +munich +munster +muppet +murder +murphy +murphy1 +murray +musashi +muschi +muscle +muscles +mushroom +music +music1 +musica +musical +musician +musicman +mustafa +mustang +mustang1 +mustang2 +mustang5 +mustang6 +mustangs +mustard +mutant +mutley +mwq6qlzo +mybaby +mydick +mygirl +mykids +mylife +mylove +mypass +myporn +myrtle +myself +myspace +myspace1 +mystery +mystic +mytime +myxworld +mzepab +nacked +nadia +nadine +naked +namaste +name +nana +nancy +nancy1 +nancy123 +nang +nanook +napalm +napoleon +napoli +napster +narnia +naruto +nascar +nascar1 +nascar24 +nash +nasty +nasty1 +natalia +natalie +natalie1 +natasha +natasha1 +natchez +nate +natedogg +nathalie +nathan +nathan1 +nathanie +nation +national +native +natural +nature +naughty +nautica +navajo +navy +navyseal +nazgul +nbvibt +ncc1701 +ncc1701a +ncc1701d +ncc1701e +ncc74656 +ndeyl5 +ne1469 +neal +nebraska +necklace +needle +needles +negative +neil +nellie +nelson +nemesis +nemrac58 +neng +neon +neptune +nermal +nero +nestle +netscape +nettie +netware +network +neutrino +neutron +nevada +never +nevermin +nevets +neville +newaccount +newark +newbie +newcastl +newcastle +newlife +newman +newness +newone +newpass +newpass6 +newport +news +newton +newuser +newyear +newyork +newyork1 +nextel +nexus6 +nguyen +nian +niang +niao +nice +niceass +niceguy +nicetits +nicholas +nichole +nick +nickel +nickie +nicky +nico +nicola +nicolas +nicole +nicole1 +nigga +nigger +nigger1 +night +nightmar +nightowl +nights +nightwin +nike +niki +nikita +nikki +nikki1 +niko +nikon +nimbus +nimda2k +nimitz +nimrod +nina +nine +nineball +nineinch +niners +nineteen +ning +ninguna +ninja +ninja1 +ninjas +nintendo +nipper +nipple +nipples +nirvana +nirvana1 +nissan +nissan1 +nitram +nitro +nitrox +nittany +nixon +njqcw4 +nnnn +nnnnn +nnnnnn +nnnnnnn +nnnnnnnn +noah +nobody +nocturne +noel +noelle +nofear +nogard +nokia +nolan +noles +noles1 +nolimit +nomad +nomore +noname +none +nonenone +nong +nono +nonono +noodle +noodles +nookie +nopass +nope +norbert +norfolk +normal +norman +normandy +norris +north +northern +norton +norway +norwich +norwood +nose +nostromo +notebook +nothing +notnow +notredam +nounours +nova +novell +november +novifarm +noway +nownow +nt5d27 +nuan +nuclear +nude +nudes +nudist +nudity +nugget +nuggets +null +number +nurse +nurses +nursing +nutmeg +nuts +nutter +nwo4life +nygiants +nyjets +nylons +nymets +nympho +nyyankee +oakland +oakley +oaktree +oasis +oatmeal +obelix +oberon +obiwan +objects +oblivion +obsession +obsidian +ocean +oceans +october +octopus +odessa +odin +odyssey +oedipus +oemdlg +office +officer +offroad +offshore +ohio +ohmygod +ohshit +ohyeah +oicu812 +oilers +okinawa +oklahoma +okokok +older +oldman +oldone +olemiss +olive +oliver +oliver1 +olivia +olivier +ollie +olympia +olympic +olympus +omar +omega +omega1 +omicron +onelove +oneone +onetime +onetwo +onion +onions +online +only +onlyme +onlyone +ontario +oooo +ooooo +oooooo +ooooooo +oooooooo +open +opendoor +openit +opennow +openup +opera +operator +ophelia +opiate +optimist +optimus +option +options +opus +oracle +oral +orange +orange1 +oranges +orchard +orchid +oregon +oreo +orgasm +orgasms +orgy +original +orioles +orion +orion1 +orlando +orpheus +orwell +osama +oscar +oscar1 +oscars +osiris +osprey +othello +otis +ottawa +otter +otto +ou812 +ou8122 +ou8123 +out3xf +outback +outkast +outlaw +outoutout +outside +outsider +ov3ajy +over +overkill +overlord +owen +oxford +oxygen +oyster +ozlq6qwm +ozzy +p3wqaw +pa55w0rd +pa55word +pablo +pacers +pacific +pacino +pack +packard +packer +packers +packers1 +pacman +paco +paddle +paddy +padres +page +paige +pain +painless +paint +paintbal +paintball +painter +painting +paisley +pajero +pakistan +palace +paladin +paladin1 +palermo +pallmall +palmer +palmtree +paloma +pamela +panama +panasoni +panasonic +pancake +pancho +panda +panda1 +pandas +pandora +pang +panhead +panic +pantera +pantera1 +panther +panther1 +panthers +pantie +panties +pants +panzer +papa +papabear +paper +papers +papillon +papito +pappy +paradigm +paradise +paradox +paragon +paramedi +paranoid +paris +paris1 +park +parker +parola +parrot +parsons +partner +party +pasadena +pascal +pass +pass1 +pass123 +pass1234 +passat +passion +passmast +passme +passpass +passport +passthie +passw0rd +passwd +passwor +passwor1 +password +password1 +password2 +password9 +passwords +passwort +pasta +pastor +pasword +patch +patches +patches1 +pathetic +pathfind +patience +patrice +patricia +patrick +patrick1 +patriot +patriots +patrol +patti +patton +patty +paul +paula +paulie +paulina +pauline +paulpaul +pavement +pavilion +pavlov +paxton +payday +payton +pdiddy +peabody +peace +peace1 +peach +peaches +peaches1 +peachy +peacock +peanut +peanut1 +peanuts +pearl +pearl1 +pearljam +pearls +pearson +peavey +pebble +pebbles +pecker +peddler +pedro +pedros +peekaboo +peepee +peeper +peepers +peewee +pegasus +peggy +pelican +pencil +penelope +penetrating +penetration +peng +penguin +penguin1 +penguins +penis +penis1 +penny +penny1 +pennywis +pentagon +penthous +pentium +people +pepe +pepito +pepper +pepper1 +peppers +pepsi +pepsi1 +perfect +perfect1 +perkins +perrin +perry +persian +person +personal +pertinant +pervert +pescator +pete +peter +peter1 +peterbil +peternorth +peterpan +peters +peterson +petra +petunia +peugeot +peyton +pfloyd +phaedrus +phantom +phantom1 +pharao +pharmacy +phat +pheonix +phialpha +phil +philip +philippe +philips +phillies +phillip +phillips +philly +phish +phish1 +phoebe +phoenix +phoenix1 +phone +phones +photo +photo1 +photoes +photon +photos +phpbb +phrases +phreak +phyllis +physics +pian +piano +pianoman +pianos +piao +piazza +pic\'s +picard +picasso +piccolo +picher +pick +pickle +pickles +picks +pickup +picnic +pics +pictere +pictuers +picture +pictures +picturs +pierce +piercing +pierre +pigeon +piggy +piglet +pigpen +pikachu +pilgrim +pillow +pilot +pilot1 +pilots +pimp +pimpdadd +pimpdaddy +pimpin +pimping +pinball +pinch +pine +pineappl +pinetree +ping +pingpong +pinhead +pink +pinkfloy +pinkfloyd +pinky +pinky1 +pinnacle +pintail +pinto +pioneer +pipe +pipeline +piper +pippen +pippin +pippo +pirate +pirates +pisces +piss +pissed +pisser +pissing +pissoff +pistol +piston +pistons +pitbull +pitch +pitcher +pitchers +pitt +pitures +pixie +pixies +pizza +pizza1 +pizzaman +pizzas +pktmxr +pkxe62 +place +placebo +places +placid +plane +planes +planet +plants +plasma +plaster +plastic +plastics +platinum +plato +platypus +play +playa +playball +playboy +playboy1 +playboy2 +player +player1 +players +playing +playmate +playoffs +playstat +playstation +playtime +pleasant +please +please1 +pleasure +plokij +ploppy +plum +plumber +plus +pluto +plymouth +pn5jvw +pocket +poetry +poets +point +pointer +points +poipoi +poison +poiu +poiuy +pokemon +poker +poker1 +pokey +poland +polaris +police +polish +politics +pollux +polly +polo +polopolo +polska +pommes +pompey +poncho +pong +pontiac +pony +poobear +poochie +poodle +pooh +poohbear +pookey +pookie +pooky +pool +pool6123 +poon +poontang +poop +pooper +poophead +poopie +poopoo +pooppoop +poopy +pooter +popcorn +pope +popeye +popo +popopo +popper +poppop +poppy +poppy1 +pork +porkchop +porky +porn +porn4life +pornking +porno +porno1 +pornographic +pornos +pornporn +porsche +porsche1 +porsche9 +port +porter +portia +portland +portugal +poseidon +positive +possum +post +postal +postman +postov1000 +potato +pothead +potter +pounded +pounding +powder +powell +power +power1 +powers +pppp +ppppp +pppppp +ppppppp +pppppppp +prague +praise +prayer +prayers +preacher +precious +predator +pregnant +prelude +prelude1 +premier +premium +presario +presiden +president +presley +pressure +presto +preston +pretty +pretzel +prick +pride +priest +prima +prime +primetime21 +primus +prince +prince1 +princess +princeto +princeton +pringles +print +printer +printing +prissy +privacy +private +private1 +probes +prodigy +producer +product +professor +profile +profit +program +progress +project +prometheus +promise +property +prophecy +prophet +prospect +prosper +protect +proton +provider +prowler +proxy +prozac +psalms +psycho +ptbdhw +ptfe3xxp +public +puck +puddin +pudding +puddles +puff +puffer +puffin +puffy +pugsley +pulled +pulsar +pump +pumper +pumpkin +pumpkin1 +pumpkins +punani +punch +punisher +punk +punkass +punker +punkin +punkrock +puppet +puppies +puppy +puppy1 +puppydog +purdue +purple +purple1 +puss +pussey +pussie +pussies +pusssy +pussy +pussy1 +pussy123 +pussy2 +pussy4me +pussy69 +pussycat +pussyeat +pussyman +pussys +pusyy +puta +putter +puzzle +pvjegu +pwxd5x +pxx3eftp +pyf8ah +pyon +pyramid +python +q1w2e3 +q1w2e3r4 +q9umoz +qawsed +qaz123 +qazqaz +qazwsx +qazwsxed +qazwsxedc +qazxsw +qbg26i +qcfmtz +qcmfd454 +qguvyt +qhxbij +qian +qiang +qiao +qing +qiong +qn632o +qqh92r +qqqq +qqqqq +qqqqqq +qqqqqqq +qqqqqqqq +quake +quality +quan +quant4307s +quantum +quartz +quasar +quattro +quebec +queen +queen1 +queenie +queens +quentin +quest +quest1 +question +quick +quincy +quinn +qwaszx +qwe123 +qweasd +qweqwe +qwer +qwer1234 +qwerasdf +qwerqwer +qwert +qwert1 +qwert123 +qwert40 +qwerty +qwerty1 +qwerty12 +qwerty123 +qwerty7 +qwertyu +qwertyui +qwertyuiop +qwertz +qwertzui +qwqwqw +r29hqq +r2d2 +r2d2c3po +rabbit +rabbit1 +rabbits +race +racecar +racer +racer1 +racers +racerx +rachael +rachel +rachel1 +rachelle +racing +racoon +radar +radar1 +radical +radio +radiohea +rafael +rage +ragnarok +raider +raiders +raiders1 +railroad +rain +rainbow +rainbow1 +rainbow6 +rainbows +rainer +raining +rainman +rainyday +raistlin +raleigh +ralph +ralph1 +ralphie +ramada +rambler +rambo +rambo1 +ramirez +ramjet +ramona +ramones +rampage +ramrod +rams +ramses +ramsey +ranch +rancid +randall +randolph +random +randy +randy1 +rang +ranger +ranger1 +rangers +rangers1 +raphael +rapier +rapper +raptor +rapture +rapunzel +raquel +rascal +rasputin +rasta +rasta220 +rasta69 +ratboy +rated +ratman +rats +raul +raven +raven1 +ravens +raymond +rayray +razor +reader +readers +reading +ready +reagan +real +reality +really +reaper +reason +rebecca +rebecca1 +rebel +rebel1 +rebels +rebelz +reboot +recall +reckless +recon +record +records +recovery +red123 +redalert +redbaron +redbird +redbone +redbull +redcar +redd +reddevil +reddog +reddwarf +redeye +redfish +redfox +redhat +redhead +redheads +redhot +redleg +redlight +redline +redman +redneck +redone +redred +redrose +redrum +reds +redshift +redskin +redskins +redsox +redsox1 +redstorm +redwine +redwing +redwings +redwood +reebok +reed +reefer +reeves +referee +reflex +reggae +reggie +regina +reginald +register +reichl +reilly +reindeer +reject +release +relief +reload +remember +remingto +remote +renate +renault +rene +renee +renee1 +renegade +reng +reno +rental +repair +report +reptile +republic +request +requiem +rescue +research +reserve +resident +respect +retard +retire +retired +return +reveal +revenge +review +revoluti +revolution +revolver +rewq +reynolds +reznor +rhiannon +rhino +rhino1 +rhinos +rhodes +rhonda +rhubarb +rhythm +ribbit +ricardo +rice +rich +richard +richard1 +richards +riches +richie +richmond +richter +rick +ricky +ricky1 +rico +riddle +ride +rider +riders +ridge +riffraff +right +rightnow +righton +riley +riley1 +rimmer +ring +ringer +ringo +ripken +ripley +ripped +ripper +ripple +riptide +rising +rita +river +rivera +riverrat +rivers +riversid +rjw7x4 +roach +road +roadkill +roadking +roadrunn +roadrunner +roadster +roadway +robbie +robert +robert1 +roberta +roberto +roberts +robin +robin1 +robinhood +robins +robinson +robocop +robot +robotech +robotics +robots +robyn +rocco +rochard +rochelle +rock +rocker +rocket +rocket1 +rockets +rockey +rockford +rockhard +rockie +rockies +rockin +rocknrol +rockon +rockrock +rocks +rockstar +rockwell +rocky +rocky1 +rocky2 +rodeo +rodman +rodney +roger +roger1 +rogers +rogue +rogue1 +roland +rolex +roll +roller +rollin +rolling +rollins +rolltide +roman +romance +romano +romans +romeo +romeo1 +romero +rommel +romulus +ronald +ronald1 +ronaldo +rong +ronnie +roofer +rookie +room +rooney +rooster +root +rootbeer +rootedit +rosa +rosario +roscoe +rose +rosebud +rosemary +roses +rosie +ross +roswell +rotary +rotten +rough +round +route66 +rover +rovers +rowing +roxanne +roxy +royal +royals +royalty +rrpass1 +rrrr +rrrrr +rrrrrr +rrrrrrr +rrrrrrrr +rsalinas +rt6ytere +ruan +rubber +rubble +ruby +rudeboy +rudolf +rudolph +rudy +rufus +rufus1 +rugby +rugby1 +ruger +rugger +rugrat +rulz +rumble +runaway +runner +running +rupert +rush +rush2112 +rushmore +russ +russel +russell +russell1 +russia +russian +rusty +rusty1 +rusty2 +rustydog +ruth +ruthie +rxmtkp +ryan +saab +sabbath +sabine +sable +sabre +sabres +sabrina +sabrina1 +saddle +sadie +sadie1 +safari +safe +safety +safeway +saffron +sage +sahara +saigon +sail +sailboat +sailing +sailor +saint +saints +sairam +saiyan +sakura +salami +salasana +saleen +salem +sales +salesman +sally +sally1 +salmon +salomon +salope +salsa +salsero +salvador +sam123 +samadams +samantha +sambo +samdog +same +samiam +samm +sammie +sammy +sammy1 +sammys +samoht +sampson +samsam +samson +samsung +samsung1 +samuel +samuel1 +samurai +sanchez +sancho +sand +sandals +sandberg +sander +sanders +sandie +sandiego +sandman +sandra +sandra1 +sandrine +sandro +sandwich +sandy +sandy1 +sanford +sanfran +sang +sanity +sanity72 +sanjose +santa +santafe +santana +santiago +santos +sapper +sapphire +sara +sarah +sarah1 +saratoga +sarge +sasasa +sascha +sasha +sasha1 +saskia +sassy +sassy1 +satan +satan666 +satchmo +satin +saturday +saturn +sauce +sauron +sausage +sausages +savage +savanna +savannah +save13tx +savior +sawyer +saxman +saxophon +sayang +scamper +scandinavian +scania +scanner +scarab +scarecrow +scarface +scarlet +scarlett +schalke +schatz +scheisse +scheme +schmidt +school +science +scirocco +scissors +scooby +scooby1 +scoobydo +scoobydoo +scooter +scooter1 +score +scorpio +scorpio1 +scorpion +scotch +scotland +scott +scott1 +scottie +scotts +scotty +scout +scout1 +scouts +scrabble +scrapper +scrappy +scratch +scream +screamer +screen +screw +screwy +screwyou +script +scroll +scrotum +scruffy +scuba +scuba1 +scully +scumbag +scxakv +seabee +seadog +seadoo +seagull +seahawk +seahawks +seal +sealteam +seaman +seamus +sean +searay +search +seaside +season +seattle +seaweed +seawolf +sebastia +sebastian +sebring +second +secret +secret1 +secrets +secure +security +sedona +seductive +seeker +seeking +seinfeld +select +selena +selina +seminole +semper +semperfi +senate +senator +senators +seneca +seng +senior +senna +sensei +sensor +sentinel +sentnece +sentra +sentry +septembe +september +serena +serenity +sergeant +sergey +sergio +series +serious +serpent +server +service +services +sesame +seth +seven +seven7 +sevens +seville +seviyi +sex +sex1 +sex123 +sex4me +sex69 +sexe +sexgod +sexman +sexo +sexpot +sexsex +sexsexsex +sextoy +sexual +sexx +sexxx +sexxxx +sexxxy +sexxy +sexy +sexy1 +sexy123 +sexy69 +sexybabe +sexyboy +sexygirl +sexylady +sexyman +sexyone +sexysexy +seymour +sf49ers +shadow +shadow1 +shadow12 +shadows +shaft +shag +shaggy +shai +shaker +shakes +shakira +shakur +shalom +shaman +shampoo +shamrock +shamus +shan +shane +shane1 +shang +shanghai +shania +shanna +shannon +shannon1 +shanti +shao +shaolin +shark +shark1 +sharks +sharky +sharon +sharp +sharpe +shasta +shaun +shauna +shaved +shawn +shawna +shawnee +shazam +shearer +sheba +sheba1 +sheeba +sheena +sheep +sheepdog +shei +sheila +shelby +shelby1 +sheldon +shell +shelley +shells +shelly +shelter +shemale +shen +sheng +shepherd +sheridan +sheriff +sherlock +sherman +sherri +sherry +sherwood +sheryl +shibby +shield +shiloh +shimmer +shine +shiner +shinobi +ship +shirley +shit +shitface +shithead +shitshit +shitty +shiva +shock +shocker +shodan +shoe +shoes +shogun +shojou +shonuf +shoot +shooter +shop +shopper +shopping +short +shorty +shot +shotgun +shou +shovel +show +shower +showing +showme +showtime +shrimp +shrink +shroom +shua +shuai +shuan +shuang +shui +shun +shuo +shuttle +shutup +shyshy +sick +sickboy +sickness +side +sidekick +sidney +siemens +sienna +sierra +sierra1 +sigma +sigmachi +sigmar +signal +signature +sigrid +silence +silent +silicon +silk +silly +silver +silver1 +silverad +silvia +simba +simba1 +simhrq +simmons +simon +simon1 +simona +simone +simons +simple +simple1 +simpson +simpsons +sims +sinatra +sinbad +sinclair +sinful +singapor +singer +single +sinister +sinned +sinner +siobhan +sirius +sissy +sister +sisters +site +sites +sithlord +sixers +sixpack +sixsix +sixteen +sixty +sixty9 +sixtynin +sizzle +skate +skater +skeeter +skeeter1 +skelter +skibum +skidoo +skiing +skilled +skillet +skin +skinhead +skinner +skinny +skins +skip +skipper +skipper1 +skippy +skirt +skittles +skolko +skooter +skull +skunk +skydive +skydiver +skyhawk +skylar +skylark +skyler +skyline +skywalke +skywalker +slacker +slam +slamdunk +slammed +slammer +slap +slapnuts +slapper +slappy +slapshot +slash +slater +slave +slave1 +slayer +slayer1 +sledge +sleep +sleeper +sleeping +sleepy +slick +slick1 +slider +slim +slimed123 +slimjim +slimshad +slinky +slipknot +slipper +slippery +sliver +sloppy +slow +slowhand +slugger +sluggo +slut +sluts +sluttey +slutty +smack +smackdow +small +smalls +smart +smart1 +smartass +smashing +smeghead +smegma +smeller +smelly +smile +smile1 +smiles +smiley +smirnoff +smith +smith1 +smithers +smiths +smithy +smitty +smk7366 +smoke +smoke1 +smoker +smokes +smokey +smokey1 +smokie +smokin +smoking +smooth +smoothie +smother +smudge +smurf +smut +smutty +snacks +snake +snake1 +snakes +snapon +snapper +snapple +snappy +snapshot +snatch +sneakers +sneaky +snicker +snickers +sniffer +sniffing +sniper +sniper1 +snooker +snoop +snoopdog +snoopy +snoopy1 +snow +snowball +snowbird +snowboar +snowboard +snowflak +snowflake +snowman +snuffy +snuggles +snyder +soap +sober +soccer +soccer1 +soccer10 +soccer11 +soccer12 +socks +socrates +soft +softail +softball +softtail +software +solace +solar +solaris +soldier +soleil +solitude +solo +solomon +solution +some +somebody +someday +someone +somerset +somethin +something +sometime +sommer +sonata +song +sonia +sonic +sonics +sonja +sonne +sonny +sonoma +sonora +sony +sonyfuck +sonysony +sooner +sooners +sooners1 +sophia +sophie +sophie1 +soprano +sopranos +sorrow +soul +soulmate +sound +sounds +soup +south +southern +southpar +southpark +southpaw +sowhat +space +spaceman +spades +spain +spam +spanish +spank +spanker +spanking +spankme +spanky +spanky1 +spanner +sparhawk +spark +sparkle +sparkles +sparks +sparky +sparky1 +sparrow +sparta +spartan +spartan1 +spartans +sparty +spawn +speaker +speakers +spears +special +special1 +specialk +spectre +spectrum +speed +speed1 +speedo +speedway +speedy +spence +spencer +spencer1 +sperm +sperma +sphere +sphinx +spice +spice1 +spider +spider1 +spiderma +spiderman +spidey +spiffy +spike +spike1 +spiker +spikes +spikey +spinner +spiral +spirit +spitfire +spjfet +splash +spleen +spliff +splinter +splurge +spock +spock1 +spoiled +sponge +spongebo +spongebob +spooge +spook +spooky +spoon +spooner +spoons +sport +sporting +sports +sporty +spot +spotty +spread +spring +springer +springs +sprint +sprinter +sprite +sprocket +sprout +spud +spunk +spunky +spurs +spurs1 +sputnik +spyder +squall +square +squash +squeak +squeeze +squerting +squid +squirrel +squirt +squirts +srinivas +ssptx452 +ssss +sssss +ssssss +sssssss +ssssssss +stacey +stacey1 +stacie +stacy +staff +stafford +stalin +stalker +stallion +stan +standard +standby +stanford +stang +stanley +stanley1 +stanton +staples +star +star1 +star12 +star69 +starbuck +starcraf +starcraft +stardust +starfire +starfish +stargate +starligh +starlight +starlite +starman +starr +stars +starship +starstar +start +start1 +starter +startrek +starwars +state +states +static +station +status +stayout +stealth +steel +steele +steeler +steelers +stefan +stefanie +stefano +steffen +steffi +stella +stellar +steph +stephan +stephane +stephani +stephanie +stephen +stephen1 +stephens +stereo +sterling +stern +steve +steve1 +steven +steven1 +stevens +stevie +stewart +stewart1 +stick +stickman +sticks +sticky +stiffy +stiletto +stimpy +sting +stinger +stingray +stinker +stinks +stinky +stinky1 +stirling +stjabn +stock +stocking +stocks +stockton +stokes +stolen +stone +stone1 +stone55 +stonecol +stonecold +stoned +stoner +stones +stonewal +stoney +stooge +stooges +stop +stopit +stoppedby +storage +store +stories +storm +storm1 +storms +stormy +story +storys +straight +strange +stranger +strap +strat +strato +stratus +strawber +strawberry +streak +stream +streaming +street +streets +strength +stress +stretch +strider +strife +strike +striker +string +strip +striper +stripes +stripper +stroke +stroker +strong +stryker +stuart +stubby +stud +student +studio +studly +studman +stuff +stuffer +stumpy +stunner +stupid +stupid1 +stuttgart +style +styles +stylus +suan +subaru +sublime +submit +suburban +subway +subzero +success +success1 +suck +suckcock +suckdick +sucked +sucker +suckers +sucking +suckit +suckme +sucks +suede +sugar +sugar1 +sugars +suicide +sukebe +sullivan +sultan +summer +summer1 +summer69 +summer99 +summers +summit +sundance +sunday +sundevil +sundown +sunfire +sunflowe +sunflower +sunlight +sunny +sunny1 +sunnyday +sunrise +sunset +sunshine +super +super1 +superb +superfly +superior +superman +supernov +supersta +superstar +support +supra +supreme +surf +surfer +surfer1 +surfing +surgery +surprise +survey +surveyor +survival +survivor +susan +susan1 +susana +susanna +susanne +sushi +susie +susieq +sutton +suzanne +suzuki +svetlana +swallow +swampy +sweden +swedish +sweeney +sweet +sweet1 +sweetie +sweetnes +sweetness +sweetpea +sweets +sweety +swift +swifty +swim +swimmer +swimming +swing +swinger +swingers +swinging +swiss +switch +switzer +swoosh +sword +swordfis +swordfish +swords +sxhq65 +sydney +sylveste +sylvia +sylvie +symbol +symmetry +symow8 +synergy +syracuse +sysadmin +system +system1 +systems +syzygy +t26gn4 +tabasco +tabatha +tabitha +table +taco +tacobell +tacoma +tadpole +taffy +tahiti +tahoe +taichi +tail +tailgate +tainted +takehana +talbot +tales +talisman +talk +talks +talon +tammie +tammy +tammy1 +tampabay +tanaka +tang +tangerin +tango +tango1 +tank +tanker +tanner +tantra +tanya +tanya1 +tara +tardis +target +tarheel +tarheels +tarpon +tartar +tarzan +tasha +tasha1 +tasty +tatiana +tattoo +taurus +taxman +taylor +taylor1 +tazman +tazmania +taztaz +tazz +tbird +tbone +teacher +team +teaser +tech +technics +techniques +techno +teddy +teddy1 +teddybea +teddybear +teen +teenage +teenie +teens +teensex +tekken +telecom +telefon +telekom +telephon +telephone +teller +temp +temp123 +tempest +templar +temple +temporal +temppass +temptress +tenchi +tender +teng +tennesse +tennis +tennis1 +tequila +terefon +teresa +terminal +terminat +termite +terra +terran +terrapin +terrell +terri +terrier +terror +terry +terry1 +tessie +test +test1 +test12 +test123 +test1234 +test2 +tester +testerer +testibil +testing +testing1 +testme +testpass +testtest +tetsuo +texaco +texas +texas1 +thailand +thanatos +thanks +thankyou +theater +theatre +thebear +thebest +theboss +thecat +thecrow +thecure +thedog +thedon +thedoors +thedude +theend +theforce +thegame +thegreat +their +thekid +theking +thelma +theman +thematri +theo +theodore +theone +therapy +there +theresa +therock +therock1 +these +theshit +thesims +thethe +thething +thetruth +thewho +thick +thierry +thighs +thing +things +think +thinking +thirteen +thirty +this +thisisit +thistle +thomas +thomas1 +thompson +thong +thongs +thor +thorne +thought +thrasher +three +threesom +thriller +throat +thrust +thuglife +thumb +thumbnils +thumbs +thumper +thumper1 +thunder +thunder1 +thunderb +thunderbird +thursday +thx1138 +tian +tiao +tiberius +tiburon +tical +ticket +tickle +tickler +tickling +ticklish +tictac +tiff +tiffany +tiffany1 +tiger +tiger1 +tiger123 +tiger2 +tiger7 +tigercat +tigers +tigers1 +tigger +tigger1 +tigger2 +tight +tights +timber +time +timeout +times +timmy +timothy +timtim +tina +ting +tinker +tinkerbe +tinman +tintin +tiny +tipper +tires +titan +titanic +titanium +titans +titfuck +titi +titleist +titman +tito +tits +titten +titts +titty +tmjxn151 +toad +toast +toaster +tobias +toby +tobydog +today +today1 +todd +toejam +toes +toffee +together +toggle +toilet +tokyo +toledo +tolkien +tomahawk +tomas +tomato +tomcat +tommie +tommy +tommy1 +tommyboy +tomorrow +tomtom +tong +tongue +toni +tonight +tonton +tony +toocool +toohot +tool +toolbox +toolman +tools +toomuch +toon +toonarmy +toons +tooth +tootie +tootsie +topaz +topcat +topdog +topgun +tophat +topher +topper +topspin +toriamos +torino +tornado +toronto +torpedo +torres +torture +toshiba +tosser +total +toto +totoro +tototo +tottenha +tottenham +touch +touching +tower +towers +town +toxic +toyota +trace +tracer +tracey +tracie +track +tracker +tracks +tractor +tracy +tracy1 +tracy71 +trader +traffic +trailer +trailers +train +trainer +training +trains +tramp +trample +trance +tranny +trans +transam +transexual +transfer +transit +transport +trapper +trash +trauma +travel +traveler +travis +travis1 +treasure +treble +trebor +tree +treefrog +trees +treetop +trek +trent +trenton +trevor +trewq +trey +tri5a3 +trial +triangle +tribal +tribble +tribe +tricia +trick +tricky +trident +trigger +trinidad +trinitro +trinity +trinity1 +trip +triple +tripleh +triplex +tripod +tripper +trish +trisha +tristan +triton +triumph +trivia +trixie +trojan +trojans +troll +trombone +trooper +trooper1 +trophy +tropical +trotter +trouble +trouble1 +troubles +trousers +trout +trout1 +troy +trs8f7 +truck +truck1 +trucker +trucking +trucks +true +trueblue +truelove +truman +trumpet +trumpet1 +trunks +trust +trustme +trustno1 +truth +tsunami +tttt +ttttt +tttttt +ttttttt +tttttttt +tuan +tucker +tucson +tuesday +tugboat +tulane +tulip +tulips +tuna +tunafish +tundra +tunnel +tupac +turbo +turbo1 +turbos +turk182 +turkey +turkey50 +turner +turnip +turtle +turtle1 +turtles +tuscl +tusymo +tuxedo +twat +tweety +twelve +twenty +twiggy +twilight +twin +twinkie +twinkle +twins +twist +twisted +twister +tycoon +tyler +tyler1 +typhoon +tyrant +tyrone +tyson +tyson1 +tyvugq +tzpvaw +ue8fpw +ugejvp +ulrich +ulrike +ultima +ultimate +ultra +ulysses +umbrella +umpire +unbelievable +uncencored +uncle +undead +under +underdog +undertak +undertaker +undertow +underwear +unhappy +unicorn +union +unique +united +unity +universa +universe +university +unix +unknown +unreal +upnfmc +uptown +upyours +uranus +ursitesux +ursula +usa123 +usarmy +user +username +usmarine +usmc +usnavy +ussy +util +utility +utopia +uuuu +uuuuu +uuuuuu +uuuuuuu +uuuuuuuu +uwrl7c +uyxnyd +vacation +vader +vader1 +vagabond +vagina +valdepen +valdez +valencia +valentin +valeria +valerie +valhalla +valiant +valkyrie +valley +valleywa +vamp +vampire +vampire1 +vampires +vancouve +vanessa +vanessa1 +vanguard +vanhalen +vanilla +vantage +vaughn +vauxhall +vbnm +vcradq +vdlxuc +vector +vectra +vedder +vegas +vegeta +vegitta +vegitto +velocity +velvet +venice +venom +ventura +venture +venus +verbatim +verena +veritas +verizon +vermont +vernon +verona +veronica +veronika +versace +vertigo +verygood +vette +vette1 +vfdhif +vgirl +vh5150 +viagra +vibrate +vicki +vickie +vicky +victor +victor1 +victoria +victory +video +video1 +videoes +vides +vienna +vietnam +view +viewer +viewsoni +viking +vikings +vikings1 +villa +village +vince +vincent +vincent1 +vinnie +vintage +violator +violet +violin +viper +viper1 +vipergts +vipers +virago +virgil +virgin +virginia +virginie +virtual +virus +visa +vision +visited +visitor +visual +vivian +vivid +vivitron +vixen +vkaxcs +vladimir +vodka +volcano +volcom +volkswag +volley +volleyba +volleyball +vols +volume +volvo +voodoo +voodoo1 +vorlon +vortex +voyager +voyager1 +voyeur +vsegda +vulcan +vulva +vvvv +vvvvv +vvvvvv +vvvvvvv +vvvvvvvv +w00t88 +w4g8at +wacker +wade +waffle +wage +wagner +wahoo +waiting +waldo +waldo1 +walker +walking +wallace +wallet +walleye +wally +wally1 +walmart +walnut +walrus +walter +walters +walton +wanda +wanderer +wang +wanker +wanking +wannabe +wanted +wapapapa +waqw3p +warcraft +ward +wareagle +warez +wargames +warhamme +warlock +warlord +warner +warning +warren +warrior +warrior1 +warriors +wars +warthog +wasabi +washburn +washingt +washington +wasser +wassup +wasted +watch +watcher +watching +water +water1 +waterboy +waterfal +waterloo +waterman +waters +waterski +watford +watson +wave +wavpzt +wayer +wayne +wayne1 +wealth +weapon +wearing +weasel +weather +weaver +webber +webcam +webmaste +webmaster +website +webster +wedding +wednesda +wednesday +weed +weed420 +weekend +weenie +weewee +weezer +weiner +weird +welcome +welcome1 +welder +weller +wellingt +wendell +wendy +wendy1 +weng +werder +werdna +werewolf +werner +wert +wesley +west +western +westham +westlife +weston +westside +westwood +wetpussy +wetter +wg8e3wjf +whale +whales +what +whatever +whatsup +whatthe +whatup +whatwhat +whdbtp +wheel +wheeler +wheels +whiplash +whiskers +whiskey +whisky +whisper +whistler +white +white1 +whiteboy +whiteout +whites +whitesox +whitey +whitney +whkzyc +whocares +whore +whynot +wibble +wiccan +wicked +widget +wife +wifes +wifey +wiggle +wilbur +wild +wildbill +wildcard +wildcat +wildcats +wilder +wildfire +wildman +wildone +wildstar +wildwood +wilhelm +will +willard +willem +willi +william +william1 +williams +willie +willie1 +willis +willow +willy +willy1 +wilma +wilson +wilson1 +wind +windmill +window +windows +windows1 +windsor +windsurf +wine +winfield +wing +wingchun +winger +wingman +wingnut +wings +winner +winner1 +winners +winnie +winona +winston +winston1 +winter +winter1 +winter99 +wireless +wisdom +wiseguy +wishbone +witch +wives +wizard +wizard1 +wizards +wizzard +wobble +wolf +wolf359 +wolfen +wolfgang +wolfie +wolfman +wolfpac +wolfpack +wolverin +wolverine +wolves +wolvie +womam +woman +womans +wombat +womble +women +wonder +wonderboy +wonderfu +wood +wooden +woodie +woodland +woodman +woodrow +woods +woodstoc +woodwork +woody +woody1 +woof +woofer +woofwoof +woohoo +wookie +woowoo +word +wordpass +wordup +work +worker +working +workout +world +worlds +worm +worship +worthy +wowwow +wp2003wp +wraith +wrangler +wrench +wrestle +wrestler +wrestlin +wrestling +wright +wrinkle1 +wrinkle5 +writer +written +wtcacq +wu4etd +wutang +wvj5np +wwww +wwwww +wwwwww +wwwwwww +wwwwwwww +wxcvbn +wyatt +wyoming +wyvern +x24ik3 +x35v8l +xanadu +xander +xavier +xerxes +xfiles +xian +xiang +xiao +xing +xiong +xirt2k +xjznq5 +xman +xmas +xmen +x-men +xngwoj +xqgann +xrated +xray +xtreme +xuan +xxx123 +xxxx +xxxxx +xxxxx1 +xxxxxx +xxxxxx1 +xxxxxxx +xxxxxxx1 +xxxxxxxx +xytfu7 +xyz123 +xyzzy +yackwin +yahoo +yahoo1 +yahooo +yamaha +yamaha1 +yamahar1 +yamato +yang +yankee +yankee1 +yankees +yankees1 +yankees2 +yanks +yasmin +yaya +yeah +yeahbaby +yeahyeah +year2005 +yellow +yellow1 +yess +yessir +yesterda +yesyes +yhwnqc +ying +yinyang +yitbos +ynot +yoda +yogi +yogibear +yolanda +yomama +yong +yosemite +yoshi +youknow +young +young1 +your +yourmom +yousuck +yoyo +yoyoma +yoyoyo +yqlgr667 +ytrewq +yuan +yummy +yumyum +yvette +yvonne +yvtte545 +ywvxpz +yy5rbfsc +yyyy +yyyyy +yyyyy1 +yyyyyy +yyyyyy1 +yyyyyyy +yyyyyyyy +yzerman +zach +zachary +zachary1 +zack +zander +zang +zanzibar +zapata +zaphod +zappa +zapper +zaq123 +zaq12wsx +zaq1xsw2 +zaqwsx +zaqxsw +zardoz +zebra +zebra1 +zebras +zeke +zelda +zeng +zenith +zephyr +zeppelin +zero +zerocool +zeus +zhai +zhan +zhang +zhao +zhei +zhen +zheng +zhong +zhou +zhua +zhuai +zhuan +zhuang +zhui +zhun +zhuo +zidane +ziggy +ziggy1 +zigzag +zildjian +zimmer +zipper +zippo +zippy +zippy1 +zlzfrh +zodiac +zombie +zone +zong +zoom +zoomer +zoomzoom +zooropa +zorro +zorro1 +zouzou +zsmj2v +ztmfcq +zuan +zulu +zurich +zw6syj +zxc123 +zxcv +zxcvb +zxcvbn +zxcvbnm +zxcvbnm1 +zxczxc +zxzxzx +zzzxxx +zzzz +zzzzz +zzzzz1 +zzzzzz +zzzzzz1 +zzzzzzz +zzzzzzzz diff --git a/src/keepass2android-app/ChangeLog.cs b/src/keepass2android-app/ChangeLog.cs index 6c8c5537..1c1a3723 100644 --- a/src/keepass2android-app/ChangeLog.cs +++ b/src/keepass2android-app/ChangeLog.cs @@ -31,6 +31,8 @@ namespace keepass2android MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ctx); builder.SetTitle(ctx.GetString(Resource.String.ChangeLog_title)); List changeLog = new List{ + BuildChangelogString(ctx, new List{Resource.Array.ChangeLog_1_13}, "1.13"), + BuildChangelogString(ctx, new List{Resource.Array.ChangeLog_1_12 #if !NoNet ,Resource.Array.ChangeLog_1_12_net diff --git a/src/keepass2android-app/CreateDatabaseActivity.cs b/src/keepass2android-app/CreateDatabaseActivity.cs index 60da7bea..e417ef34 100644 --- a/src/keepass2android-app/CreateDatabaseActivity.cs +++ b/src/keepass2android-app/CreateDatabaseActivity.cs @@ -183,7 +183,7 @@ namespace keepass2android // Verify that a password or keyfile is set if (password.Length == 0 && !keyfileCheckbox.Checked) { - Toast.MakeText(this, Resource.String.error_nopass, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.error_nopass, MessageSeverity.Error); return; } @@ -207,7 +207,7 @@ namespace keepass2android } catch (Exception) { - Toast.MakeText(this, Resource.String.error_adding_keyfile, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.error_adding_keyfile, MessageSeverity.Error); return; } } @@ -235,7 +235,7 @@ namespace keepass2android if (! pass.Equals(confpass)) { // Passwords do not match - Toast.MakeText(this, Resource.String.error_pass_match, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.error_pass_match, MessageSeverity.Error); return false; } return true; diff --git a/src/keepass2android-app/CreateNewFilename.cs b/src/keepass2android-app/CreateNewFilename.cs index f918f458..e7ffa9a9 100644 --- a/src/keepass2android-app/CreateNewFilename.cs +++ b/src/keepass2android-app/CreateNewFilename.cs @@ -28,7 +28,7 @@ namespace keepass2android } catch (Exception e) { - Finish(false, e.Message); + Finish(false, Util.GetErrorMessage(e)); } } diff --git a/src/keepass2android-app/DisableAutofillForQueryActivity.cs b/src/keepass2android-app/DisableAutofillForQueryActivity.cs index df6e3101..1d2e30a1 100644 --- a/src/keepass2android-app/DisableAutofillForQueryActivity.cs +++ b/src/keepass2android-app/DisableAutofillForQueryActivity.cs @@ -19,7 +19,7 @@ using keepass2android.services.AutofillBase; namespace keepass2android { - [Activity(Label = "DisableAutofillForQueryActivity")] + [Activity(Label = "DisableAutofillForQueryActivity", Theme = "@style/Kp2aTheme_ActionBar")] public class DisableAutofillForQueryActivity : Activity { public IAutofillIntentBuilder IntentBuilder = new Kp2aAutofillIntentBuilder(); @@ -41,7 +41,7 @@ namespace keepass2android string requestedUrl = Intent.GetStringExtra(ChooseForAutofillActivityBase.ExtraQueryString); if (requestedUrl == null) { - Toast.MakeText(this, "Cannot execute query for null.", ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, "Cannot execute query for null.", MessageSeverity.Error); RestartApp(); return; } @@ -63,8 +63,6 @@ namespace keepass2android prefs.Edit().PutStringSet("AutoFillDisabledQueries", disabledValues).Commit(); - bool isManual = Intent.GetBooleanExtra(ChooseForAutofillActivityBase.ExtraIsManualRequest, false); - Intent reply = new Intent(); FillResponse.Builder builder = new FillResponse.Builder(); AssistStructure structure = (AssistStructure)Intent.GetParcelableExtra(AutofillManager.ExtraAssistStructure); @@ -77,7 +75,7 @@ namespace keepass2android StructureParser parser = new StructureParser(this, structure); try { - parser.ParseForFill(isManual); + parser.ParseForFill(); } catch (Java.Lang.SecurityException e) diff --git a/src/keepass2android-app/EntryActivity.cs b/src/keepass2android-app/EntryActivity.cs index 832e850a..2e9797a0 100644 --- a/src/keepass2android-app/EntryActivity.cs +++ b/src/keepass2android-app/EntryActivity.cs @@ -78,7 +78,7 @@ namespace keepass2android var task = new EntryActivity.WriteBinaryTask(_activity, App.Kp2a, new ActionOnFinish(_activity, (success, message, activity) => { if (!success) - Toast.MakeText(activity, message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(activity, message, MessageSeverity.Error); } ), ((EntryActivity)_activity).Entry.Binaries.Get(_binaryToSave), ioc); ProgressTask pt = new ProgressTask(App.Kp2a, _activity, task); @@ -107,8 +107,8 @@ namespace keepass2android public const int requestCodeBinaryFilename = 42376; public const int requestCodeSelFileStorageForWriteAttachment = 42377; - + protected override View? SnackbarAnchorView => FindViewById(Resource.Id.main_content); public static void Launch(Activity act, PwEntry pw, int pos, AppTask appTask, ActivityFlags? flags = null, int historyIndex=-1) { @@ -767,9 +767,9 @@ namespace keepass2android if (parent == null || (parent.Exists() && !parent.IsDirectory)) { - Toast.MakeText(this, + App.Kp2a.ShowMessage(this, Resource.String.error_invalid_path, - ToastLength.Long).Show(); + MessageSeverity.Error); return null; } @@ -778,9 +778,9 @@ namespace keepass2android // Create parent directory if (!parent.Mkdirs()) { - Toast.MakeText(this, + App.Kp2a.ShowMessage(this, Resource.String.error_could_not_create_parent, - ToastLength.Long).Show(); + MessageSeverity.Error); return null; } @@ -794,18 +794,18 @@ namespace keepass2android } catch (Exception exWrite) { - Toast.MakeText(this, + App.Kp2a.ShowMessage(this, GetString(Resource.String.SaveAttachment_Failed, new Java.Lang.Object[] {filename}) - + exWrite.Message, ToastLength.Long).Show(); + + Util.GetErrorMessage(exWrite), MessageSeverity.Error); return null; } finally { MemUtil.ZeroByteArray(pbData); } - Toast.MakeText(this, + App.Kp2a.ShowMessage(this, GetString(Resource.String.SaveAttachment_doneMessage, new Java.Lang.Object[] {filename}), - ToastLength.Short).Show(); + MessageSeverity.Info); return Uri.Parse("content://" + AttachmentContentProvider.Authority + "/" + filename); } @@ -838,7 +838,7 @@ namespace keepass2android catch (ActivityNotFoundException) { //ignore - Toast.MakeText(this, "Couldn't open file", ToastLength.Short).Show(); + App.Kp2a.ShowMessage(this, "Couldn't open file", MessageSeverity.Error); } } @@ -1305,7 +1305,7 @@ namespace keepass2android } catch (Exception ex) { - Finish(false, ex.Message); + Finish(false, Util.GetErrorMessage(ex)); } @@ -1546,10 +1546,10 @@ namespace keepass2android string url = _stringViews[urlFieldKey].Text; if (url == null) return false; - // Default http:// if no protocol specified + // Default https:// if no protocol specified if ((!url.Contains(":") || (url.StartsWith("www.")))) { - url = "http://" + url; + url = "https://" + url; } try @@ -1558,7 +1558,7 @@ namespace keepass2android } catch (ActivityNotFoundException) { - Toast.MakeText(this, Resource.String.no_url_handler, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.no_url_handler, MessageSeverity.Error); } return true; } diff --git a/src/keepass2android-app/EntryEditActivity.cs b/src/keepass2android-app/EntryEditActivity.cs index d6337052..ab76fce3 100644 --- a/src/keepass2android-app/EntryEditActivity.cs +++ b/src/keepass2android-app/EntryEditActivity.cs @@ -37,8 +37,10 @@ using System.Net; using System.Text; using Android.Content.Res; using Android.Database; +#if !NO_QR_SCANNER using Android.Gms.Common; using Android.Gms.Tasks; +#endif using Android.Graphics; using Android.Graphics.Drawables; using Android.Runtime; @@ -55,19 +57,20 @@ using Object = Java.Lang.Object; using Uri = Android.Net.Uri; using Resource = keepass2android.Resource; using Google.Android.Material.TextField; +#if !NO_QR_SCANNER using Xamarin.Google.MLKit.Vision.Barcode.Common; using Xamarin.Google.MLKit.Vision.CodeScanner; +#endif using Console = System.Console; -using Task = Android.Gms.Tasks.Task; namespace keepass2android { [Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden, Theme = "@style/Kp2aTheme_ActionBar")] public class EntryEditActivity : LockCloseActivity { - - - public const String KeyEntry = "entry"; + protected override View? SnackbarAnchorView => FindViewById(Resource.Id.main_content); + + public const String KeyEntry = "entry"; public const String KeyParent = "parent"; public const String KeyTemplateUuid = "KeyTemplateUuid"; @@ -331,13 +334,18 @@ namespace keepass2android } - protected override void OnStart() + private bool hasRequestedKeyboardActivation = false; + protected override void OnStart() { base.OnStart(); if (PreferenceManager.GetDefaultSharedPreferences(this) - .GetBoolean(GetString(Resource.String.UseKp2aKeyboardInKp2a_key), false)) + .GetBoolean(GetString(Resource.String.UseKp2aKeyboardInKp2a_key), false) + && (!hasRequestedKeyboardActivation)) { - CopyToClipboardService.ActivateKeyboard(this); + //only try this once. if the user clicks cancel, we don't want to ask again + // (it may happen that the activity is restarted because of the NewTask flag immediately after the dialog) + hasRequestedKeyboardActivation = true; + CopyToClipboardService.ActivateKeyboard(this); } } @@ -715,7 +723,7 @@ namespace keepass2android } catch(Exception exAttach) { - Toast.MakeText(this, GetString(Resource.String.AttachFailed)+" "+exAttach.Message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, GetString(Resource.String.AttachFailed)+" "+ Util.GetErrorMessage(exAttach), MessageSeverity.Error); } State.EntryModified = true; PopulateBinaries(); @@ -833,7 +841,7 @@ namespace keepass2android string s = Util.GetFilenameFromInternalFileChooser(data, this); if (s == null) { - Toast.MakeText(this, "No URI retrieved.", ToastLength.Short).Show(); + App.Kp2a.ShowMessage(this, "No URI retrieved.", MessageSeverity.Error); return; } uri = Uri.Parse(s); @@ -1139,7 +1147,7 @@ namespace keepass2android } else { - Toast.MakeText(this, "did not find target field", ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, "did not find target field", MessageSeverity.Error); } @@ -1153,12 +1161,15 @@ namespace keepass2android { dlgView.FindViewById(Resource.Id.totp_custom_settings_group).Visibility = args.IsChecked ? ViewStates.Visible : ViewStates.Gone; }; - - dlgView.FindViewById