KeePassLib finally portable (but version 2.19)

Windows Store project stub
This commit is contained in:
2017-09-11 15:13:04 +02:00
parent 9640efaa5f
commit d3a3d73491
154 changed files with 102785 additions and 787 deletions

View File

@@ -0,0 +1,65 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using ModernKeePassLib.Security;
using ModernKeePassLib.Utility;
namespace ModernKeePassLib.Cryptography.PasswordGenerator
{
internal static class CharSetBasedGenerator
{
internal static PwgError Generate(out ProtectedString psOut,
PwProfile pwProfile, CryptoRandomStream crsRandomSource)
{
psOut = ProtectedString.Empty;
if(pwProfile.Length == 0) return PwgError.Success;
PwCharSet pcs = new PwCharSet(pwProfile.CharSet.ToString());
char[] vGenerated = new char[pwProfile.Length];
PwGenerator.PrepareCharSet(pcs, pwProfile);
for(int nIndex = 0; nIndex < (int)pwProfile.Length; ++nIndex)
{
char ch = PwGenerator.GenerateCharacter(pwProfile, pcs,
crsRandomSource);
if(ch == char.MinValue)
{
Array.Clear(vGenerated, 0, vGenerated.Length);
return PwgError.TooFewCharacters;
}
vGenerated[nIndex] = ch;
}
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vGenerated);
psOut = new ProtectedString(true, pbUtf8);
MemUtil.ZeroByteArray(pbUtf8);
Array.Clear(vGenerated, 0, vGenerated.Length);
return PwgError.Success;
}
}
}

View File

@@ -0,0 +1,66 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Text;
using ModernKeePassLib;
using ModernKeePassLib.Security;
namespace ModernKeePassLib.Cryptography.PasswordGenerator
{
public abstract class CustomPwGenerator
{
/// <summary>
/// Each custom password generation algorithm must have
/// its own unique UUID.
/// </summary>
public abstract PwUuid Uuid { get; }
/// <summary>
/// Displayable name of the password generation algorithm.
/// </summary>
public abstract string Name { get; }
public virtual bool SupportsOptions
{
get { return false; }
}
/// <summary>
/// Password generation function.
/// </summary>
/// <param name="prf">Password generation options chosen
/// by the user. This may be <c>null</c>, if the default
/// options should be used.</param>
/// <param name="crsRandomSource">Source that the algorithm
/// can use to generate random numbers.</param>
/// <returns>Generated password or <c>null</c> in case
/// of failure. If returning <c>null</c>, the caller assumes
/// that an error message has already been shown to the user.</returns>
public abstract ProtectedString Generate(PwProfile prf,
CryptoRandomStream crsRandomSource);
public virtual string GetOptions(string strCurrentOptions)
{
return string.Empty;
}
}
}

View File

@@ -0,0 +1,110 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace ModernKeePassLib.Cryptography.PasswordGenerator
{
public sealed class CustomPwGeneratorPool : IEnumerable<CustomPwGenerator>
{
private List<CustomPwGenerator> m_vGens = new List<CustomPwGenerator>();
public int Count
{
get { return m_vGens.Count; }
}
public CustomPwGeneratorPool()
{
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_vGens.GetEnumerator();
}
public IEnumerator<CustomPwGenerator> GetEnumerator()
{
return m_vGens.GetEnumerator();
}
public void Add(CustomPwGenerator pwg)
{
if(pwg == null) throw new ArgumentNullException("pwg");
PwUuid uuid = pwg.Uuid;
if(uuid == null) throw new ArgumentException();
int nIndex = FindIndex(uuid);
if(nIndex >= 0) m_vGens[nIndex] = pwg; // Replace
else m_vGens.Add(pwg);
}
public CustomPwGenerator Find(PwUuid uuid)
{
if(uuid == null) throw new ArgumentNullException("uuid");
foreach(CustomPwGenerator pwg in m_vGens)
{
if(uuid.EqualsValue(pwg.Uuid)) return pwg;
}
return null;
}
public CustomPwGenerator Find(string strName)
{
if(strName == null) throw new ArgumentNullException("strName");
foreach(CustomPwGenerator pwg in m_vGens)
{
if(pwg.Name == strName) return pwg;
}
return null;
}
private int FindIndex(PwUuid uuid)
{
if(uuid == null) throw new ArgumentNullException("uuid");
for(int i = 0; i < m_vGens.Count; ++i)
{
if(uuid.EqualsValue(m_vGens[i].Uuid)) return i;
}
return -1;
}
public bool Remove(PwUuid uuid)
{
if(uuid == null) throw new ArgumentNullException("uuid");
int nIndex = FindIndex(uuid);
if(nIndex < 0) return false;
m_vGens.RemoveAt(nIndex);
return true;
}
}
}

