1
Fork 0
mirror of https://github.com/jech/galene.git synced 2024-12-22 15:25:48 +01:00

Add support for hashing password with BCrypt.

This commit is contained in:
Juliusz Chroboczek 2023-11-23 13:57:37 +01:00
parent 2a32ac8f40
commit 8628344a6d
3 changed files with 66 additions and 14 deletions

View file

@ -9,22 +9,31 @@ import (
"fmt"
"log"
"os"
"strings"
"golang.org/x/crypto/bcrypt"
"golang.org/x/crypto/pbkdf2"
"github.com/jech/galene/group"
)
func main() {
var algorithm string
var iterations int
var cost int
var length int
var saltLen int
var username string
flag.StringVar(&username, "user", "",
"generate entry for given `username`")
flag.IntVar(&iterations, "iterations", 4096, "`number` of iterations")
flag.IntVar(&length, "key", 32, "key `length`")
flag.IntVar(&saltLen, "salt", 8, "salt `length`")
flag.StringVar(&algorithm, "hash", "pbkdf2",
"hashing `algorithm`")
flag.IntVar(&iterations, "iterations", 4096,
"`number` of iterations (pbkdf2)")
flag.IntVar(&cost, "cost", bcrypt.DefaultCost,
"`cost` (bcrypt)")
flag.IntVar(&length, "key", 32, "key `length` (pbkdf2)")
flag.IntVar(&saltLen, "salt", 8, "salt `length` (pbkdf2)")
flag.Parse()
if len(flag.Args()) == 0 {
@ -43,17 +52,34 @@ func main() {
if err != nil {
log.Fatalf("Salt: %v", err)
}
key := pbkdf2.Key(
[]byte(pw), salt, iterations, length, sha256.New,
)
var p group.Password
if strings.EqualFold(algorithm, "pbkdf2") {
key := pbkdf2.Key(
[]byte(pw), salt, iterations, length, sha256.New,
)
p = group.Password{
Type: "pbkdf2",
Hash: "sha-256",
Key: hex.EncodeToString(key),
Salt: hex.EncodeToString(salt),
Iterations: iterations,
}
} else if strings.EqualFold(algorithm, "bcrypt") {
key, err := bcrypt.GenerateFromPassword(
[]byte(pw), cost,
)
if err != nil {
log.Fatalf("Couldn't hash password: %v", err)
}
p := group.Password{
Type: "pbkdf2",
Hash: "sha-256",
Key: hex.EncodeToString(key),
Salt: hex.EncodeToString(salt),
Iterations: iterations,
p = group.Password{
Type: "bcrypt",
Key: string(key),
}
} else {
log.Fatalf("Unknown hash type %v", algorithm)
}
e := json.NewEncoder(os.Stdout)
if username != "" {
creds := group.ClientPattern{

View file

@ -8,6 +8,7 @@ import (
"errors"
"hash"
"golang.org/x/crypto/bcrypt"
"golang.org/x/crypto/pbkdf2"
"github.com/jech/galene/conn"
@ -47,6 +48,12 @@ func (p Password) Match(pw string) (bool, error) {
[]byte(pw), salt, p.Iterations, len(key), h,
)
return bytes.Equal(key, theirKey), nil
case "bcrypt":
err := bcrypt.CompareHashAndPassword([]byte(p.Key), []byte(pw))
if err == bcrypt.ErrMismatchedHashAndPassword {
return false, nil
}
return err == nil, err
default:
return false, errors.New("unknown password type")
}

View file

@ -17,6 +17,10 @@ var pw3 = Password{
Iterations: 4096,
}
var pw4 = Password{
Type: "bcrypt",
Key: "$2a$10$afOr2f33onT/nDFFyT3mbOq5FMSw1wWXfyTXQTBMbKvZpBkoD3Qwu",
}
var pw5 = Password{
Type: "bad",
}
@ -27,6 +31,9 @@ func TestGood(t *testing.T) {
if match, err := pw3.Match("pass"); err != nil || !match {
t.Errorf("pw3 doesn't match (%v)", err)
}
if match, err := pw4.Match("pass"); err != nil || !match {
t.Errorf("pw4 doesn't match (%v)", err)
}
}
func TestBad(t *testing.T) {
@ -39,7 +46,10 @@ func TestBad(t *testing.T) {
if match, err := pw3.Match("bad"); err != nil || match {
t.Errorf("pw3 matches")
}
if match, err := pw4.Match("bad"); err == nil || match {
if match, err := pw4.Match("bad"); err != nil || match {
t.Errorf("pw4 matches")
}
if match, err := pw5.Match("bad"); err == nil || match {
t.Errorf("pw4 matches")
}
}
@ -50,7 +60,7 @@ func TestJSON(t *testing.T) {
t.Errorf("Expected \"pass\", got %v", string(plain))
}
for _, pw := range []Password{pw1, pw2, pw3, pw4} {
for _, pw := range []Password{pw1, pw2, pw3, pw4, pw5} {
j, err := json.Marshal(pw)
if err != nil {
t.Fatalf("Marshal: %v", err)
@ -85,3 +95,12 @@ func BenchmarkPBKDF2(b *testing.B) {
}
}
}
func BenchmarkBCrypt(b *testing.B) {
for i := 0; i < b.N; i++ {
match, err := pw4.Match("bad")
if err != nil || match {
b.Errorf("pw3 matched")
}
}
}