private static double L33tVariations(DictionaryMatch dictionaryMatch) { if (dictionaryMatch.GetType() != typeof(L33tDictionaryMatch)) { return(1); } double variations = 1; L33tDictionaryMatch ldm = (L33tDictionaryMatch)dictionaryMatch; foreach (KeyValuePair <char, char> val in ldm.Subs) { char subbed = val.Key; char unsubbed = val.Value; char[] chrs = ldm.Token.ToLower().ToCharArray(); int S = chrs.Where(c => c == subbed).Count(); int U = chrs.Where(c => c == unsubbed).Count(); if (S == 0 || U == 0) { variations *= 2; } else { int p = (int)Math.Min(U, S); double possibilities = 0; foreach (int i in EnumerableUtility.Range(1, p + 1)) { possibilities += nCk(U + S, i); } variations *= possibilities; } } return(variations); }
private void CalulateL33tEntropy(L33tDictionaryMatch match) { // I'm a bit dubious about this function, but I have duplicated zxcvbn functionality regardless int possibilities = 0; foreach (KeyValuePair <char, char> kvp in match.Subs) { int subbedChars = match.Token.Count(c => c == kvp.Key); int unsubbedChars = match.Token.Count(c => c == kvp.Value); // Won't this always be zero? possibilities += Enumerable.Range(0, Math.Min(subbedChars, unsubbedChars) + 1).Sum(i => (int)PasswordScoring.Binomial(subbedChars + unsubbedChars, i)); } // Calculate the base entropy double entropy = Math.Log(possibilities, 2); // In the case of only a single subsitution (e.g. 4pple) this would otherwise come out as zero, so give it one bit match.L33tEntropy = entropy < 1 ? 1 : entropy; match.Entropy += match.L33tEntropy; // We have to recalculate the uppercase entropy -- the password matcher will have used the subbed password not the original text match.Entropy -= match.UppercaseEntropy; match.UppercaseEntropy = PasswordScoring.CalculateUppercaseEntropy(match.Token); match.Entropy += match.UppercaseEntropy; }