View File

@@ -0,0 +1,173 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using ModernKeePassLib.Security;
using ModernKeePassLib.Utility;
namespace ModernKeePassLib.Cryptography.PasswordGenerator
{
internal static class PatternBasedGenerator
{
internal static PwgError Generate(out ProtectedString psOut,
PwProfile pwProfile, CryptoRandomStream crsRandomSource)
{
psOut = ProtectedString.Empty;
LinkedList<char> vGenerated = new LinkedList<char>();
PwCharSet pcsCurrent = new PwCharSet();
PwCharSet pcsCustom = new PwCharSet();
PwCharSet pcsUsed = new PwCharSet();
bool bInCharSetDef = false;
string strPattern = ExpandPattern(pwProfile.Pattern);
if(strPattern.Length == 0) return PwgError.Success;
CharStream csStream = new CharStream(strPattern);
char ch = csStream.ReadChar();
while(ch != char.MinValue)
{
pcsCurrent.Clear();
bool bGenerateChar = false;
if(ch == '\\')
{
ch = csStream.ReadChar();
if(ch == char.MinValue) // Backslash at the end
{
vGenerated.AddLast('\\');
break;
}
if(bInCharSetDef) pcsCustom.Add(ch);
else
{
vGenerated.AddLast(ch);
pcsUsed.Add(ch);
}
}
else if(ch == '[')
{
pcsCustom.Clear();
bInCharSetDef = true;
}
else if(ch == ']')
{
pcsCurrent.Add(pcsCustom.ToString());
bInCharSetDef = false;
bGenerateChar = true;
}
else if(bInCharSetDef)
{
if(pcsCustom.AddCharSet(ch) == false)
pcsCustom.Add(ch);
}
else if(pcsCurrent.AddCharSet(ch) == false)
{
vGenerated.AddLast(ch);
pcsUsed.Add(ch);
}
else bGenerateChar = true;
if(bGenerateChar)
{
PwGenerator.PrepareCharSet(pcsCurrent, pwProfile);
if(pwProfile.NoRepeatingCharacters)
pcsCurrent.Remove(pcsUsed.ToString());
char chGen = PwGenerator.GenerateCharacter(pwProfile,
pcsCurrent, crsRandomSource);
if(chGen == char.MinValue) return PwgError.TooFewCharacters;
vGenerated.AddLast(chGen);
pcsUsed.Add(chGen);
}
ch = csStream.ReadChar();
}
if(vGenerated.Count == 0) return PwgError.Success;
char[] vArray = new char[vGenerated.Count];
vGenerated.CopyTo(vArray, 0);
if(pwProfile.PatternPermutePassword)
PwGenerator.ShufflePassword(vArray, crsRandomSource);
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vArray);
psOut = new ProtectedString(true, pbUtf8);
MemUtil.ZeroByteArray(pbUtf8);
Array.Clear(vArray, 0, vArray.Length);
vGenerated.Clear();
return PwgError.Success;
}
private static string ExpandPattern(string strPattern)
{
Debug.Assert(strPattern != null); if(strPattern == null) return string.Empty;
string str = strPattern;
while(true)
{
int nOpen = FindFirstUnescapedChar(str, '{');
int nClose = FindFirstUnescapedChar(str, '}');
if((nOpen >= 0) && (nOpen < nClose))
{
string strCount = str.Substring(nOpen + 1, nClose - nOpen - 1);
str = str.Remove(nOpen, nClose - nOpen + 1);
uint uRepeat;
if(StrUtil.TryParseUInt(strCount, out uRepeat) && (nOpen >= 1))
{
if(uRepeat == 0)
str = str.Remove(nOpen - 1, 1);
else
str = str.Insert(nOpen, new string(str[nOpen - 1], (int)uRepeat - 1));
}
}
else break;
}
return str;
}
private static int FindFirstUnescapedChar(string str, char ch)
{
for(int i = 0; i < str.Length; ++i)
{
char chCur = str[i];
if(chCur == '\\') ++i; // Next is escaped, skip it
else if(chCur == ch) return i;
}
return -1;
}
}
}

