{"record":{"id":"d1698a3c35ca4cf5","repo":"golang/go","slug":"crypto-sha1-invalid-hash-state-size","errorCode":null,"errorMessage":"crypto/sha1: invalid hash state size","messagePattern":"crypto/sha1: invalid hash state size","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/boring/sha.go","lineNumber":185,"sourceCode":"\td := (*sha1Ctx)(unsafe.Pointer(&h.ctx))\n\tb = append(b, sha1Magic...)\n\tb = byteorder.BEAppendUint32(b, d.h[0])\n\tb = byteorder.BEAppendUint32(b, d.h[1])\n\tb = byteorder.BEAppendUint32(b, d.h[2])\n\tb = byteorder.BEAppendUint32(b, d.h[3])\n\tb = byteorder.BEAppendUint32(b, d.h[4])\n\tb = append(b, d.x[:d.nx]...)\n\tb = append(b, make([]byte, len(d.x)-int(d.nx))...)\n\tb = byteorder.BEAppendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)\n\treturn b, nil\n}\n\nfunc (h *sha1Hash) UnmarshalBinary(b []byte) error {\n\tif len(b) < len(sha1Magic) || string(b[:len(sha1Magic)]) != sha1Magic {\n\t\treturn errors.New(\"crypto/sha1: invalid hash state identifier\")\n\t}\n\tif len(b) != sha1MarshaledSize {\n\t\treturn errors.New(\"crypto/sha1: invalid hash state size\")\n\t}\n\td := (*sha1Ctx)(unsafe.Pointer(&h.ctx))\n\tb = b[len(sha1Magic):]\n\tb, d.h[0] = consumeUint32(b)\n\tb, d.h[1] = consumeUint32(b)\n\tb, d.h[2] = consumeUint32(b)\n\tb, d.h[3] = consumeUint32(b)\n\tb, d.h[4] = consumeUint32(b)\n\tb = b[copy(d.x[:], b):]\n\tb, n := consumeUint64(b)\n\td.nl = uint32(n << 3)\n\td.nh = uint32(n >> 29)\n\td.nx = uint32(n) % 64\n\treturn nil\n}\n\n// NewSHA224 returns a new SHA224 hash.\nfunc NewSHA224() hash.Hash {","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/boring/sha.go#L167-L203","documentation":"Returned by sha1Hash.UnmarshalBinary after the magic check passes but the total byte length does not equal sha1MarshaledSize (len(\"sha\\x01\") + 5*4 + 64 + 8 = 92). It guards against partial/truncated or extended blobs that would otherwise read out of bounds during the fixed-shape decode.","triggerScenarios":"Calling UnmarshalBinary on a sha1.New() hash with a blob of the correct magic but wrong length (truncated, padded, or from a future Go version whose marshalled layout differs).","commonSituations":"Blob stored in a DB/queue and later truncated; blob produced by a different Go version whose sha1MarshaledSize changed; hand-constructed test fixture with wrong padding.","solutions":["Verify length == 92 bytes (current Go) before unmarshalling, and reject mismatches explicitly.","Re-derive the state by re-hashing rather than persisting internal state across versions.","Regenerate the persisted blob from a current build of Go."],"exampleFix":"// before\nh.(encoding.BinaryUnmarshalser).UnmarshalBinary(state)\n// after\nconst sha1MarshaledSize = 92\nif len(state) != sha1MarshaledSize || string(state[:4]) != \"sha\\x01\" {\n    return fmt.Errorf(\"bad sha1 state\")\n}\nh.(encoding.BinaryUnmarshalser).UnmarshalBinary(state)","handlingStrategy":"validation","validationCode":"const sha1MarshaledSize = 4 + 5*4 + 64 + 8 // = 92\nfunc validSHA1State(s []byte) bool {\n    return len(s) == sha1MarshaledSize && string(s[:4]) == \"sha\\x01\"\n}","typeGuard":"// n/a","tryCatchPattern":"if err := h.(encoding.BinaryUnmarshalser).UnmarshalBinary(state); err != nil {\n    return fmt.Errorf(\"cannot restore sha1 state: %w\", err)\n}","preventionTips":["Validate magic and length before UnmarshalBinary.","Regenerate fixtures when upgrading Go.","Avoid storing marshalled hash state long-term."],"tags":["crypto","sha1","boringcrypto","serialization","validation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}