Blog

All Blog Posts  |  Next Post  |  Previous Post

Demystifying SSH crypto containers: architecture, X.509 differences, OpenSSL creation, and TMS Crypto creation

Today

When managing secure access to remote infrastructure, understanding how cryptographic material is structured and stored is essential. While terms like "keys," "certificates," and "containers" are often used interchangeably, they represent distinct layers of security abstraction.

Our TMS Cryptography Pack contains all cryptographic primitives to generate SSH objects but so far, generation and decoding of such containers was not possible. This is fixed with version 5.3.3.0. 

In this blog post, we will explore SSH crypto containers, compare them with traditional X.509 certificates and keys, outline available options, and walk through creating one using OpenSSL, and, as usual, show how simple it is to generate and read them with TMS Cryptography Pack in native Delphi.

What is an SSH crypto container?

An SSH crypto container refers to a structured file or format designed to securely encapsulate cryptographic material (such as private keys, public keys, and metadata) used within the Secure Shell (SSH) ecosystem.

Rather than storing a private key as plain text on a disk, modern crypto containers or formats (like PEM-formatted encrypted keys, PKCS#8, or OpenSSH's native key formats) wrap the sensitive material inside an authenticated, encrypted envelope. This ensures that even if unauthorized users gain read access to the storage medium, the private key remains protected behind a symmetric encryption cipher (such as AES-256) and a user-defined passphrase.


SSH containers vs. X.509 certificates and keys 

It is common to confuse SSH authentication formats with X.509 certificates (commonly used in TLS/HTTPS, web browsers, and mTLS). However, they serve different ecosystems and follow distinct design philosophies:


FeatureSSH Keys & ContainersX.509 Certificates & Keystores (PEM/PKCS#12)
Primary Use CaseRemote shell access, server administration, Git operations.Web traffic (TLS/SSL), code signing, enterprise mTLS.
Trust ModelDirect trust (Public keys stored in authorized_keys or via SSH Certificate Authorities).Hierarchical trust via a Public Key Infrastructure (PKI) chain of trust to a Root CA.
ComplexityLightweight, optimized specifically for the SSH protocol.Heavy, carrying extensive metadata, Distinguished Names (DN), and varied extensions.
Container FormatsOpenSSH format, PEM, PKCS#8.PKCS#12 (.p12/.pfx), PEM chains (various encodings).

Overview of options for SSH cryptographic storage

When working with cryptographic keys for SSH, you generally encounter a few standard options:

  • Traditional PEM / OpenSSH Private Key Format: The default plaintext or ciphertext file generated by tools like ssh-keygen.
  • PKCS#8 Containers: A standardized syntax for storing private key information, allowing better algorithm agility and stronger encryption wrappers across different tools.
  • Encrypted PEM with Symmetric Ciphers: Wrapping standard keys using algorithms like aes256-cbc or chacha20-poly1305, requiring a passphrase for extraction.
  • Hardware Tokens / Secure Enclaves: Storing keys in YubiKeys, TPMs, or HSMs (PKCS#11) where the container acts as a logical reference to hardware-isolated crypto operations.

Hands-On: Creating an Encrypted SSH Crypto Container with OpenSSL

You can use OpenSSL to generate a secure, password-protected private key container that can later be adapted or converted for cryptographic operations.

Step 1: Generate an Encrypted RSA Private Key Container

Run the following command to generate a 4096-bit RSA private key encrypted with AES-256:

openssl genpkey -algorithm RSA -out ssh_crypto_container.pem -aes256 -pkeyopt rsa_keygen_bits:4096
  • -aes256: Ensures the private key is wrapped inside an encrypted container, prompting you for a secure passphrase.

  • -out ssh_crypto_container.pem: Specifies the output file acting as your crypto container.

Step 2: Inspect the Container Structure

Because the container is encrypted, attempting to read the private key directly will show ciphertext wrapper headers:

cat ssh_crypto_container.pem

Output preview:

-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIJrDBOBgkqhkiG9w0BBQ0wMjAbBgkqhkiG9w0BBQwwDgQI...
-----END ENCRYPTED PRIVATE KEY-----

Step 3: Extract the Public Key Component

To use this container for authentication workflows, you need to extract the corresponding public key:

openssl rsa -in ssh_crypto_container.pem -pubout -out ssh_public_key.pub

(Note: You will be prompted to enter the passphrase you created in Step 1).

What does TMS Cryptography Pack provide for SSH?

The TSSHKeyHandler class is a self-contained Delphi unit to generate, read, write and convert SSH keys, interoperable with OpenSSH (ssh-keygen, ssh) and OpenSSL. It builds on the library’s own primitives (RSA, ECDSA, Ed25519, AES, bcrypt - added) and needs no external tool or DLL at run time.

  • Key types: RSA (1024–4096 bits), ECDSA (P-256, P-384, P-521) and Ed25519.
  • OpenSSH private keys (-----BEGIN OPENSSH PRIVATE KEY-----): read and write, in clear or protected by a passphrase (bcrypt KDF with aes128/192/256-ctr on reading, aes256-ctr on writing).
  • PKCS#8 / PEM files; readable by OpenSSL: private key (optionally encrypted), public key (SubjectPublicKeyInfo), and the one-line ssh-rsa … / ecdsa-sha2-… / ssh-ed25519 … public key.
  • Public keys: read and write .pub files with their comments, and compute SHA256 fingerprints identical to ssh-keygen -lPassphrases and comments may contain any Unicode character (stored as UTF-8).

 

Some features are not supported:

ssh-dss, FIDO (sk-*) keys, and the ciphers chacha20-poly1305, aes*-gcm and aes*-cbc for OpenSSH private keys (AES GCM and CBC might be added later).
  • OpenSSH rejects private key files with CRLF line endings, so SSHObj always writes them with LF, whatever the platform.
  • Secrets are wiped from memory on a best-effort basis; Delphi strings and dynamic arrays cannot guarantee it completely.
  • The demo project (SSHDemo) exercises the whole API against containers generated by OpenSSH and OpenSSL.

How to use the class

Everything is exposed through the static methods of TSSHKeyHandler. Keys are exchanged through the records TSSHPublicKey and TSSHPrivateKey, whose fields are hexadecimal strings (modulus, exponent, EC point, private exponent or seed, RSA primes, comment).

Here is an example of code.

uses SSHObj;

var
  K: TSSHPrivateKey;

begin
  // Generate an Ed25519 key pair in OpenSSH format, protected by a passphrase
  TSSHKeyHandler.GenerateOpenSSHKeyFiles(ktED25519, 'my passphrase', 'me@host',
    'id_ed25519', 'id_ed25519.pub');

  // RSA works the same way; the last two arguments are bcrypt rounds and key size
  TSSHKeyHandler.GenerateOpenSSHKeyFiles(ktRSA, '', 'me@host', 'id_rsa', 'id_rsa.pub', 16, 3072);

  // Read a key (raises ECryptoPack if the passphrase is wrong or missing)
  if TSSHKeyHandler.FromSSHPrivateKeyFile(K, 'my passphrase', 'id_ed25519') then
    Writeln(K.Algorithm, ' ', K.Size, ' bits, ', K.Comment);

  // Change the passphrase (an empty passphrase writes the key in clear)
  TSSHKeyHandler.ToSSHPrivateKeyFile(K, 'new passphrase', 'id_ed25519_new');

  // SHA256 fingerprint, as printed by ssh-keygen -l
  Writeln(TSSHKeyHandler.FingerPrintKeyFile('id_ed25519.pub'));

  // PKCS#8 + PEM public key + ssh public key, for OpenSSL
  TSSHKeyHandler.ToKeyFiles(ktECDSA_P256, 0, 'pwd', 'key.pem', 'key.pub', 'key.pub.pem');
end;

Conclusion

Understanding how SSH crypto containers operate gives you deeper control over your infrastructure's security posture. By leveraging encrypted containers via SSHObj from your applications, you ensure that your credentials remain safe even if storage boundaries are compromised.
Are you currently using file-based SSH keys, or have you transitioned to hardware tokens and certificate-based authorities in your environment?


Bernard Roussely




This blog post has not received any comments yet.



Add a new comment

You will receive a confirmation mail with a link to validate your comment, please use a valid email address.
All fields are required.



All Blog Posts  |  Next Post  |  Previous Post