-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
What version of Go are you using (go version
)?
Tested with golang/x/crypto: golang/crypto@61a8779
and
go version go1.13.4 linux/amd64
Does this issue reproduce with the latest release?
It repros with the latest golang/x/crypto yes.
What operating system and processor architecture are you using (go env
)?
go env
Output
GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/home/ncw/.cache/go-build" GOENV="/home/ncw/.config/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/home/ncw/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/opt/go/go1.13" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/opt/go/go1.13/pkg/tool/linux_amd64" GCCGO="gccgo" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build519269826=/tmp/go-build -gno-record-gcc-switches"
What did you do?
I've discovered that bcrypt.CompareHashAndPassword
only reads the first 72 characters of the password input. You can try this for yourself with the program below.
This means that any characters after the 72 byte mark are ignored when comparing passwords.
I was expecting to receive an error from CompareHashAndPassword
but instead it said the clearly non-matching passwords matched.
This behavior of bcrypt is fairly well known: https://security.stackexchange.com/questions/39849/does-bcrypt-have-a-maximum-password-length
However I found it surprising that the CompareHashAndPassword
didn't give an error. The documentation doesn't mention any 72 character limit either.
See: https://play.golang.org/p/igM0KIsFhDD
package main
import (
"fmt"
"golang.org/x/crypto/bcrypt"
)
// check makes the hash of a password of length n then
// sees if CompareHashAndPassword gives the correct answer for a password of one bigger
func check(n int) {
pw := make([]byte, n)
for i := range pw {
pw[i] = 'x'
}
pwHash, err := bcrypt.GenerateFromPassword(pw, bcrypt.MinCost)
if err != nil {
panic(err)
}
fmt.Printf("Made hash of password of length %d\npw=%q\n", len(pw), pw)
pw = append(pw, 'A')
fmt.Printf("Now checking against a password of length %d with the same start\npw=%q\n", len(pw), pw)
err = bcrypt.CompareHashAndPassword(pwHash, pw)
if err != nil {
fmt.Printf("OK got error: %v\n", err)
} else {
fmt.Printf("FAILED was expecting error\n")
}
fmt.Println()
}
func main() {
check(71)
check(72)
}
What did you expect to see?
I expected to see either an error being returned after comparing a 73 byte password with a 72 byte password.
Or a note in the docs that only the first 72 bytes of the password are significant.
What did you see instead?
Made hash of password of length 71
pw="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Now checking against a password of length 72 with the same start
pw="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxA"
OK got error: crypto/bcrypt: hashedPassword is not the hash of the given password
Made hash of password of length 72
pw="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Now checking against a password of length 73 with the same start
pw="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxA"
FAILED was expecting error
Cc: @FiloSottile