{"record":{"id":"6f091a4969108318","repo":"golang/go","slug":"crypto-rsa-d-too-small","errorCode":null,"errorMessage":"crypto/rsa: d too small","messagePattern":"crypto/rsa: d too small","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/crypto/internal/fips140/rsa/rsa.go","lineNumber":320,"sourceCode":"\t} else {\n\t\t// p > q\n\t\t// diff = 0 - q mod p = p - q\n\t\tdiff.ExpandFor(p).Sub(qP, p)\n\t}\n\t// A tiny bit of leakage is acceptable because it's not adaptive, an\n\t// attacker only learns the magnitude of p - q.\n\tif diff.BitLenVarTime() <= N.BitLen()/2-100 {\n\t\treturn errors.New(\"crypto/rsa: |p - q| too small\")\n\t}\n\n\t// Check that d > 2^(nlen/2).\n\t//\n\t// See section 3 of https://crypto.stanford.edu/~dabo/papers/RSA-survey.pdf\n\t// for more details about attacks on small d values.\n\t//\n\t// Likewise, the leakage of the magnitude of d is not adaptive.\n\tif priv.d.BitLenVarTime() <= N.BitLen()/2 {\n\t\treturn errors.New(\"crypto/rsa: d too small\")\n\t}\n\n\treturn nil\n}\n\nfunc checkPublicKey(pub *PublicKey) (fipsApproved bool, err error) {\n\tfipsApproved = true\n\tif pub.N == nil {\n\t\treturn false, errors.New(\"crypto/rsa: missing public modulus\")\n\t}\n\tif pub.N.Nat().IsOdd() == 0 {\n\t\treturn false, errors.New(\"crypto/rsa: public modulus is even\")\n\t}\n\t// FIPS 186-5, Section 5.1: \"This standard specifies the use of a modulus\n\t// whose bit length is an even integer and greater than or equal to 2048\n\t// bits.\"\n\tif pub.N.BitLen() < 2048 {\n\t\tfipsApproved = false","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/rsa/rsa.go#L302-L338","documentation":"Thrown when the private exponent d is too small (BitLenVarTime <= N.BitLen()/2). Small-d RSA is vulnerable to Wiener's attack and related lattice attacks, which recover d (and thus the private key) efficiently when d < N^0.5. The check rejects such keys; the leaked magnitude of d is non-adaptive and acceptable.","triggerScenarios":"Key validation checks priv.d.BitLenVarTime() <= N.BitLen()/2 and rejects. Reached at the end of the private-key consistency check for generated or imported keys.","commonSituations":"A deliberately small d chosen for fast signing (a known insecure optimization). Imported keys from a legacy/broken library. Test fixtures with toy-sized d.","solutions":["Regenerate the key with rsa.GenerateKey, which yields a full-size d.","Never choose d directly; let the generator pick d = e^{-1} mod λ(N) from random primes.","Reject imported keys whose d bit length is <= half the modulus bit length."],"exampleFix":"// before\n// d hand-picked small for speed\n\n// after\nkey, err := rsa.GenerateKey(rand.Reader, 2048) // d derived, full-size","handlingStrategy":"validation","validationCode":"if d.BitLen() <= n.BitLen()/2 {\n    return errors.New(\"d too small; vulnerable to Wiener/lattice attacks\")\n}","typeGuard":"func dLargeEnough(d, n *big.Int) bool { return d.BitLen() > n.BitLen()/2 }","tryCatchPattern":"err := validateKey(priv)\nif err != nil && strings.Contains(err.Error(), \"d too small\") {\n    return err // regenerate; never pick small d deliberately\n}","preventionTips":["Never optimize signing by choosing a small d.","Let rsa.GenerateKey derive d from random primes.","Reject imported keys with d <= N^0.5."],"tags":["crypto","rsa","key-validation","security","go"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}