View File

@@ -0,0 +1,318 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace ModernKeePassLib.Cryptography.PasswordGenerator
{
public sealed class PwCharSet
{
public const string UpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public const string LowerCase = "abcdefghijklmnopqrstuvwxyz";
public const string Digits = "0123456789";
public const string UpperConsonants = "BCDFGHJKLMNPQRSTVWXYZ";
public const string LowerConsonants = "bcdfghjklmnpqrstvwxyz";
public const string UpperVowels = "AEIOU";
public const string LowerVowels = "aeiou";
public const string Punctuation = @",.;:";
public const string Brackets = @"[]{}()<>";
public const string PrintableAsciiSpecial = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
public const string UpperHex = "0123456789ABCDEF";
public const string LowerHex = "0123456789abcdef";
public const string Invalid = "\t\r\n";
public const string LookAlike = @"O0l1I|";
private const int CharTabSize = (0x10000 / 8);
private List<char> m_vChars = new List<char>();
private byte[] m_vTab = new byte[CharTabSize];
private string m_strHighAnsi = string.Empty;
private string m_strSpecial = string.Empty;
/// <summary>
/// Create a new, empty character set collection object.
/// </summary>
public PwCharSet()
{
this.Initialize(true);
}
public PwCharSet(string strCharSet)
{
this.Initialize(true);
this.Add(strCharSet);
}
private PwCharSet(bool bFullInitialize)
{
this.Initialize(bFullInitialize);
}
private void Initialize(bool bFullInitialize)
{
this.Clear();
if(bFullInitialize == false) return;
StringBuilder sbHighAnsi = new StringBuilder();
for(char ch = '~'; ch < 255; ++ch)
sbHighAnsi.Append(ch);
m_strHighAnsi = sbHighAnsi.ToString();
PwCharSet pcs = new PwCharSet(false);
pcs.AddRange('!', '/');
pcs.AddRange(':', '@');
pcs.AddRange('[', '`');
pcs.Remove(@"-_ ");
pcs.Remove(PwCharSet.Brackets);
m_strSpecial = pcs.ToString();
}
/// <summary>
/// Number of characters in this set.
/// </summary>
public uint Size
{
get { return (uint)m_vChars.Count; }
}
/// <summary>
/// Get a character of the set using an index.
/// </summary>
/// <param name="uPos">Index of the character to get.</param>
/// <returns>Character at the specified position. If the index is invalid,
/// an <c>ArgumentOutOfRangeException</c> is thrown.</returns>
public char this[uint uPos]
{
get
{
if(uPos >= (uint)m_vChars.Count)
throw new ArgumentOutOfRangeException("uPos");
return m_vChars[(int)uPos];
}
}
public string SpecialChars { get { return m_strSpecial; } }
public string HighAnsiChars { get { return m_strHighAnsi; } }
/// <summary>
/// Remove all characters from this set.
/// </summary>
public void Clear()
{
m_vChars.Clear();
Array.Clear(m_vTab, 0, m_vTab.Length);
}
public bool Contains(char ch)
{
return (((m_vTab[ch / 8] >> (ch % 8)) & 1) != char.MinValue);
}
public bool Contains(string strCharacters)
{
Debug.Assert(strCharacters != null);
if(strCharacters == null) throw new ArgumentNullException("strCharacters");
foreach(char ch in strCharacters)
{
if(this.Contains(ch) == false) return false;
}
return true;
}
/// <summary>
/// Add characters to the set.
/// </summary>
/// <param name="ch">Character to add.</param>
public void Add(char ch)
{
if(ch == char.MinValue) { Debug.Assert(false); return; }
if(this.Contains(ch) == false)
{
m_vChars.Add(ch);
m_vTab[ch / 8] |= (byte)(1 << (ch % 8));
}
}
/// <summary>
/// Add characters to the set.
/// </summary>
/// <param name="strCharSet">String containing characters to add.</param>
public void Add(string strCharSet)
{
Debug.Assert(strCharSet != null);
if(strCharSet == null) throw new ArgumentNullException("strCharSet");
m_vChars.Capacity = m_vChars.Count + strCharSet.Length;
foreach(char ch in strCharSet)
this.Add(ch);
}
public void Add(string strCharSet1, string strCharSet2)
{
this.Add(strCharSet1);
this.Add(strCharSet2);
}
public void Add(string strCharSet1, string strCharSet2, string strCharSet3)
{
this.Add(strCharSet1);
this.Add(strCharSet2);
this.Add(strCharSet3);
}
public void AddRange(char chMin, char chMax)
{
m_vChars.Capacity = m_vChars.Count + (chMax - chMin) + 1;
for(char ch = chMin; ch < chMax; ++ch)
this.Add(ch);
this.Add(chMax);
}
public bool AddCharSet(char chCharSetIdentifier)
{
bool bResult = true;
switch(chCharSetIdentifier)
{
case 'a': this.Add(PwCharSet.LowerCase, PwCharSet.Digits); break;
case 'A': this.Add(PwCharSet.LowerCase, PwCharSet.UpperCase,
PwCharSet.Digits); break;
case 'U': this.Add(PwCharSet.UpperCase, PwCharSet.Digits); break;
case 'c': this.Add(PwCharSet.LowerConsonants); break;
case 'C': this.Add(PwCharSet.LowerConsonants,
PwCharSet.UpperConsonants); break;
case 'z': this.Add(PwCharSet.UpperConsonants); break;
case 'd': this.Add(PwCharSet.Digits); break; // Digit
case 'h': this.Add(PwCharSet.LowerHex); break;
case 'H': this.Add(PwCharSet.UpperHex); break;
case 'l': this.Add(PwCharSet.LowerCase); break;
case 'L': this.Add(PwCharSet.LowerCase, PwCharSet.UpperCase); break;
case 'u': this.Add(PwCharSet.UpperCase); break;
case 'p': this.Add(PwCharSet.Punctuation); break;
case 'b': this.Add(PwCharSet.Brackets); break;
case 's': this.Add(PwCharSet.PrintableAsciiSpecial); break;
case 'S': this.Add(PwCharSet.UpperCase, PwCharSet.LowerCase);
this.Add(PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial); break;
case 'v': this.Add(PwCharSet.LowerVowels); break;
case 'V': this.Add(PwCharSet.LowerVowels, PwCharSet.UpperVowels); break;
case 'Z': this.Add(PwCharSet.UpperVowels); break;
case 'x': this.Add(m_strHighAnsi); break;
default: bResult = false; break;
}
return bResult;
}
public bool Remove(char ch)
{
m_vTab[ch / 8] &= (byte)~(1 << (ch % 8));
return m_vChars.Remove(ch);
}
public bool Remove(string strCharacters)
{
Debug.Assert(strCharacters != null);
if(strCharacters == null) throw new ArgumentNullException("strCharacters");
bool bResult = true;
foreach(char ch in strCharacters)
{
if(!Remove(ch)) bResult = false;
}
return bResult;
}
public bool RemoveIfAllExist(string strCharacters)
{
Debug.Assert(strCharacters != null);
if(strCharacters == null) throw new ArgumentNullException("strCharacters");
if(this.Contains(strCharacters) == false)
return false;
return this.Remove(strCharacters);
}
/// <summary>
/// Convert the character set to a string containing all its characters.
/// </summary>
/// <returns>String containing all character set characters.</returns>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach(char ch in m_vChars)
sb.Append(ch);
return sb.ToString();
}
public string PackAndRemoveCharRanges()
{
StringBuilder sb = new StringBuilder();
sb.Append(this.RemoveIfAllExist(PwCharSet.UpperCase) ? 'U' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.LowerCase) ? 'L' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Digits) ? 'D' : '_');
sb.Append(this.RemoveIfAllExist(m_strSpecial) ? 'S' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Punctuation) ? 'P' : '_');
sb.Append(this.RemoveIfAllExist(@"-") ? 'm' : '_');
sb.Append(this.RemoveIfAllExist(@"_") ? 'u' : '_');
sb.Append(this.RemoveIfAllExist(@" ") ? 's' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Brackets) ? 'B' : '_');
sb.Append(this.RemoveIfAllExist(m_strHighAnsi) ? 'H' : '_');
return sb.ToString();
}
public void UnpackCharRanges(string strRanges)
{
if(strRanges == null) { Debug.Assert(false); return; }
if(strRanges.Length < 10) { Debug.Assert(false); return; }
if(strRanges[0] != '_') this.Add(PwCharSet.UpperCase);
if(strRanges[1] != '_') this.Add(PwCharSet.LowerCase);
if(strRanges[2] != '_') this.Add(PwCharSet.Digits);
if(strRanges[3] != '_') this.Add(m_strSpecial);
if(strRanges[4] != '_') this.Add(PwCharSet.Punctuation);
if(strRanges[5] != '_') this.Add('-');
if(strRanges[6] != '_') this.Add('_');
if(strRanges[7] != '_') this.Add(' ');
if(strRanges[8] != '_') this.Add(PwCharSet.Brackets);
if(strRanges[9] != '_') this.Add(m_strHighAnsi);
}
}
}

