golang/go · error
crypto/rsa: input must be hashed message
Error message
crypto/rsa: input must be hashed message
What it means
Thrown by SignPKCS1v15 when hash is non-zero and len(hashed) != hash.Size(). PKCS#1 v1.5 signing requires the input to be exactly the digest of the named hash function; a mismatched length means the caller passed the wrong data (e.g. the raw message instead of its hash, or a different hash's output). This is basic input validation, not FIPS-specific.
Source
Thrown at src/crypto/rsa/fips.go:339
}
// SignPKCS1v15 calculates the signature of hashed using
// RSASSA-PKCS1-V1_5-SIGN from RSA PKCS #1 v1.5. Note that hashed must
// be the result of hashing the input message using the given hash
// function. If hash is zero, hashed is signed directly. This isn't
// advisable except for interoperability.
//
// The random parameter is legacy and ignored, and it can be nil.
//
// This function is deterministic. Thus, if the set of possible
// messages is small, an attacker may be able to build a map from
// messages to signatures and identify the signed messages. As ever,
// signatures provide authenticity, not confidentiality.
func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
var hashName string
if hash != crypto.Hash(0) {
if len(hashed) != hash.Size() {
return nil, errors.New("crypto/rsa: input must be hashed message")
}
hashName = hash.String()
}
if err := checkPublicKeySize(&priv.PublicKey); err != nil {
return nil, err
}
if boring.Enabled && priv.N.BitLen() >= 1024 {
bkey, err := boringPrivateKey(priv)
if err != nil {
return nil, err
}
return boring.SignRSAPKCS1v15(bkey, hash, hashed)
}
if err := checkFIPS140OnlyPrivateKey(priv); err != nil {
return nil, errView on GitHub (pinned to b6b368adc5)
Solutions
- Hash first: h := sha256.Sum256(msg); then pass h[:] with crypto.SHA256.
- Ensure the hash constant passed as 'hash' matches the function that produced 'hashed'.
- If hash == 0 (sign pre-hashed/raw), pass the data directly — but only when you intentionally bypass the digest requirement.
Example fix
// before sig, err := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, message) // after digest := sha256.Sum256(message) sig, err := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, digest[:])
Defensive patterns
Strategy: validation
Validate before calling
if hash != 0 && len(hashed) != hash.Size() {
return fmt.Errorf("hashed input is %d bytes, expected %d for %s", len(hashed), hash.Size(), hash)
}
sig, err := rsa.SignPKCS1v15(rand.Reader, priv, hash, hashed) Type guard
func digestMatchesHash(hash crypto.Hash, hashed []byte) bool {
return hash == 0 || len(hashed) == hash.Size()
} Prevention
- Always hash the message immediately before the Sign call using the same hash constant.
- Never pass the raw message where a digest is expected.
- Wrap signing in a helper that hashes+signs together to prevent the mismatch.
When it happens
Trigger: Calling rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, rawMessageBytes) — passing the plaintext instead of sha256.Sum256(...). Passing a SHA-512 digest (64 bytes) with crypto.SHA256 (expects 32 bytes). Passing a truncated or padded hash slice.
Common situations: Forgetting to hash the message first. Mismatch between the hash used to produce 'hashed' and the 'hash' argument. Off-by-slice (passing a 33-byte slice that includes a length prefix).
Related errors
- crypto/rsa: invalid PSS salt length
- crypto/rsa: verification error
- crypto/rsa: invalid PSS salt length
- crypto/rsa: unsupported hash function: %d
- crypto/rsa: unsupported hash function
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/4592a71ebd793530.
Report an issue: GitHub.