Skip to content

Why ECDH, not RSA

The obvious way to receive encrypted mail with a hosted key is an RSA key you can decrypt with. That does not work, and the reason is worth stating precisely, because it looks like a gap in a particular key service when it is not.

The padding mismatch

OpenPGP encrypts the session key in a PKESK packet using PKCS#1 v1.5 padding (RFC 9580, Public-Key Encrypted Session Key Packet).

AWS KMS supports only RSAES_OAEP_SHA_1 and RSAES_OAEP_SHA_256 for RSA decryption. There is no PKCS#1 v1.5 path.

So an ENCRYPT_DECRYPT RSA key provisions cleanly, costs money, and then decrypts nothing. The failure arrives at the first real message rather than at setup, which is the expensive kind.

This is not an AWS quirk to route around. PKCS#1 v1.5 decryption is a padding oracle risk, and key services decline to offer it deliberately. Expect the same answer elsewhere.

Why ECDH escapes it

ECDH involves no padding at all.

A key agreement returns a shared secret — for a NIST curve, the x-coordinate of the shared point. OpenPGP's ECDH runs a KDF over exactly that value to produce a key-encryption key, then AES-key-unwraps the session key with it.

So the value a key service is willing to return is precisely the value the format needs. Nothing has to be smuggled past a padding scheme.

Two details that could have broken this, and did not:

  • KMS implements the cofactor ECDH primitive (SP 800-56A). NIST curves have cofactor h=1, so cofactor ECDH is ordinary ECDH here.
  • The peer's public key goes in as a DER SubjectPublicKeyInfo, which is a re-encoding of the PKESK's ephemeral point rather than a cryptographic obstacle.

What this costs

An encryption subkey that is ECDH, and therefore a certification primary that is something else — a KEY_AGREEMENT key cannot sign its own binding signature. So a certificate needs two keys where one might have done.

That is the price of the private half never existing outside the service, and it is a good trade.