How Linux Generates Ed25519 SSH Keys
This article provides an overview of how the Linux operating system creates and manages SSH authentication keys using the Ed25519 elliptic curve algorithm. It explores the interaction between user-space tools like OpenSSH, the kernel's entropy and randomness subsystem, the mathematical structure of the Edwards-curve Digital Signature Algorithm (EdDSA), and the filesystem permission standards that secure private credentials.
The Role of OpenSSH and the Command Layer
In Linux, SSH key management is handled primarily by the OpenSSH
suite. Generating an Ed25519 key pair begins in user space using the
ssh-keygen utility:
ssh-keygen -t ed25519 -C "user@example.com"The -t ed25519 flag instructs ssh-keygen to
use the Edwards-curve Digital Signature Algorithm (EdDSA) instantiated
over Curve25519. Unlike RSA, which requires the user to specify key
lengths (such as 2048, 3072, or 4096 bits), Ed25519 uses a fixed key
size of 256 bits, which translates to a compact 32-byte public key and a
64-byte signature.
Entropy Gathering via the Linux Kernel
The security of any asymmetric cryptosystem depends entirely on the
unpredictability of its secret key. During the generation phase,
ssh-keygen interacts with the Linux kernel's
Cryptographically Secure Pseudorandom Number Generator (CSPRNG).
On modern Linux kernels, the tool relies on the
getrandom() system call (or /dev/urandom as a
fallback). The kernel gathers hardware noise, interrupt timings, and
device inputs to build entropy pools, feeding ChaCha20-based DRNG
algorithms. This guarantees that the initial 32-byte seed extracted for
the private key possesses maximum cryptographic randomness, preventing
predictability or brute-force attacks on the generated keypair.
Mathematical Derivation of the Keypair
Once the 32-byte random seed is acquired from the kernel, OpenSSH processes it according to the Ed25519 specification:
- Hashing the Seed: The 32-byte seed is passed through the SHA-512 cryptographic hash function, generating a 64-byte digest.
- Scalar Clamping: The lower 32 bytes of the digest are "clamped" (specific bits are cleared and set) to clear small subgroup attacks and ensure the scalar value falls within safe limits.
- Public Key Calculation: The clamped 32-byte scalar is multiplied by the standard base point \(B\) on the twisted Edwards curve $ -x^2 + y^2 = 1 - \frac{121665}{121666}x^2y^2 $ over the prime field \(2^{255} - 19\). The resulting coordinate is compressed into a 32-byte public key.
- Private Key Storage: The private key consists of the initial 32-byte seed (or the full 64-byte expanded secret along with the public key) to facilitate fast signing.
File Encoding, Passphrase Protection, and Permissions
After computing the keypair, OpenSSH formats and writes the files to
the user's home directory, usually inside ~/.ssh/:
id_ed25519(Private Key): Stored using the OpenSSH private key format. If the user provides a passphrase, Linux uses a key derivation function (bcrypt KDF) coupled with AES-256-CTR or ChaCha20-Poly1305 to encrypt the private key payload before writing it to disk.id_ed25519.pub(Public Key): Stored in Base64 plaintext format containing the key type identifier, the 32-byte public key, and the optional comment string.
Linux enforces mandatory Discretionary Access Control (DAC) file
permissions on these assets. OpenSSH refuses to load private keys that
are readable by other users, automatically verifying that
id_ed25519 has permissions set to 0600
(read/write only by the owner) and the parent .ssh
directory is restricted to 0700.