Parcourir la source

x/crypto/pkcs12: deal with short byte array in PBKDF

A bug in the PBKDF implementation in the pkcs12 package caused certain
inputs to produce the wrong output. In step 6C, we treat Ij as a big.Int
of v bytes and compute Ij + B + 1. The resulting big.Int can have
leading zero bytes, such that Ij.Bytes() produces a byte array that is
smaller than v bytes. In this case we must zero-pad the output to make
Ijb properly sized.

Change-Id: I6e672e6f6bbbd5bea419355d318db289731bb174
Reviewed-on: https://go-review.googlesource.com/16520
Reviewed-by: Adam Langley <agl@golang.org>
Cedric Staub il y a 10 ans
Parent
commit
575fdbe86e
2 fichiers modifiés avec 28 ajouts et 1 suppressions
  1. 15 0
      pkcs12/pbkdf.go
  2. 13 1
      pkcs12/pbkdf_test.go

+ 15 - 0
pkcs12/pbkdf.go

@@ -103,6 +103,7 @@ func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID
 
 	//    6.  For i=1, 2, ..., c, do the following:
 	A := make([]byte, c*20)
+	var IjBuf []byte
 	for i := 0; i < c; i++ {
 		//        A.  Set A2=H^r(D||I). (i.e., the r-th hash of D||1,
 		//            H(H(H(... H(D||I))))
@@ -133,9 +134,23 @@ func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID
 					Ij.Add(Ij, Bbi)
 					Ij.Add(Ij, one)
 					Ijb := Ij.Bytes()
+					// We expect Ijb to be exactly v bytes,
+					// if it is longer or shorter we must
+					// adjust it accordingly.
 					if len(Ijb) > v {
 						Ijb = Ijb[len(Ijb)-v:]
 					}
+					if len(Ijb) < v {
+						if IjBuf == nil {
+							IjBuf = make([]byte, v)
+						}
+						bytesShort := v - len(Ijb)
+						for i := 0; i < bytesShort; i++ {
+							IjBuf[i] = 0
+						}
+						copy(IjBuf[bytesShort:], Ijb)
+						Ijb = IjBuf
+					}
 					copy(I[j*v:(j+1)*v], Ijb)
 				}
 			}

+ 13 - 1
pkcs12/pbkdf_test.go

@@ -17,6 +17,18 @@ func TestThatPBKDFWorksCorrectlyForLongKeys(t *testing.T) {
 	key := cipherInfo.deriveKey(salt, password, 2048)
 
 	if expected := []byte("\x7c\xd9\xfd\x3e\x2b\x3b\xe7\x69\x1a\x44\xe3\xbe\xf0\xf9\xea\x0f\xb9\xb8\x97\xd4\xe3\x25\xd9\xd1"); bytes.Compare(key, expected) != 0 {
-		t.Fatalf("expected key '%x', but found '%x'", key, expected)
+		t.Fatalf("expected key '%x', but found '%x'", expected, key)
+	}
+}
+
+func TestThatPBKDFHandlesLeadingZeros(t *testing.T) {
+	// This test triggers a case where I_j (in step 6C) ends up with leading zero
+	// byte, meaning that len(Ijb) < v (leading zeros get stripped by big.Int).
+	// This was previously causing bug whereby certain inputs would break the
+	// derivation and produce the wrong output.
+	key := pbkdf(sha1Sum, 20, 64, []byte("\xf3\x7e\x05\xb5\x18\x32\x4b\x4b"), []byte("\x00\x00"), 2048, 1, 24)
+	expected := []byte("\x00\xf7\x59\xff\x47\xd1\x4d\xd0\x36\x65\xd5\x94\x3c\xb3\xc4\xa3\x9a\x25\x55\xc0\x2a\xed\x66\xe1")
+	if bytes.Compare(key, expected) != 0 {
+		t.Fatalf("expected key '%x', but found '%x'", expected, key)
 	}
 }