View File

@@ -0,0 +1,146 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using ModernKeePassLib.Security;
namespace ModernKeePassLib.Cryptography.PasswordGenerator
{
public enum PwgError
{
Success = 0,
Unknown = 1,
TooFewCharacters = 2,
UnknownAlgorithm = 3
}
/// <summary>
/// Utility functions for generating random passwords.
/// </summary>
public static class PwGenerator
{
public static PwgError Generate(out ProtectedString psOut,
PwProfile pwProfile, byte[] pbUserEntropy,
CustomPwGeneratorPool pwAlgorithmPool)
{
Debug.Assert(pwProfile != null);
if(pwProfile == null) throw new ArgumentNullException("pwProfile");
CryptoRandomStream crs = CreateCryptoStream(pbUserEntropy);
PwgError e = PwgError.Unknown;
if(pwProfile.GeneratorType == PasswordGeneratorType.CharSet)
e = CharSetBasedGenerator.Generate(out psOut, pwProfile, crs);
else if(pwProfile.GeneratorType == PasswordGeneratorType.Pattern)
e = PatternBasedGenerator.Generate(out psOut, pwProfile, crs);
else if(pwProfile.GeneratorType == PasswordGeneratorType.Custom)
e = GenerateCustom(out psOut, pwProfile, crs, pwAlgorithmPool);
else { Debug.Assert(false); psOut = ProtectedString.Empty; }
return e;
}
private static CryptoRandomStream CreateCryptoStream(byte[] pbAdditionalEntropy)
{
byte[] pbKey = CryptoRandom.Instance.GetRandomBytes(256);
// Mix in additional entropy
if((pbAdditionalEntropy != null) && (pbAdditionalEntropy.Length > 0))
{
for(int nKeyPos = 0; nKeyPos < pbKey.Length; ++nKeyPos)
pbKey[nKeyPos] ^= pbAdditionalEntropy[nKeyPos % pbAdditionalEntropy.Length];
}
return new CryptoRandomStream(CrsAlgorithm.Salsa20, pbKey);
}
internal static char GenerateCharacter(PwProfile pwProfile,
PwCharSet pwCharSet, CryptoRandomStream crsRandomSource)
{
if(pwCharSet.Size == 0) return char.MinValue;
ulong uIndex = crsRandomSource.GetRandomUInt64();
uIndex %= (ulong)pwCharSet.Size;
char ch = pwCharSet[(uint)uIndex];
if(pwProfile.NoRepeatingCharacters)
pwCharSet.Remove(ch);
return ch;
}
internal static void PrepareCharSet(PwCharSet pwCharSet, PwProfile pwProfile)
{
pwCharSet.Remove(PwCharSet.Invalid);
if(pwProfile.ExcludeLookAlike) pwCharSet.Remove(PwCharSet.LookAlike);
if(pwProfile.ExcludeCharacters.Length > 0)
pwCharSet.Remove(pwProfile.ExcludeCharacters);
}
internal static void ShufflePassword(char[] pPassword,
CryptoRandomStream crsRandomSource)
{
Debug.Assert(pPassword != null); if(pPassword == null) return;
Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) return;
if(pPassword.Length <= 1) return; // Nothing to shuffle
for(int nSelect = 0; nSelect < pPassword.Length; ++nSelect)
{
ulong uRandomIndex = crsRandomSource.GetRandomUInt64();
uRandomIndex %= (ulong)(pPassword.Length - nSelect);
char chTemp = pPassword[nSelect];
pPassword[nSelect] = pPassword[nSelect + (int)uRandomIndex];
pPassword[nSelect + (int)uRandomIndex] = chTemp;
}
}
private static PwgError GenerateCustom(out ProtectedString psOut,
PwProfile pwProfile, CryptoRandomStream crs,
CustomPwGeneratorPool pwAlgorithmPool)
{
psOut = ProtectedString.Empty;
Debug.Assert(pwProfile.GeneratorType == PasswordGeneratorType.Custom);
if(pwAlgorithmPool == null) return PwgError.UnknownAlgorithm;
string strID = pwProfile.CustomAlgorithmUuid;
if(string.IsNullOrEmpty(strID)) { Debug.Assert(false); return PwgError.UnknownAlgorithm; }
byte[] pbUuid = Convert.FromBase64String(strID);
PwUuid uuid = new PwUuid(pbUuid);
CustomPwGenerator pwg = pwAlgorithmPool.Find(uuid);
if(pwg == null) { Debug.Assert(false); return PwgError.UnknownAlgorithm; }
ProtectedString pwd = pwg.Generate(pwProfile.CloneDeep(), crs);
if(pwd == null) return PwgError.Unknown;
psOut = pwd;
return PwgError.Success;
}
}
}

