private static double ComputePathCost(List<QePatternInstance> 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); }
/// <summary> /// Estimate the quality of a password. /// </summary> /// <param name="vPasswordChars">Password to check.</param> /// <returns>Estimated bit-strength of the password.</returns> 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<QePatternInstance>[] vPatterns = new List<QePatternInstance>[n]; for(int i = 0; i < n; ++i) { vPatterns[i] = new List<QePatternInstance>(); 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<QePathState> sRec = new Stack<QePathState>(); sRec.Push(new QePathState(0, new List<QePatternInstance>())); 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<QePatternInstance> 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<QePatternInstance> lNewPath = new List<QePatternInstance>(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); }
/// <summary> /// Estimate the quality of a password. /// </summary> /// <param name="vPasswordChars">Password to check.</param> /// <returns>Estimated bit-strength of the password.</returns> 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 <QePatternInstance>[] vPatterns = new List <QePatternInstance> [n]; for (int i = 0; i < n; ++i) { vPatterns[i] = new List <QePatternInstance>(); 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 <QePathState> sRec = new Stack <QePathState>(); sRec.Push(new QePathState(0, new List <QePatternInstance>())); 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 <QePatternInstance> 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 <QePatternInstance> lNewPath = new List <QePatternInstance>(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)); }
private static double ComputePathCost(List <QePatternInstance> 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 double ComputePathCost(List <QePatternInstance> patternInstanceCollection, char[] password, EntropyEncoder ecPattern, MultiEntropyEncoder mcData) { ecPattern.Reset(); for (var i = 0; i < patternInstanceCollection.Count; ++i) { ecPattern.Write(patternInstanceCollection[i].ThePatternId); } var dblPatternCost = ecPattern.GetOutputSize(); mcData.Reset(); var dblDataCost = 0.0; foreach (var parameterInstance in patternInstanceCollection) { QeCharType characterType = parameterInstance.SingleCharType; if (characterType != null) { var character = password[parameterInstance.Position]; if (!mcData.Write(characterType.TypeId, character)) { dblDataCost += parameterInstance.Cost; } } else { dblDataCost += parameterInstance.Cost; } } dblDataCost += mcData.GetOutputSize(); return(dblPatternCost + dblDataCost); }