@marcel91200 / caddy Mirror · read-only / commits / 13a4ec75
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, 19:45 UTC

basicauth: Implement argon2id (#7186)

* feat: add argon2id hash-password command * feat: ardon2id owasp safe value * feat: add argon2id compare method * chore: fmt argon2id * docs: more argon2id docs * chore: upgrade x/crypto dep * revert: remove golangci * refactor: argon2id decode * chore: update deps * refactor: simplify argon2id compare return * chore: upgrade dependencies * chore: upgrade dependencies

GreyXor committed Oct 7, 2025 at 01:27 UTC 13a4ec7597f8e9ebe105b0ee89102ba521f21173
6 files changed +303 -57
go.mod
+14 -14
@@ -37,12 +37,12 @@ require (
37 go.uber.org/automaxprocs v1.6.0
38 go.uber.org/zap v1.27.0
39 go.uber.org/zap/exp v0.3.0
40 - golang.org/x/crypto v0.41.0
41 - golang.org/x/crypto/x509roots/fallback v0.0.0-20250305170421-49bf5b80c810
42 - golang.org/x/net v0.43.0
43 - golang.org/x/sync v0.16.0
44 - golang.org/x/term v0.34.0
45 - golang.org/x/time v0.12.0
40 + golang.org/x/crypto v0.42.0
41 + golang.org/x/crypto/x509roots/fallback v0.0.0-20250927194341-2beaa59a3c99
42 + golang.org/x/net v0.44.0
43 + golang.org/x/sync v0.17.0
44 + golang.org/x/term v0.35.0
45 + golang.org/x/time v0.13.0
46 gopkg.in/natefinch/lumberjack.v2 v2.2.1
47 gopkg.in/yaml.v3 v3.0.1
48 )
@@ -90,11 +90,11 @@ require (
90 go.opentelemetry.io/contrib/propagators/jaeger v1.38.0 // indirect
91 go.opentelemetry.io/contrib/propagators/ot v1.38.0 // indirect
92 go.uber.org/mock v0.5.2 // indirect
93 - golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
93 + golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 // indirect
94 golang.org/x/oauth2 v0.30.0 // indirect
95 google.golang.org/api v0.247.0 // indirect
96 google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
97 - google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
97 + google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect
98 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect
99 )
100
@@ -153,11 +153,11 @@ require (
153 go.opentelemetry.io/proto/otlp v1.7.1 // indirect
154 go.step.sm/crypto v0.70.0
155 go.uber.org/multierr v1.11.0 // indirect
156 - golang.org/x/mod v0.26.0 // indirect
157 - golang.org/x/sys v0.35.0
158 - golang.org/x/text v0.28.0 // indirect
159 - golang.org/x/tools v0.35.0 // indirect
160 - google.golang.org/grpc v1.75.0 // indirect
161 - google.golang.org/protobuf v1.36.8 // indirect
156 + golang.org/x/mod v0.27.0 // indirect
157 + golang.org/x/sys v0.36.0
158 + golang.org/x/text v0.29.0 // indirect
159 + golang.org/x/tools v0.36.0 // indirect
160 + google.golang.org/grpc v1.75.1 // indirect
161 + google.golang.org/protobuf v1.36.10 // indirect
162 howett.net/plist v1.0.0 // indirect
163 )
go.sum
+28 -28
@@ -502,13 +502,13 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
502 golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
503 golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
504 golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
505 -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
506 -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
507 -golang.org/x/crypto/x509roots/fallback v0.0.0-20250305170421-49bf5b80c810 h1:V5+zy0jmgNYmK1uW/sPpBw8ioFvalrhaUrYWmu1Fpe4=
508 -golang.org/x/crypto/x509roots/fallback v0.0.0-20250305170421-49bf5b80c810/go.mod h1:lxN5T34bK4Z/i6cMaU7frUU57VkDXFD4Kamfl/cp9oU=
505 +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
506 +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
507 +golang.org/x/crypto/x509roots/fallback v0.0.0-20250927194341-2beaa59a3c99 h1:CH0o4/bZX6KIUCjjgjmtNtfM/kXSkTYlzTOB9vZF45g=
508 +golang.org/x/crypto/x509roots/fallback v0.0.0-20250927194341-2beaa59a3c99/go.mod h1:MEIPiCnxvQEjA4astfaKItNwEVZA5Ki+3+nyGbJ5N18=
509 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
510 -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
511 -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
510 +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE=
511 +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
512 golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
513 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
514 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -517,8 +517,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
517 golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
518 golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
519 golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
520 -golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
521 -golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
520 +golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
521 +golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
522 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
523 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
524 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -535,8 +535,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
535 golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
536 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
537 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
538 -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
539 -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
538 +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
539 +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
540 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
541 golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
542 golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -556,8 +556,8 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
556 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
557 golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
558 golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
559 -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
560 -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
559 +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
560 +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
561 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
562 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
563 golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -582,8 +582,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
582 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
583 golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
584 golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
585 -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
586 -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
585 +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
586 +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
587 golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
588 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
589 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -594,8 +594,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
594 golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
595 golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
596 golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
597 -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
598 -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
597 +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
598 +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
599 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
600 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
601 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -607,12 +607,12 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
607 golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
608 golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
609 golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
610 -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
611 -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
610 +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
611 +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
612 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
613 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
614 -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
615 -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
614 +golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
615 +golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
616 golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
617 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
618 golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -623,8 +623,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
623 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
624 golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
625 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
626 -golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
627 -golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
626 +golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
627 +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
628 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
629 gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
630 gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
@@ -646,18 +646,18 @@ google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuO
646 google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
647 google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
648 google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
649 -google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
650 -google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
649 +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk=
650 +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ=
651 google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
652 google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
653 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
654 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
655 -google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
656 -google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
655 +google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
656 +google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
657 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
658 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
659 -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
660 -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
659 +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
660 +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
661 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
662 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
663 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
modules/caddyhttp/caddyauth/argon2id.go new
+188
@@ -0,0 +1,188 @@
1 +// Copyright 2015 Matthew Holt and The Caddy Authors
2 +//
3 +// Licensed under the Apache License, Version 2.0 (the "License");
4 +// you may not use this file except in compliance with the License.
5 +// You may obtain a copy of the License at
6 +//
7 +// http://www.apache.org/licenses/LICENSE-2.0
8 +//
9 +// Unless required by applicable law or agreed to in writing, software
10 +// distributed under the License is distributed on an "AS IS" BASIS,
11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 +// See the License for the specific language governing permissions and
13 +// limitations under the License.
14 +
15 +package caddyauth
16 +
17 +import (
18 + "crypto/rand"
19 + "crypto/subtle"
20 + "encoding/base64"
21 + "fmt"
22 + "strconv"
23 + "strings"
24 +
25 + "golang.org/x/crypto/argon2"
26 +
27 + "github.com/caddyserver/caddy/v2"
28 +)
29 +
30 +func init() {
31 + caddy.RegisterModule(Argon2idHash{})
32 +}
33 +
34 +const (
35 + argon2idName = "argon2id"
36 + defaultArgon2idTime = 1
37 + defaultArgon2idMemory = 46 * 1024
38 + defaultArgon2idThreads = 1
39 + defaultArgon2idKeylen = 32
40 + defaultSaltLength = 16
41 +)
42 +
43 +// Argon2idHash implements the Argon2id password hashing.
44 +type Argon2idHash struct {
45 + salt []byte
46 + time uint32
47 + memory uint32
48 + threads uint8
49 + keyLen uint32
50 +}
51 +
52 +// CaddyModule returns the Caddy module information.
53 +func (Argon2idHash) CaddyModule() caddy.ModuleInfo {
54 + return caddy.ModuleInfo{
55 + ID: "http.authentication.hashes.argon2id",
56 + New: func() caddy.Module { return new(Argon2idHash) },
57 + }
58 +}
59 +
60 +// Compare checks if the plaintext password matches the given Argon2id hash.
61 +func (Argon2idHash) Compare(hashed, plaintext []byte) (bool, error) {
62 + argHash, storedKey, err := DecodeHash(hashed)
63 + if err != nil {
64 + return false, err
65 + }
66 +
67 + computedKey := argon2.IDKey(
68 + plaintext,
69 + argHash.salt,
70 + argHash.time,
71 + argHash.memory,
72 + argHash.threads,
73 + argHash.keyLen,
74 + )
75 +
76 + return subtle.ConstantTimeCompare(storedKey, computedKey) == 1, nil
77 +}
78 +
79 +// Hash generates an Argon2id hash of the given plaintext using the configured parameters and salt.
80 +func (b Argon2idHash) Hash(plaintext []byte) ([]byte, error) {
81 + if b.salt == nil {
82 + s, err := generateSalt(defaultSaltLength)
83 + if err != nil {
84 + return nil, err
85 + }
86 + b.salt = s
87 + }
88 +
89 + key := argon2.IDKey(
90 + plaintext,
91 + b.salt,
92 + b.time,
93 + b.memory,
94 + b.threads,
95 + b.keyLen,
96 + )
97 +
98 + hash := fmt.Sprintf(
99 + "$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s",
100 + argon2.Version,
101 + b.memory,
102 + b.time,
103 + b.threads,
104 + base64.RawStdEncoding.EncodeToString(b.salt),
105 + base64.RawStdEncoding.EncodeToString(key),
106 + )
107 +
108 + return []byte(hash), nil
109 +}
110 +
111 +// DecodeHash parses an Argon2id PHC string into an Argon2idHash struct and returns the struct along with the derived key.
112 +func DecodeHash(hash []byte) (*Argon2idHash, []byte, error) {
113 + parts := strings.Split(string(hash), "$")
114 + if len(parts) != 6 {
115 + return nil, nil, fmt.Errorf("invalid hash format")
116 + }
117 +
118 + if parts[1] != argon2idName {
119 + return nil, nil, fmt.Errorf("unsupported variant: %s", parts[1])
120 + }
121 +
122 + version, err := strconv.Atoi(strings.TrimPrefix(parts[2], "v="))
123 + if err != nil {
124 + return nil, nil, fmt.Errorf("invalid version: %w", err)
125 + }
126 + if version != argon2.Version {
127 + return nil, nil, fmt.Errorf("incompatible version: %d", version)
128 + }
129 +
130 + params := strings.Split(parts[3], ",")
131 + if len(params) != 3 {
132 + return nil, nil, fmt.Errorf("invalid parameters")
133 + }
134 +
135 + mem, err := strconv.ParseUint(strings.TrimPrefix(params[0], "m="), 10, 32)
136 + if err != nil {
137 + return nil, nil, fmt.Errorf("invalid memory parameter: %w", err)
138 + }
139 +
140 + iter, err := strconv.ParseUint(strings.TrimPrefix(params[1], "t="), 10, 32)
141 + if err != nil {
142 + return nil, nil, fmt.Errorf("invalid iterations parameter: %w", err)
143 + }
144 +
145 + threads, err := strconv.ParseUint(strings.TrimPrefix(params[2], "p="), 10, 8)
146 + if err != nil {
147 + return nil, nil, fmt.Errorf("invalid parallelism parameter: %w", err)
148 + }
149 +
150 + salt, err := base64.RawStdEncoding.Strict().DecodeString(parts[4])
151 + if err != nil {
152 + return nil, nil, fmt.Errorf("decode salt: %w", err)
153 + }
154 +
155 + key, err := base64.RawStdEncoding.Strict().DecodeString(parts[5])
156 + if err != nil {
157 + return nil, nil, fmt.Errorf("decode key: %w", err)
158 + }
159 +
160 + return &Argon2idHash{
161 + salt: salt,
162 + time: uint32(iter),
163 + memory: uint32(mem),
164 + threads: uint8(threads),
165 + keyLen: uint32(len(key)),
166 + }, key, nil
167 +}
168 +
169 +// FakeHash returns a constant fake hash for timing attacks mitigation.
170 +func (Argon2idHash) FakeHash() []byte {
171 + // hashed with the following command:
172 + // caddy hash-password --plaintext "antitiming" --algorithm "argon2id"
173 + return []byte("$argon2id$v=19$m=47104,t=1,p=1$P2nzckEdTZ3bxCiBCkRTyA$xQL3Z32eo5jKl7u5tcIsnEKObYiyNZQQf5/4sAau6Pg")
174 +}
175 +
176 +// Interface guards
177 +var (
178 + _ Comparer = (*Argon2idHash)(nil)
179 + _ Hasher = (*Argon2idHash)(nil)
180 +)
181 +
182 +func generateSalt(length int) ([]byte, error) {
183 + salt := make([]byte, length)
184 + if _, err := rand.Read(salt); err != nil {
185 + return nil, fmt.Errorf("failed to generate salt: %w", err)
186 + }
187 + return salt, nil
188 +}
modules/caddyhttp/caddyauth/bcrypt.go renamed
+4 -1
@@ -27,7 +27,10 @@ func init() {
27 }
28
29 // defaultBcryptCost cost 14 strikes a solid balance between security, usability, and hardware performance
30 -const defaultBcryptCost = 14
30 +const (
31 + bcryptName = "bcrypt"
32 + defaultBcryptCost = 14
33 +)
34
35 // BcryptHash implements the bcrypt hash.
36 type BcryptHash struct {
modules/caddyhttp/caddyauth/caddyfile.go
+4 -2
@@ -51,7 +51,7 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
51 var hashName string
52 switch len(args) {
53 case 0:
54 - hashName = "bcrypt"
54 + hashName = bcryptName
55 case 1:
56 hashName = args[0]
57 case 2:
@@ -62,8 +62,10 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
62 }
63
64 switch hashName {
65 - case "bcrypt":
65 + case bcryptName:
66 cmp = BcryptHash{}
67 + case argon2idName:
68 + cmp = Argon2idHash{}
69 default:
70 return nil, h.Errf("unrecognized hash algorithm: %s", hashName)
71 }
modules/caddyhttp/caddyauth/command.go
+65 -12
@@ -32,28 +32,55 @@ import (
32 func init() {
33 caddycmd.RegisterCommand(caddycmd.Command{
34 Name: "hash-password",
35 - Usage: "[--plaintext <password>] [--algorithm <name>] [--bcrypt-cost <difficulty>]",
35 + Usage: "[--plaintext <password>] [--algorithm <argon2id|bcrypt>] [--bcrypt-cost <difficulty>] [--argon2id-time <iterations>] [--argon2id-memory <KiB>] [--argon2id-threads <n>] [--argon2id-keylen <bytes>]",
36 Short: "Hashes a password and writes base64",
37 Long: `
38 Convenient way to hash a plaintext password. The resulting
39 hash is written to stdout as a base64 string.
40
41 ---plaintext, when omitted, will be read from stdin. If
42 -Caddy is attached to a controlling tty, the plaintext will
43 -not be echoed.
41 +--plaintext
42 + The password to hash. If omitted, it will be read from stdin.
43 + If Caddy is attached to a controlling TTY, the input will not be echoed.
44
45 ---algorithm currently only supports 'bcrypt', and is the default.
45 +--algorithm
46 + Selects the hashing algorithm. Valid options are:
47 + * 'argon2id' (recommended for modern security)
48 + * 'bcrypt' (legacy, slower, configurable cost)
49
47 ---bcrypt-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.
50 +bcrypt-specific parameters:
51 +
52 +--bcrypt-cost
53 + Sets the bcrypt hashing difficulty. Higher values increase security by
54 + making the hash computation slower and more CPU-intensive.
55 + Must be within the valid range [bcrypt.MinCost, bcrypt.MaxCost].
56 + If omitted or invalid, the default cost is used.
57 +
58 +Argon2id-specific parameters:
59 +
60 +--argon2id-time
61 + Number of iterations to perform. Increasing this makes
62 + hashing slower and more resistant to brute-force attacks.
63 +
64 +--argon2id-memory
65 + Amount of memory to use during hashing.
66 + Larger values increase resistance to GPU/ASIC attacks.
67 +
68 +--argon2id-threads
69 + Number of CPU threads to use. Increase for faster hashing
70 + on multi-core systems.
71 +
72 +--argon2id-keylen
73 + Length of the resulting hash in bytes. Longer keys increase
74 + security but slightly increase storage size.
75 `,
76 CobraFunc: func(cmd *cobra.Command) {
77 cmd.Flags().StringP("plaintext", "p", "", "The plaintext password")
55 - cmd.Flags().StringP("algorithm", "a", "bcrypt", "Name of the hash algorithm")
78 + cmd.Flags().StringP("algorithm", "a", bcryptName, "Name of the hash algorithm")
79 cmd.Flags().Int("bcrypt-cost", defaultBcryptCost, "Bcrypt hashing cost (only used with 'bcrypt' algorithm)")
80 + cmd.Flags().Uint32("argon2id-time", defaultArgon2idTime, "Number of iterations for Argon2id hashing. Increasing this makes the hash slower and more resistant to brute-force attacks.")
81 + cmd.Flags().Uint32("argon2id-memory", defaultArgon2idMemory, "Memory to use in KiB for Argon2id hashing. Larger values increase resistance to GPU/ASIC attacks.")
82 + cmd.Flags().Uint8("argon2id-threads", defaultArgon2idThreads, "Number of CPU threads to use for Argon2id hashing. Increase for faster hashing on multi-core systems.")
83 + cmd.Flags().Uint32("argon2id-keylen", defaultArgon2idKeylen, "Length of the resulting Argon2id hash in bytes. Longer hashes increase security but slightly increase storage size.")
84 cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdHashPassword)
85 },
86 })
@@ -115,8 +142,34 @@ func cmdHashPassword(fs caddycmd.Flags) (int, error) {
142 var hash []byte
143 var hashString string
144 switch algorithm {
118 - case "bcrypt":
145 + case bcryptName:
146 hash, err = BcryptHash{cost: bcryptCost}.Hash(plaintext)
147 + hashString = string(hash)
148 + case argon2idName:
149 + time, err := fs.GetUint32("argon2id-time")
150 + if err != nil {
151 + return caddy.ExitCodeFailedStartup, fmt.Errorf("failed to get argon2id time parameter: %w", err)
152 + }
153 + memory, err := fs.GetUint32("argon2id-memory")
154 + if err != nil {
155 + return caddy.ExitCodeFailedStartup, fmt.Errorf("failed to get argon2id memory parameter: %w", err)
156 + }
157 + threads, err := fs.GetUint8("argon2id-threads")
158 + if err != nil {
159 + return caddy.ExitCodeFailedStartup, fmt.Errorf("failed to get argon2id threads parameter: %w", err)
160 + }
161 + keyLen, err := fs.GetUint32("argon2id-keylen")
162 + if err != nil {
163 + return caddy.ExitCodeFailedStartup, fmt.Errorf("failed to get argon2id keylen parameter: %w", err)
164 + }
165 +
166 + hash, _ = Argon2idHash{
167 + time: time,
168 + memory: memory,
169 + threads: threads,
170 + keyLen: keyLen,
171 + }.Hash(plaintext)
172 +
173 hashString = string(hash)
174 default:
175 return caddy.ExitCodeFailedStartup, fmt.Errorf("unrecognized hash algorithm: %s", algorithm)