From fafe11c5abcfb55283f0ca8bacdbe07c1a2c9803 Mon Sep 17 00:00:00 2001 From: Stephen Hosom <0xhosom@gmail.com> Date: Mon, 14 May 2018 15:19:33 -0400 Subject: [PATCH] Add basic entropy function. Add a metric entropy function check, but do not configure it to execute. I need to look over how this is structured to determine how I want to handle new checks. --- passfilt-server/checkpass.go | 27 +++++++++++++++++++++++++++ passfilt-server/checkpass_test.go | 13 +++++++++++++ 2 files changed, 40 insertions(+) diff --git a/passfilt-server/checkpass.go b/passfilt-server/checkpass.go index ee0830b..f0fe347 100644 --- a/passfilt-server/checkpass.go +++ b/passfilt-server/checkpass.go @@ -4,6 +4,7 @@ import ( "bufio" "crypto/sha1" "fmt" + "math" "net/http" "strings" "sync" @@ -50,6 +51,32 @@ func isPwnd(p string) bool { return false } +// metricEntropy tries to measure the 'randomness' of a password +// it returns the shannon entropy divided by the length of the +// password. +func metricEntropy(pass string) float64 { + m := map[rune]float64{} + for _, r := range pass { + m[r]++ + } + + var hx float64 + for _, val := range m { + hx += val * math.Log2(val) + } + + l := float64(len(pass)) + hx = (math.Log2(l) - (hx / l)) + + mEntropy := hx / l + + if math.IsNaN(mEntropy) { + return 0.0 + } + + return mEntropy +} + func checkpass(user string, pass string, banlist *sync.Map) bool { // by default, passwords are considered OK passOk := true diff --git a/passfilt-server/checkpass_test.go b/passfilt-server/checkpass_test.go index 402af34..e5287f6 100644 --- a/passfilt-server/checkpass_test.go +++ b/passfilt-server/checkpass_test.go @@ -26,3 +26,16 @@ func TestIsPwnd(t *testing.T) { t.Error("Random password detected as pwnd.") } } + +func TestMetricEntropy(t *testing.T) { + s := "abbcccdddd" + + if metricEntropy(s) != 0.18464393446710153 { + t.Error("Failed to calculate correct entropy.", metricEntropy(s)) + } + + s = "" + if metricEntropy(s) != 0 { + t.Error("Failed to handle empty string.", metricEntropy(s)) + } +}