Пример #1
0
func crackTimeToScore(seconds float64) int {
	if seconds < math.Pow(10, 2) {
		return 0
	} else if seconds < math.Pow(10, 4) {
		return 1
	} else if seconds < math.Pow(10, 6) {
		return 2
	} else if seconds < math.Pow(10, 8) {
		return 3
	}

	return 4
}
Пример #2
0
func getWordsEntropy(numWords int, guessesPerSec float64) Entropy {
	entropy := Entropy{}

	var (
		avgHumanLifespanInYears float64 = 67.2         // https://en.wikipedia.org/wiki/Life_expectancy
		ageOfUniverseInYears    float64 = 13798000000. // https://en.wikipedia.org/wiki/Age_of_the_universe
	)

	entropy.Entropy = 12.92 * float64(numWords)

	// https://xkcd.com/936/
	// https://security.stackexchange.com/questions/62832/is-the-oft-cited-xkcd-scheme-no-longer-good-advice/62881#62881
	// https://hashcat.net/forum/thread-2580.html
	entropy.KeySpace = math.Pow(7776., float64(numWords))

	// Divide the keySpace in half. On average it is expected that an
	// exhaustive search of only half the keySpace will result in success.
	entropy.HalfKeySpace = entropy.KeySpace / 2

	// // "Assume that your adversary is capable of a trillion guesses per second" - Snowden
	// // http://www.nytimes.com/2013/08/18/magazine/laura-poitras-snowden.html?pagewanted=all&_r=0
	// guessesPerSec = 1000000000000.

	entropy.Seconds = entropy.HalfKeySpace / guessesPerSec
	entropy.Minutes = entropy.Seconds / 60
	entropy.Hours = entropy.Minutes / 60
	entropy.Days = entropy.Hours / 24
	entropy.Years = entropy.Days / 365
	entropy.Millenia = entropy.Years / 1000
	entropy.HumanLifetimes = entropy.Years / avgHumanLifespanInYears
	entropy.UniverseLifetimes = entropy.Years / ageOfUniverseInYears

	return entropy
}
Пример #3
0
func SpatialEntropy(match match.Match, turns int, shiftCount int) float64 {
	var s, d float64
	if match.DictionaryName == "qwerty" || match.DictionaryName == "dvorak" {
		//todo: verify qwerty and dvorak have the same length and degree
		s = float64(len(adjacency.BuildQwerty().Graph))
		d = adjacency.BuildQwerty().CalculateAvgDegree()
	} else {
		s = float64(KEYPAD_STARTING_POSITIONS)
		d = KEYPAD_AVG_DEGREE
	}

	possibilities := float64(0)

	length := float64(len(match.Token))

	//TODO: Should this be <= or just < ?
	//Estimate the number of possible patterns w/ length L or less with t turns or less
	for i := float64(2); i <= length+1; i++ {
		possibleTurns := math.Min(float64(turns), i-1)
		for j := float64(1); j <= possibleTurns+1; j++ {
			x := zxcvbn_math.NChoseK(i-1, j-1) * s * math.Pow(d, j)
			possibilities += x
		}
	}

	entropy := math.Log2(possibilities)
	//add extra entropu for shifted keys. ( % instead of 5 A instead of a)
	//Math is similar to extra entropy for uppercase letters in dictionary matches.

	if S := float64(shiftCount); S > float64(0) {
		possibilities = float64(0)
		U := length - S

		for i := float64(0); i < math.Min(S, U)+1; i++ {
			possibilities += zxcvbn_math.NChoseK(S+U, i)
		}

		entropy += math.Log2(possibilities)
	}

	return entropy
}
Пример #4
0
/*
Returns minimum entropy

    Takes a list of overlapping matches, returns the non-overlapping sublist with
    minimum entropy. O(nm) dp alg for length-n password with m candidate matches.
*/
func MinimumEntropyMatchSequence(password string, matches []match.Match) MinEntropyMatch {
	bruteforceCardinality := float64(entropy.CalcBruteForceCardinality(password))
	upToK := make([]float64, len(password))
	backPointers := make([]match.Match, len(password))

	for k := 0; k < len(password); k++ {
		upToK[k] = get(upToK, k-1) + math.Log2(bruteforceCardinality)

		for _, match := range matches {
			if match.J != k {
				continue
			}

			i, j := match.I, match.J
			//			see if best entropy up to i-1 + entropy of match is less that current min at j
			upTo := get(upToK, i-1)
			calculatedEntropy := match.Entropy
			match.Entropy = calculatedEntropy
			candidateEntropy := upTo + calculatedEntropy

			if candidateEntropy < upToK[j] {
				upToK[j] = candidateEntropy
				match.Entropy = candidateEntropy
				backPointers[j] = match
			}
		}
	}

	//walk backwards and decode the best sequence
	var matchSequence []match.Match
	passwordLen := len(password)
	passwordLen--
	for k := passwordLen; k >= 0; {
		match := backPointers[k]
		if match.Pattern != "" {
			matchSequence = append(matchSequence, match)
			k = match.I - 1

		} else {
			k--
		}

	}
	sort.Sort(match.Matches(matchSequence))

	makeBruteForceMatch := func(i, j int) match.Match {
		return match.Match{Pattern: "bruteforce",
			I:       i,
			J:       j,
			Token:   password[i : j+1],
			Entropy: math.Log2(math.Pow(bruteforceCardinality, float64(j-i)))}

	}

	k := 0
	var matchSequenceCopy []match.Match
	for _, match := range matchSequence {
		i, j := match.I, match.J
		if i-k > 0 {
			matchSequenceCopy = append(matchSequenceCopy, makeBruteForceMatch(k, i-1))
		}
		k = j + 1
		matchSequenceCopy = append(matchSequenceCopy, match)
	}

	if k < len(password) {
		matchSequenceCopy = append(matchSequenceCopy, makeBruteForceMatch(k, len(password)-1))
	}
	var minEntropy float64
	if len(password) == 0 {
		minEntropy = float64(0)
	} else {
		minEntropy = upToK[len(password)-1]
	}

	crackTime := roundToXDigits(entropyToCrackTime(minEntropy), 3)
	return MinEntropyMatch{Password: password,
		Entropy:          roundToXDigits(minEntropy, 3),
		MatchSequence:    matchSequenceCopy,
		CrackTime:        crackTime,
		CrackTimeDisplay: displayTime(crackTime),
		Score:            crackTimeToScore(crackTime)}

}
Пример #5
0
func entropyToCrackTime(entropy float64) float64 {
	crackTime := (0.5 * math.Pow(float64(2), entropy)) * SECONDS_PER_GUESS

	return crackTime
}