View File

@@ -0,0 +1,274 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.ComponentModel;
using System.Xml.Serialization;
using ModernKeePassLib.Interfaces;
using ModernKeePassLib.Security;
using ModernKeePassLib.Utility;
namespace ModernKeePassLib.Cryptography.PasswordGenerator
{
/// <summary>
/// Type of the password generator. Different types like generators
/// based on given patterns, based on character sets, etc. are
/// available.
/// </summary>
public enum PasswordGeneratorType
{
/// <summary>
/// Generator based on character spaces/sets, i.e. groups
/// of characters like lower-case, upper-case or numeric characters.
/// </summary>
CharSet = 0,
/// <summary>
/// Password generation based on a pattern. The user has provided
/// a pattern, which describes how the generated password has to
/// look like.
/// </summary>
Pattern = 1,
Custom = 2
}
public sealed class PwProfile : IDeepCloneable<PwProfile>
{
private string m_strName = string.Empty;
[DefaultValue("")]
public string Name
{
get { return m_strName; }
set { m_strName = value; }
}
private PasswordGeneratorType m_type = PasswordGeneratorType.CharSet;
public PasswordGeneratorType GeneratorType
{
get { return m_type; }
set { m_type = value; }
}
private bool m_bUserEntropy = false;
[DefaultValue(false)]
public bool CollectUserEntropy
{
get { return m_bUserEntropy; }
set { m_bUserEntropy = value; }
}
private uint m_uLength = 20;
public uint Length
{
get { return m_uLength; }
set { m_uLength = value; }
}
private PwCharSet m_pwCharSet = new PwCharSet(PwCharSet.UpperCase +
PwCharSet.LowerCase + PwCharSet.Digits);
[XmlIgnore]
public PwCharSet CharSet
{
get { return m_pwCharSet; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_pwCharSet = value;
}
}
private string m_strCharSetRanges = string.Empty;
[DefaultValue("")]
public string CharSetRanges
{
get { this.UpdateCharSet(true); return m_strCharSetRanges; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strCharSetRanges = value;
this.UpdateCharSet(false);
}
}
private string m_strCharSetAdditional = string.Empty;
[DefaultValue("")]
public string CharSetAdditional
{
get { this.UpdateCharSet(true); return m_strCharSetAdditional; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strCharSetAdditional = value;
this.UpdateCharSet(false);
}
}
private string m_strPattern = string.Empty;
[DefaultValue("")]
public string Pattern
{
get { return m_strPattern; }
set { m_strPattern = value; }
}
private bool m_bPatternPermute = false;
[DefaultValue(false)]
public bool PatternPermutePassword
{
get { return m_bPatternPermute; }
set { m_bPatternPermute = value; }
}
private bool m_bNoLookAlike = false;
[DefaultValue(false)]
public bool ExcludeLookAlike
{
get { return m_bNoLookAlike; }
set { m_bNoLookAlike = value; }
}
private bool m_bNoRepeat = false;
[DefaultValue(false)]
public bool NoRepeatingCharacters
{
get { return m_bNoRepeat; }
set { m_bNoRepeat = value; }
}
private string m_strExclude = string.Empty;
[DefaultValue("")]
public string ExcludeCharacters
{
get { return m_strExclude; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strExclude = value;
}
}
private string m_strCustomID = string.Empty;
[DefaultValue("")]
public string CustomAlgorithmUuid
{
get { return m_strCustomID; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strCustomID = value;
}
}
private string m_strCustomOpt = string.Empty;
[DefaultValue("")]
public string CustomAlgorithmOptions
{
get { return m_strCustomOpt; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strCustomOpt = value;
}
}
public PwProfile()
{
}
public PwProfile CloneDeep()
{
PwProfile p = new PwProfile();
p.m_strName = m_strName;
p.m_type = m_type;
p.m_bUserEntropy = m_bUserEntropy;
p.m_uLength = m_uLength;
p.m_pwCharSet = new PwCharSet(m_pwCharSet.ToString());
p.m_strCharSetRanges = m_strCharSetRanges;
p.m_strCharSetAdditional = m_strCharSetAdditional;
p.m_strPattern = m_strPattern;
p.m_bPatternPermute = m_bPatternPermute;
p.m_bNoLookAlike = m_bNoLookAlike;
p.m_bNoRepeat = m_bNoRepeat;
p.m_strExclude = m_strExclude;
p.m_strCustomID = m_strCustomID;
p.m_strCustomOpt = m_strCustomOpt;
return p;
}
private void UpdateCharSet(bool bSetXml)
{
if(bSetXml)
{
PwCharSet pcs = new PwCharSet(m_pwCharSet.ToString());
m_strCharSetRanges = pcs.PackAndRemoveCharRanges();
m_strCharSetAdditional = pcs.ToString();
}
else
{
PwCharSet pcs = new PwCharSet(m_strCharSetAdditional);
pcs.UnpackCharRanges(m_strCharSetRanges);
m_pwCharSet = pcs;
}
}
public static PwProfile DeriveFromPassword(ProtectedString psPassword)
{
PwProfile pp = new PwProfile();
Debug.Assert(psPassword != null); if(psPassword == null) return pp;
byte[] pbUtf8 = psPassword.ReadUtf8();
char[] vChars = StrUtil.Utf8.GetChars(pbUtf8);
pp.GeneratorType = PasswordGeneratorType.CharSet;
pp.Length = (uint)vChars.Length;
PwCharSet pcs = pp.CharSet;
pcs.Clear();
foreach(char ch in vChars)
{
if((ch >= 'A') && (ch <= 'Z')) pcs.Add(PwCharSet.UpperCase);
else if((ch >= 'a') && (ch <= 'z')) pcs.Add(PwCharSet.LowerCase);
else if((ch >= '0') && (ch <= '9')) pcs.Add(PwCharSet.Digits);
else if((@"!#$%&'*+,./:;=?@^").IndexOf(ch) >= 0) pcs.Add(pcs.SpecialChars);
else if(ch == ' ') pcs.Add(' ');
else if(ch == '-') pcs.Add('-');
else if(ch == '_') pcs.Add('_');
else if(ch == '\"') pcs.Add(pcs.SpecialChars);
else if(ch == '\\') pcs.Add(pcs.SpecialChars);
else if((@"()[]{}<>").IndexOf(ch) >= 0) pcs.Add(PwCharSet.Brackets);
else if((ch >= '~') && (ch <= 255)) pcs.Add(pcs.HighAnsiChars);
else pcs.Add(ch);
}
Array.Clear(vChars, 0, vChars.Length);
MemUtil.ZeroByteArray(pbUtf8);
return pp;
}
public bool HasSecurityReducingOption()
{
return (m_bNoLookAlike || m_bNoRepeat || (m_strExclude.Length > 0));
}
}
}