summary refs log tree commit diff stats
path: root/password
diff options
context:
space:
mode:
Diffstat (limited to 'password')
-rw-r--r--password/check.go13
-rw-r--r--password/check_test.go38
-rw-r--r--password/hash.go11
-rw-r--r--password/hash_test.go34
-rw-r--r--password/randstr.go13
5 files changed, 109 insertions, 0 deletions
diff --git a/password/check.go b/password/check.go
new file mode 100644
index 0000000..b84e9fe
--- /dev/null
+++ b/password/check.go
@@ -0,0 +1,13 @@
+// Password package contains functions related to passwords.
+package password
+
+import "golang.org/x/crypto/bcrypt"
+
+// Check takes a string and hash as input and returns an error. If
+// the error is not nil then the consider the password wrong. We're
+// returning error instead of a bool so that we can print failed
+// logins to log and logging shouldn't happen here.
+func Check(password, hash string) error {
+	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
+	return err
+}
diff --git a/password/check_test.go b/password/check_test.go
new file mode 100644
index 0000000..e55c169
--- /dev/null
+++ b/password/check_test.go
@@ -0,0 +1,38 @@
+package password
+
+import "testing"
+
+// TestCheck tests the Check function.
+func TestCheck(t *testing.T) {
+	var err error
+	passhash := make(map[string]string)
+
+	// First we check with static values, these should always pass.
+	passhash["ter4cQ=="] = "$2a$10$ANkaNEFFQ4zxDwTwvAUfoOCqpVIdgtPFopFOTMSrFy39WkaMAYLIC"
+	passhash["G29J6A=="] = "$2a$10$1oH1PyhncIHcHJWbLt3Gv.OjClUoFoaEDaFpQ9E9atfRbIrVxsbwm"
+	passhash["Z1S/kQ=="] = "$2a$10$fZ05kKmb7bh4vBLebpK1u.3bUNQ6eeX5ghT/GZaekgS.5bx4.Ru1e"
+	passhash["J861dQ=="] = "$2a$10$nXb6Btn6n3AWMAUkDh9bFObvQw5V9FLKhfX.E1EzRWgVDuqIp99u2"
+
+	// We also check with values generated with Hash, this may
+	// fail if Hash itself fails in that case it's not Check error
+	// so the test shouldn't fail but warning should be sent. We
+	// use genID func to generate random inputs for this test.
+	for i := 1; i <= 4; i++ {
+		p := RandStr(8)
+		passhash[p], err = Hash(p)
+		if err != nil {
+			t.Log("hashPass func failed")
+		}
+	}
+
+	// We test the Check func by ranging over all values of
+	// passhash. We assume that Hash func returns correct hashes.
+	for p, h := range passhash {
+		err = Check(p, h)
+		if err != nil {
+			t.Errorf("password: %s, hash: %s didn't match.",
+				p, h)
+		}
+	}
+
+}
diff --git a/password/hash.go b/password/hash.go
new file mode 100644
index 0000000..3dd949b
--- /dev/null
+++ b/password/hash.go
@@ -0,0 +1,11 @@
+package password
+
+import "golang.org/x/crypto/bcrypt"
+
+// Hash takes a string as input and returns the hash of the
+// password.
+func Hash(password string) (string, error) {
+	// 10 is the default cost.
+	out, err := bcrypt.GenerateFromPassword([]byte(password), 10)
+	return string(out), err
+}
diff --git a/password/hash_test.go b/password/hash_test.go
new file mode 100644
index 0000000..4f37393
--- /dev/null
+++ b/password/hash_test.go
@@ -0,0 +1,34 @@
+package password
+
+import "testing"
+
+// TestHash tests the Hash function.
+func TestHash(t *testing.T) {
+	var err error
+	passhash := make(map[string]string)
+
+	// We generate random hashes with Hash, random string is
+	// generate by RandStr func.
+	for i := 1; i <= 8; i++ {
+		p := RandStr(8)
+		passhash[p], err = Hash(p)
+
+		// Here we test if the hashPass func runs sucessfully.
+		if err != nil {
+			t.Errorf("Hash func failed for password: %s",
+				p)
+		}
+	}
+
+	// Here we are testing if the hashPass func returns correct
+	// hashes. We assume that checkPass func returns correct
+	// values.
+	for p, h := range passhash {
+		err = Check(p, h)
+		if err != nil {
+			t.Errorf("password: %s, hash: %s didn't match.",
+				p, h)
+		}
+	}
+
+}
diff --git a/password/randstr.go b/password/randstr.go
new file mode 100644
index 0000000..86ae9a1
--- /dev/null
+++ b/password/randstr.go
@@ -0,0 +1,13 @@
+package password
+
+import (
+	"crypto/rand"
+	"encoding/base64"
+)
+
+// RandStr will return a random base64 encoded string of length n.
+func RandStr(n int) string {
+	b := make([]byte, n/2)
+	rand.Read(b)
+	return base64.StdEncoding.EncodeToString(b)
+}