mirror of
https://github.com/caddyserver/caddy.git
synced 2025-08-11 09:16:26 -04:00
bcrypt: add cost parameter to hash-password (#7149)
* feat: add bcrypt cost parameter to hash-password * revert: typos * refactor: take the cost out of interface * fix: default bcrypt cost to 14 * fix: follow bcrypt library for min and max cost * doc: mention defaultBcryptCost in cost parameter description * chore: gci format * fix: more specific bcrypt cost algorithm flag * feat: bcrypt cost provisioning * Revert "feat: bcrypt cost provisioning" This reverts commit e09d4bd036e7657588ed7785afd2c5388b29fb2a. * chore: gci format * chore: gci format * chore: gci format * chore: golangcilint fmted --------- Co-authored-by: Mohammed Al Sahaf <msaa1990@gmail.com>
This commit is contained in:
parent
19ff47a63b
commit
49dac61b07
@ -60,7 +60,8 @@ func (Authentication) CaddyModule() caddy.ModuleInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// Provision sets up a.
|
||||
// Provision sets up an Authentication module by initializing its logger,
|
||||
// loading and registering all configured authentication providers.
|
||||
func (a *Authentication) Provision(ctx caddy.Context) error {
|
||||
a.logger = ctx.Logger()
|
||||
a.Providers = make(map[string]Authenticator)
|
||||
|
@ -32,7 +32,7 @@ import (
|
||||
func init() {
|
||||
caddycmd.RegisterCommand(caddycmd.Command{
|
||||
Name: "hash-password",
|
||||
Usage: "[--plaintext <password>] [--algorithm <name>]",
|
||||
Usage: "[--plaintext <password>] [--algorithm <name>] [--cost <difficulty>]",
|
||||
Short: "Hashes a password and writes base64",
|
||||
Long: `
|
||||
Convenient way to hash a plaintext password. The resulting
|
||||
@ -43,10 +43,17 @@ Caddy is attached to a controlling tty, the plaintext will
|
||||
not be echoed.
|
||||
|
||||
--algorithm currently only supports 'bcrypt', and is the default.
|
||||
|
||||
--cost sets the bcrypt hashing difficulty.
|
||||
Higher values increase security by making the hash computation slower and more CPU-intensive.
|
||||
If the provided cost is not within the valid range [bcrypt.MinCost, bcrypt.MaxCost],
|
||||
the default value (defaultBcryptCost) will be used instead.
|
||||
Note: Higher cost values can significantly degrade performance on slower systems.
|
||||
`,
|
||||
CobraFunc: func(cmd *cobra.Command) {
|
||||
cmd.Flags().StringP("plaintext", "p", "", "The plaintext password")
|
||||
cmd.Flags().StringP("algorithm", "a", "bcrypt", "Name of the hash algorithm")
|
||||
cmd.Flags().Int("bcrypt-cost", defaultBcryptCost, "Bcrypt hashing cost (only used with 'bcrypt' algorithm)")
|
||||
cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdHashPassword)
|
||||
},
|
||||
})
|
||||
@ -57,6 +64,7 @@ func cmdHashPassword(fs caddycmd.Flags) (int, error) {
|
||||
|
||||
algorithm := fs.String("algorithm")
|
||||
plaintext := []byte(fs.String("plaintext"))
|
||||
bcryptCost := fs.Int("bcrypt-cost")
|
||||
|
||||
if len(plaintext) == 0 {
|
||||
fd := int(os.Stdin.Fd())
|
||||
@ -108,7 +116,7 @@ func cmdHashPassword(fs caddycmd.Flags) (int, error) {
|
||||
var hashString string
|
||||
switch algorithm {
|
||||
case "bcrypt":
|
||||
hash, err = BcryptHash{}.Hash(plaintext)
|
||||
hash, err = BcryptHash{cost: bcryptCost}.Hash(plaintext)
|
||||
hashString = string(hash)
|
||||
default:
|
||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("unrecognized hash algorithm: %s", algorithm)
|
||||
|
@ -15,6 +15,8 @@
|
||||
package caddyauth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
@ -24,8 +26,15 @@ func init() {
|
||||
caddy.RegisterModule(BcryptHash{})
|
||||
}
|
||||
|
||||
// defaultBcryptCost cost 14 strikes a solid balance between security, usability, and hardware performance
|
||||
const defaultBcryptCost = 14
|
||||
|
||||
// BcryptHash implements the bcrypt hash.
|
||||
type BcryptHash struct{}
|
||||
type BcryptHash struct {
|
||||
// cost is the bcrypt hashing difficulty factor (work factor).
|
||||
// Higher values increase computation time and security.
|
||||
cost int
|
||||
}
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
func (BcryptHash) CaddyModule() caddy.ModuleInfo {
|
||||
@ -38,7 +47,7 @@ func (BcryptHash) CaddyModule() caddy.ModuleInfo {
|
||||
// Compare compares passwords.
|
||||
func (BcryptHash) Compare(hashed, plaintext []byte) (bool, error) {
|
||||
err := bcrypt.CompareHashAndPassword(hashed, plaintext)
|
||||
if err == bcrypt.ErrMismatchedHashAndPassword {
|
||||
if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
|
||||
return false, nil
|
||||
}
|
||||
if err != nil {
|
||||
@ -48,8 +57,13 @@ func (BcryptHash) Compare(hashed, plaintext []byte) (bool, error) {
|
||||
}
|
||||
|
||||
// Hash hashes plaintext using a random salt.
|
||||
func (BcryptHash) Hash(plaintext []byte) ([]byte, error) {
|
||||
return bcrypt.GenerateFromPassword(plaintext, 14)
|
||||
func (b BcryptHash) Hash(plaintext []byte) ([]byte, error) {
|
||||
cost := b.cost
|
||||
if cost < bcrypt.MinCost || cost > bcrypt.MaxCost {
|
||||
cost = defaultBcryptCost
|
||||
}
|
||||
|
||||
return bcrypt.GenerateFromPassword(plaintext, cost)
|
||||
}
|
||||
|
||||
// FakeHash returns a fake hash.
|
||||
|
@ -122,7 +122,6 @@ func TestPreferOrder(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
|
Loading…
x
Reference in New Issue
Block a user