{"record":{"id":"ab0a69fb1e61d4d0","repo":"FiloSottile/age","slug":"rsa-key-size-is-too-small","errorCode":null,"errorMessage":"RSA key size is too small","messagePattern":"RSA key size is too small","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agessh/agessh.go","lineNumber":67,"sourceCode":"func NewRSARecipient(pk ssh.PublicKey) (*RSARecipient, error) {\n\tif pk.Type() != \"ssh-rsa\" {\n\t\treturn nil, errors.New(\"SSH public key is not an RSA key\")\n\t}\n\tr := &RSARecipient{\n\t\tsshKey: pk,\n\t}\n\n\tif pk, ok := pk.(ssh.CryptoPublicKey); ok {\n\t\tif pk, ok := pk.CryptoPublicKey().(*rsa.PublicKey); ok {\n\t\t\tr.pubKey = pk\n\t\t} else {\n\t\t\treturn nil, errors.New(\"unexpected public key type\")\n\t\t}\n\t} else {\n\t\treturn nil, errors.New(\"pk does not implement ssh.CryptoPublicKey\")\n\t}\n\tif r.pubKey.N.BitLen() < 2048 {\n\t\treturn nil, errors.New(\"RSA key size is too small\")\n\t}\n\treturn r, nil\n}\n\nfunc (r *RSARecipient) Wrap(fileKey []byte) ([]*age.Stanza, error) {\n\tif r.pubKey.N.BitLen() < 2048 {\n\t\treturn nil, errors.New(\"RSA key size is too small\")\n\t}\n\tl := &age.Stanza{\n\t\tType: \"ssh-rsa\",\n\t\tArgs: []string{sshFingerprint(r.sshKey)},\n\t}\n\n\twrappedKey, err := rsa.EncryptOAEP(sha256.New(), rand.Reader,\n\t\tr.pubKey, fileKey, []byte(oaepLabel))\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/agessh/agessh.go#L49-L85","documentation":"NewRSARecipient enforces a minimum modulus size of 2048 bits before accepting the key, because RSA-1024 and smaller are considered insecure. The key is otherwise a valid ssh-rsa key but is rejected at construction time. The same check is repeated in Wrap (error [4]) for defense in depth.","triggerScenarios":"Calling agessh.NewRSARecipient(pk) with an ssh-rsa key whose rsa.PublicKey.N.BitLen() < 2048 — e.g. a 1024-bit (or 768-bit) RSA key.","commonSituations":"Legacy authorized_keys entries generated in the 2000s with ssh-keygen -t rsa -b 1024; old automated/deployment keys never rotated; corporate keys grandfathered from pre-2013 standards.","solutions":["Generate a new key with at least 2048 bits, preferably 4096: ssh-keygen -t rsa -b 4096.","Re-encrypt the data to the new recipient key and retire the weak key.","If you control key generation in Go, use rsa.GenerateKey(rand.Reader, 4096) and ssh.NewPublicKey."],"exampleFix":"// before\nssh-keygen -t rsa -b 1024 -f id_rsa // rejected\n// after\nssh-keygen -t rsa -b 4096 -f id_rsa","handlingStrategy":"validation","validationCode":"func checkRSASize(pk ssh.PublicKey) error {\n    cpk, ok := pk.(ssh.CryptoPublicKey)\n    if !ok { return errors.New(\"no crypto key\") }\n    r, ok := cpk.CryptoPublicKey().(*rsa.PublicKey)\n    if !ok { return errors.New(\"not RSA\") }\n    if r.N.BitLen() < 2048 {\n        return fmt.Errorf(\"RSA key has %d bits; need >= 2048\", r.N.BitLen())\n    }\n    return nil\n}","typeGuard":"func isStrongRSA(pk ssh.PublicKey) bool {\n    cpk, ok := pk.(ssh.CryptoPublicKey)\n    if !ok { return false }\n    r, ok := cpk.CryptoPublicKey().(*rsa.PublicKey)\n    return ok && r.N.BitLen() >= 2048\n}","tryCatchPattern":"rec, err := agessh.NewRSARecipient(pk)\nif err != nil {\n    if strings.Contains(err.Error(), \"key size is too small\") {\n        return fmt.Errorf(\"rotate key %s: RSA < 2048 bits\", sshFingerprint(pk))\n    }\n    return err\n}","preventionTips":["Generate RSA keys with ssh-keygen -t rsa -b 4096 (never below 2048).","Audit legacy authorized_keys for 1024-bit keys and rotate them.","Enforce key-size policy at key-provisioning time, not at use time.","Prefer Ed25519 keys for new deployments to sidestep RSA sizing entirely."],"tags":["rsa","key-size","security","ssh","age"],"backgroundTag":"rsa-key-too-small","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}