Jelajahi Sumber

bcrypt: fix C compatibility code

The bcrypt implementation must append a zero byte to the user provided key
to be compatible to C implementations.
This will change the user provided key if the slice has enough capacity to
hold the extra zero byte.

This change always allocates a new slice for the C-compatible key.

Fixes golang/go#20425

Change-Id: I8dc4e840c29711daabdabe58d83643cc0103cedd
Reviewed-on: https://go-review.googlesource.com/43715
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Andreas Auernhammer 8 tahun lalu
induk
melakukan
6c586e17d9
2 mengubah file dengan 21 tambahan dan 3 penghapusan
  1. 4 3
      bcrypt/bcrypt.go
  2. 17 0
      bcrypt/bcrypt_test.go

+ 4 - 3
bcrypt/bcrypt.go

@@ -12,9 +12,10 @@ import (
 	"crypto/subtle"
 	"errors"
 	"fmt"
-	"golang.org/x/crypto/blowfish"
 	"io"
 	"strconv"
+
+	"golang.org/x/crypto/blowfish"
 )
 
 const (
@@ -205,7 +206,6 @@ func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) {
 }
 
 func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
-
 	csalt, err := base64Decode(salt)
 	if err != nil {
 		return nil, err
@@ -213,7 +213,8 @@ func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cip
 
 	// Bug compatibility with C bcrypt implementations. They use the trailing
 	// NULL in the key string during expansion.
-	ckey := append(key, 0)
+	// We copy the key to prevent changing the underlying array.
+	ckey := append(key[:len(key):len(key)], 0)
 
 	c, err := blowfish.NewSaltedCipher(ckey, csalt)
 	if err != nil {

+ 17 - 0
bcrypt/bcrypt_test.go

@@ -224,3 +224,20 @@ func BenchmarkGeneration(b *testing.B) {
 		GenerateFromPassword(passwd, 10)
 	}
 }
+
+// See Issue https://github.com/golang/go/issues/20425.
+func TestNoSideEffectsFromCompare(t *testing.T) {
+	source := []byte("passw0rd123456")
+	password := source[:len(source)-6]
+	token := source[len(source)-6:]
+	want := make([]byte, len(source))
+	copy(want, source)
+
+	wantHash := []byte("$2a$10$LK9XRuhNxHHCvjX3tdkRKei1QiCDUKrJRhZv7WWZPuQGRUM92rOUa")
+	_ = CompareHashAndPassword(wantHash, password)
+
+	got := bytes.Join([][]byte{password, token}, []byte(""))
+	if !bytes.Equal(got, want) {
+		t.Errorf("got=%q want=%q", got, want)
+	}
+}