FiloSottile/age · error
RSA key size is too small
Error message
RSA key size is too small
What it means
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.
Source
Thrown at agessh/agessh.go:67
func NewRSARecipient(pk ssh.PublicKey) (*RSARecipient, error) {
if pk.Type() != "ssh-rsa" {
return nil, errors.New("SSH public key is not an RSA key")
}
r := &RSARecipient{
sshKey: pk,
}
if pk, ok := pk.(ssh.CryptoPublicKey); ok {
if pk, ok := pk.CryptoPublicKey().(*rsa.PublicKey); ok {
r.pubKey = pk
} else {
return nil, errors.New("unexpected public key type")
}
} else {
return nil, errors.New("pk does not implement ssh.CryptoPublicKey")
}
if r.pubKey.N.BitLen() < 2048 {
return nil, errors.New("RSA key size is too small")
}
return r, nil
}
func (r *RSARecipient) Wrap(fileKey []byte) ([]*age.Stanza, error) {
if r.pubKey.N.BitLen() < 2048 {
return nil, errors.New("RSA key size is too small")
}
l := &age.Stanza{
Type: "ssh-rsa",
Args: []string{sshFingerprint(r.sshKey)},
}
wrappedKey, err := rsa.EncryptOAEP(sha256.New(), rand.Reader,
r.pubKey, fileKey, []byte(oaepLabel))
if err != nil {
return nil, err
}View on GitHub (pinned to b74dce4cdb)
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.
Example fix
// before ssh-keygen -t rsa -b 1024 -f id_rsa // rejected // after ssh-keygen -t rsa -b 4096 -f id_rsa
Defensive patterns
Strategy: validation
Validate before calling
func checkRSASize(pk ssh.PublicKey) error {
cpk, ok := pk.(ssh.CryptoPublicKey)
if !ok { return errors.New("no crypto key") }
r, ok := cpk.CryptoPublicKey().(*rsa.PublicKey)
if !ok { return errors.New("not RSA") }
if r.N.BitLen() < 2048 {
return fmt.Errorf("RSA key has %d bits; need >= 2048", r.N.BitLen())
}
return nil
} Type guard
func isStrongRSA(pk ssh.PublicKey) bool {
cpk, ok := pk.(ssh.CryptoPublicKey)
if !ok { return false }
r, ok := cpk.CryptoPublicKey().(*rsa.PublicKey)
return ok && r.N.BitLen() >= 2048
} Try / catch
rec, err := agessh.NewRSARecipient(pk)
if err != nil {
if strings.Contains(err.Error(), "key size is too small") {
return fmt.Errorf("rotate key %s: RSA < 2048 bits", sshFingerprint(pk))
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- unexpected public key type
- pk does not implement ssh.CryptoPublicKey
- SSH public key is not an RSA key
- SSH public key is not an Ed25519 key
- mismatched private and public SSH key
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/ab0a69fb1e61d4d0.
Report an issue: GitHub.