Limit the number of concurrent password hashing operations.
This avoids running out of memory when doing too many BCrypt operations at the same time.
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"hash"
|
"hash"
|
||||||
"net"
|
"net"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
@@ -26,6 +27,10 @@ type RawPassword struct {
|
|||||||
|
|
||||||
type Password RawPassword
|
type Password RawPassword
|
||||||
|
|
||||||
|
// limit the number of concurrent hashing operations. This avoids running
|
||||||
|
// out of memory when doing too many BCrypt hashes at the same time.
|
||||||
|
var hashSemaphore = make(chan struct{}, runtime.GOMAXPROCS(-1))
|
||||||
|
|
||||||
// constantTimeCompare compares a and b in time proportional to the length of a.
|
// constantTimeCompare compares a and b in time proportional to the length of a.
|
||||||
func constantTimeCompare(a, b string) bool {
|
func constantTimeCompare(a, b string) bool {
|
||||||
as := []byte(a)
|
as := []byte(a)
|
||||||
@@ -65,6 +70,10 @@ func (p Password) Match(pw string) (bool, error) {
|
|||||||
default:
|
default:
|
||||||
return false, errors.New("unknown hash type")
|
return false, errors.New("unknown hash type")
|
||||||
}
|
}
|
||||||
|
hashSemaphore <- struct{}{}
|
||||||
|
defer func() {
|
||||||
|
<-hashSemaphore
|
||||||
|
}()
|
||||||
theirKey := pbkdf2.Key(
|
theirKey := pbkdf2.Key(
|
||||||
[]byte(pw), salt, p.Iterations, len(key), h,
|
[]byte(pw), salt, p.Iterations, len(key), h,
|
||||||
)
|
)
|
||||||
@@ -73,6 +82,10 @@ func (p Password) Match(pw string) (bool, error) {
|
|||||||
if p.Key == nil {
|
if p.Key == nil {
|
||||||
return false, errors.New("missing key")
|
return false, errors.New("missing key")
|
||||||
}
|
}
|
||||||
|
hashSemaphore <- struct{}{}
|
||||||
|
defer func() {
|
||||||
|
<-hashSemaphore
|
||||||
|
}()
|
||||||
err := bcrypt.CompareHashAndPassword([]byte(*p.Key), []byte(pw))
|
err := bcrypt.CompareHashAndPassword([]byte(*p.Key), []byte(pw))
|
||||||
if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
|
if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user