mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-08 04:20:59 -05:00
105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
package zxcvbn
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
)
|
|
|
|
type EstimatedTimes struct {
|
|
CrackTimesSeconds map[string]float64 `json:"crack_times_seconds"`
|
|
CrashTimesDisplay map[string]string `json:"crack_times_display"`
|
|
Score int
|
|
}
|
|
|
|
func estimateAttackTimes(guesses float64) (t EstimatedTimes) {
|
|
// crack_times_seconds
|
|
t.CrackTimesSeconds = make(map[string]float64)
|
|
t.CrackTimesSeconds["online_throttling_100_per_hour"] = guesses / (100 / 3600)
|
|
t.CrackTimesSeconds["online_no_throttling_10_per_second"] = guesses / 10
|
|
t.CrackTimesSeconds["offline_slow_hashing_1e4_per_second"] = guesses / 1e4
|
|
t.CrackTimesSeconds["offline_fast_hashing_1e10_per_second"] = guesses / 1e10
|
|
|
|
t.CrashTimesDisplay = make(map[string]string)
|
|
|
|
for scenario, seconds := range t.CrackTimesSeconds {
|
|
t.CrashTimesDisplay[scenario] = displayTime(seconds)
|
|
}
|
|
|
|
t.Score = guessesToScore(guesses)
|
|
return
|
|
}
|
|
|
|
func guessesToScore(guesses float64) int {
|
|
const DELTA = 5
|
|
if guesses < 1e3+DELTA {
|
|
// risky password: "too guessable"
|
|
return 0
|
|
}
|
|
if guesses < 1e6+DELTA {
|
|
// modest protection from throttled online attacks: "very guessable"
|
|
return 1
|
|
}
|
|
if guesses < 1e8+DELTA {
|
|
// modest protection from unthrottled online attacks: "somewhat guessable"
|
|
return 2
|
|
}
|
|
if guesses < 1e10+DELTA {
|
|
// modest protection from offline attacks: "safely unguessable"
|
|
// assuming a salted, slow hash function like bcrypt, scrypt, PBKDF2, argon, etc
|
|
return 3
|
|
}
|
|
// strong protection from offline attacks under same scenario: "very unguessable"
|
|
return 4
|
|
}
|
|
|
|
func displayTime(seconds float64) string {
|
|
minute := float64(60)
|
|
hour := minute * 60
|
|
day := hour * 24
|
|
month := day * 31
|
|
year := month * 12
|
|
century := year * 100
|
|
|
|
if seconds < 1 {
|
|
return "less than a second"
|
|
}
|
|
if seconds < minute {
|
|
return strCount(seconds, "second")
|
|
} else if seconds < hour {
|
|
return strCount(seconds/minute, "minute")
|
|
} else if seconds < day {
|
|
return strCount(seconds/hour, "hour")
|
|
} else if seconds < month {
|
|
return strCount(seconds/day, "day")
|
|
} else if seconds < year {
|
|
return strCount(seconds/month, "month")
|
|
} else if seconds < century {
|
|
return strCount(seconds/year, "year")
|
|
} else {
|
|
return "centuries"
|
|
}
|
|
}
|
|
|
|
func strCount(count float64, base string) string {
|
|
c := int(round(count, 0.5, 0))
|
|
str := fmt.Sprintf("%d %s", c, base)
|
|
if c > 1 {
|
|
str += "s"
|
|
}
|
|
return str
|
|
}
|
|
|
|
func round(val float64, roundOn float64, places int) (newVal float64) {
|
|
var round float64
|
|
pow := math.Pow(10, float64(places))
|
|
digit := pow * val
|
|
_, div := math.Modf(digit)
|
|
if div >= roundOn {
|
|
round = math.Ceil(digit)
|
|
} else {
|
|
round = math.Floor(digit)
|
|
}
|
|
newVal = round / pow
|
|
return
|
|
}
|