@marcel91200 / caddy Mirror · read-only / commits / 49dac61b
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 22:15 UTC

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>

GreyXor committed Aug 11, 2025 at 13:26 UTC 49dac61b078a704b3e98566134c108d6def19450
4 files changed +30 -8
modules/caddyhttp/caddyauth/caddyauth.go
+2 -1
@@ -60,7 +60,8 @@ func (Authentication) CaddyModule() caddy.ModuleInfo {
60 }
61 }
62
63 -// Provision sets up a.
63 +// Provision sets up an Authentication module by initializing its logger,
64 +// loading and registering all configured authentication providers.
65 func (a *Authentication) Provision(ctx caddy.Context) error {
66 a.logger = ctx.Logger()
67 a.Providers = make(map[string]Authenticator)
modules/caddyhttp/caddyauth/command.go
+10 -2
@@ -32,7 +32,7 @@ import (
32 func init() {
33 caddycmd.RegisterCommand(caddycmd.Command{
34 Name: "hash-password",
35 - Usage: "[--plaintext <password>] [--algorithm <name>]",
35 + Usage: "[--plaintext <password>] [--algorithm <name>] [--cost <difficulty>]",
36 Short: "Hashes a password and writes base64",
37 Long: `
38 Convenient way to hash a plaintext password. The resulting
@@ -43,10 +43,17 @@ Caddy is attached to a controlling tty, the plaintext will
43 not be echoed.
44
45 --algorithm currently only supports 'bcrypt', and is the default.
46 +
47 +--cost sets the bcrypt hashing difficulty.
48 +Higher values increase security by making the hash computation slower and more CPU-intensive.
49 +If the provided cost is not within the valid range [bcrypt.MinCost, bcrypt.MaxCost],
50 +the default value (defaultBcryptCost) will be used instead.
51 +Note: Higher cost values can significantly degrade performance on slower systems.
52 `,
53 CobraFunc: func(cmd *cobra.Command) {
54 cmd.Flags().StringP("plaintext", "p", "", "The plaintext password")
55 cmd.Flags().StringP("algorithm", "a", "bcrypt", "Name of the hash algorithm")
56 + cmd.Flags().Int("bcrypt-cost", defaultBcryptCost, "Bcrypt hashing cost (only used with 'bcrypt' algorithm)")
57 cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdHashPassword)
58 },
59 })
@@ -57,6 +64,7 @@ func cmdHashPassword(fs caddycmd.Flags) (int, error) {
64
65 algorithm := fs.String("algorithm")
66 plaintext := []byte(fs.String("plaintext"))
67 + bcryptCost := fs.Int("bcrypt-cost")
68
69 if len(plaintext) == 0 {
70 fd := int(os.Stdin.Fd())
@@ -108,7 +116,7 @@ func cmdHashPassword(fs caddycmd.Flags) (int, error) {
116 var hashString string
117 switch algorithm {
118 case "bcrypt":
111 - hash, err = BcryptHash{}.Hash(plaintext)
119 + hash, err = BcryptHash{cost: bcryptCost}.Hash(plaintext)
120 hashString = string(hash)
121 default:
122 return caddy.ExitCodeFailedStartup, fmt.Errorf("unrecognized hash algorithm: %s", algorithm)
modules/caddyhttp/caddyauth/hashes.go
+18 -4
@@ -15,6 +15,8 @@
15 package caddyauth
16
17 import (
18 + "errors"
19 +
20 "golang.org/x/crypto/bcrypt"
21
22 "github.com/caddyserver/caddy/v2"
@@ -24,8 +26,15 @@ func init() {
26 caddy.RegisterModule(BcryptHash{})
27 }
28
29 +// defaultBcryptCost cost 14 strikes a solid balance between security, usability, and hardware performance
30 +const defaultBcryptCost = 14
31 +
32 // BcryptHash implements the bcrypt hash.
28 -type BcryptHash struct{}
33 +type BcryptHash struct {
34 + // cost is the bcrypt hashing difficulty factor (work factor).
35 + // Higher values increase computation time and security.
36 + cost int
37 +}
38
39 // CaddyModule returns the Caddy module information.
40 func (BcryptHash) CaddyModule() caddy.ModuleInfo {
@@ -38,7 +47,7 @@ func (BcryptHash) CaddyModule() caddy.ModuleInfo {
47 // Compare compares passwords.
48 func (BcryptHash) Compare(hashed, plaintext []byte) (bool, error) {
49 err := bcrypt.CompareHashAndPassword(hashed, plaintext)
41 - if err == bcrypt.ErrMismatchedHashAndPassword {
50 + if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
51 return false, nil
52 }
53 if err != nil {
@@ -48,8 +57,13 @@ func (BcryptHash) Compare(hashed, plaintext []byte) (bool, error) {
57 }
58
59 // Hash hashes plaintext using a random salt.
51 -func (BcryptHash) Hash(plaintext []byte) ([]byte, error) {
52 - return bcrypt.GenerateFromPassword(plaintext, 14)
60 +func (b BcryptHash) Hash(plaintext []byte) ([]byte, error) {
61 + cost := b.cost
62 + if cost < bcrypt.MinCost || cost > bcrypt.MaxCost {
63 + cost = defaultBcryptCost
64 + }
65 +
66 + return bcrypt.GenerateFromPassword(plaintext, cost)
67 }
68
69 // FakeHash returns a fake hash.
modules/caddyhttp/encode/encode_test.go
-1
@@ -122,7 +122,6 @@ func TestPreferOrder(t *testing.T) {
122 }
123 }
124
125 -
125 func TestValidate(t *testing.T) {
126 type testCase struct {
127 name string