golang/go · error
crypto/sha1: invalid hash state identifier
Error message
crypto/sha1: invalid hash state identifier
What it means
Returned by sha1Hash.UnmarshalBinary in the BoringCrypto SHA-1 backend when the marshalled blob does not begin with the magic bytes "sha\x01". This is the Go encoding.BinaryUnmarshalser contract used by hash.Hash; the magic identifies which algorithm/version produced the state so it cannot be loaded into the wrong hasher.
Source
Thrown at src/crypto/internal/boring/sha.go:182
}
func (h *sha1Hash) AppendBinary(b []byte) ([]byte, error) {
d := (*sha1Ctx)(unsafe.Pointer(&h.ctx))
b = append(b, sha1Magic...)
b = byteorder.BEAppendUint32(b, d.h[0])
b = byteorder.BEAppendUint32(b, d.h[1])
b = byteorder.BEAppendUint32(b, d.h[2])
b = byteorder.BEAppendUint32(b, d.h[3])
b = byteorder.BEAppendUint32(b, d.h[4])
b = append(b, d.x[:d.nx]...)
b = append(b, make([]byte, len(d.x)-int(d.nx))...)
b = byteorder.BEAppendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
return b, nil
}
func (h *sha1Hash) UnmarshalBinary(b []byte) error {
if len(b) < len(sha1Magic) || string(b[:len(sha1Magic)]) != sha1Magic {
return errors.New("crypto/sha1: invalid hash state identifier")
}
if len(b) != sha1MarshaledSize {
return errors.New("crypto/sha1: invalid hash state size")
}
d := (*sha1Ctx)(unsafe.Pointer(&h.ctx))
b = b[len(sha1Magic):]
b, d.h[0] = consumeUint32(b)
b, d.h[1] = consumeUint32(b)
b, d.h[2] = consumeUint32(b)
b, d.h[3] = consumeUint32(b)
b, d.h[4] = consumeUint32(b)
b = b[copy(d.x[:], b):]
b, n := consumeUint64(b)
d.nl = uint32(n << 3)
d.nh = uint32(n >> 29)
d.nx = uint32(n) % 64
return nil
}View on GitHub (pinned to b6b368adc5)
Solutions
- Confirm the blob was produced by MarshalBinary on the same SHA-1 implementation (same BoringCrypto setting) in the same Go version.
- Use sha1.New() fresh and re-hash the data instead of round-tripping state across builds/versions.
- Validate the magic prefix ("sha\x01") and length before calling UnmarshalBinary.
Example fix
// before h := sha1.New() h.(encoding.BinaryUnmarshalser).UnmarshalBinary(stateFromOtherBuild) // after h := sha1.New() h.Write(data) // recompute instead of cross-loading state
Defensive patterns
Strategy: validation
Validate before calling
func isValidSHA1State(state []byte) bool {
const magic = "sha\x01"
return len(state) >= len(magic) && string(state[:len(magic)]) == magic
}
// call before h.(encoding.BinaryUnmarshalser).UnmarshalBinary(state) Type guard
// n/a
Try / catch
if err := h.(encoding.BinaryUnmarshalser).UnmarshalBinary(state); err != nil {
// treat as unrecoverable; recompute the hash from source data
} Prevention
- Never persist hash internal state across Go versions or build configs.
- Round-trip state only within the same process lifetime.
- Re-hash the original data when in doubt.
When it happens
Trigger: Calling h.(encoding.BinaryUnmarshalser).UnmarshalBinary(state) on a sha1.New() hash with state bytes that do not start with "sha\x01", are empty, or were produced by a different hash (e.g. sha256.MarshalBinary output) or a non-BoringCrypto sha1 implementation.
Common situations: Cross-build portability: state marshalled by the standard (non-Boring) crypto/sha1 uses a different magic and cannot be unmarshalled by the BoringCrypto build, or vice versa. Also triggered by truncation, corruption, or feeding a SHA-256/512 blob into a SHA-1 hasher.
Related errors
- crypto/sha1: invalid hash state size
- crypto/sha256: invalid hash state identifier
- crypto/sha512: invalid hash state identifier
- crypto/rsa: unsupported hash function
- crypto/rsa: unsupported hash function: %d
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/19c691446491bd05.
Report an issue: GitHub.