Skip to content

Commit

Permalink
fix SHA.Write for large inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
qmuntal committed Mar 21, 2022
1 parent 7c7aef6 commit 7b9094c
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 7 deletions.
10 changes: 10 additions & 0 deletions cng/cng.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ import (
"github.com/microsoft/go-crypto-winnative/internal/bcrypt"
)

// ulong casts v into a Win32 ULONG, which is a 32-bit unsigned integer.
// If the cast would overflow, v is truncated to the fit into an uint32.
func ulong(v int) (ul uint32, truncated bool) {
const maxULong = 1<<32 - 1
if v > maxULong {
return maxULong, true
}
return uint32(v), false
}

type algCacheEntry struct {
id string
flags uint32
Expand Down
14 changes: 7 additions & 7 deletions cng/sha.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,17 @@ func (h *shaXHash) Reset() {
}

func (h *shaXHash) Write(p []byte) (int, error) {
// BCryptHashData only accepts 2**32-1 bytes at a time, so truncate.
inputLen := uint32(len(p))
if inputLen == 0 {
return 0, nil
inputLen, truncated := ulong(len(p))
err := bcrypt.HashData(h.ctx, p[:inputLen], 0)
if err == nil && truncated {
err = bcrypt.HashData(h.ctx, p[inputLen:], 0)
}
err := bcrypt.HashData(h.ctx, p, 0)
if err != nil {
return 0, err
// hash.Hash interface mandates Write should never return an error.
panic(err)
}
runtime.KeepAlive(h)
return int(inputLen), nil
return len(p), nil
}

func (h *shaXHash) Size() int {
Expand Down
20 changes: 20 additions & 0 deletions cng/sha_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,23 @@ func TestSha(t *testing.T) {
})
}
}

func TestSha256_Large(t *testing.T) {
msg := make([]byte, 1<<32)
h := NewSHA256()
initSum := h.Sum(nil)
n, err := h.Write(msg)
if err != nil {
t.Fatal(err)
}
if n != len(msg) {
t.Errorf("got: %d, want: %d", n, len(msg))
}
sum := h.Sum(nil)
if size := h.Size(); len(sum) != size {
t.Errorf("got: %d, want: %d", len(sum), size)
}
if bytes.Equal(sum, initSum) {
t.Error("Write didn't change internal hash state")
}
}

0 comments on commit 7b9094c

Please sign in to comment.