null to decline
(for example when the user cancels a prompt), which aborts loading with SshKeyPassphraseException.
SSH private key file loaders (unencrypted formats only).
Loads explicitly supported unencrypted private key containers and adapts them to the SshSigner interface used by SshSession.authenticatePublicKey. The supported container and key combinations are:
openssh-key-v1 with cipher/KDF none
(PEM label "OPENSSH PRIVATE KEY"; also accepted without armor). Carries ssh-ed25519, ssh-rsa, and ecdsa-sha2-nistp256 keys; exactly one key per file is supported.
RSAPrivateKey (PEM label "RSA PRIVATE KEY"
or raw DER).
ECPrivateKey (PEM label "EC PRIVATE KEY" or
raw DER), restricted to P-256.
PrivateKeyInfo (PEM label
"PRIVATE KEY" or raw DER) carrying RSA, Ed25519, or ECDSA P-256 keys.
Encrypted containers are governed by the passphrase contract: a caller may supply an SshPassphraseProvider callback that acquires the passphrase synchronously (key loading never runs on the pump path). With a provider, encrypted openssh-key-v1 files using the dominant aes256-ctr cipher with the bcrypt KDF and encrypted PKCS#8 files using PBES2 with PBKDF2 (HMAC-SHA-1/-SHA-256/-SHA-512) and AES-CBC are decrypted in-process; other encrypted-key-v1 ciphers (including the aes256-gcm@openssh.com default of OpenSSH 9.5 and later) and other PBES2 schemes fail with SshKeyEncryptionException. Wrong passphrases are retried a bounded number of times through SshKeyPassphraseException. Without a provider, every encrypted container — encrypted openssh-key-v1, encrypted PKCS#8 ("ENCRYPTED PRIVATE KEY" / PBES2, and legacy PEM encryption (Proc-Type/DEK-Info) — fails with SshKeyEncryptionException so callers can direct the user at ssh-add/agent-based workflows instead. Unknown labels and structures fail with SshKeyException.
Loaded keys are validated before use: public/private consistency is checked cryptographically (Ed25519 public keys are re-derived from the private material and must match the container; RSA requires n == p * q), and RSA moduli below SshKeyLimits.rsaMinBits are rejected. Private ECDSA containers are rejected before scalar decoding.
Secret hygiene: every secret buffer this module allocates — the KDF-derived key material, the cipher state, and the decrypted private section — is explicitly zeroized once parsing completes. The passphrase itself arrives as an immutable D string and the loaded key material is copied into long-lived key objects, so perfect scrubbing is impossible under D's GC; this residual-copy risk is accepted and documented rather than hidden.
Raised when a private key file uses encryption.
Encrypted containers are explicitly out of scope: OpenSSH encryption requires bcrypt_pbkdf and legacy PEM/PKCS#8 encryption is a separate feature. The distinct type lets callers direct users at agent-based workflows without string matching.
this(string msg, string file = __FILE__, size_t line = __LINE__)Constructs an encryption-not-supported exception.Raised when passphrase-protected key material cannot be unlocked.
This is the retry-loop signal: an encrypted container reports a rejected passphrase by throwing this type, and the loader asks the provider again until maxPassphraseAttempts is exhausted. It derives from SshKeyEncryptionException so callers written against the older single-exception surface keep working.
this(string msg, string file = __FILE__, size_t line = __LINE__)Constructs a passphrase-failure exception.Context handed to an SshPassphraseProvider when an encrypted private key file needs its passphrase.
uint attemptOne-based number of this attempt; a value above 1 means the previous passphrase was rejected and the user should be told so.string containerHuman-readable container description, for example "openssh-key-v1 (aes256-ctr") or "PKCS#8 PBES2 (AES-256-CBC").Synchronously acquires the passphrase for an encrypted key file.
null to decline
(for example when the user cancels a prompt), which aborts loading with SshKeyPassphraseException.
Key file parser limits enforced before any allocation.
An SshSigner backed by an in-memory private key loaded from a key file.
Signing is synchronous: sign completes in one call. RSA keys accept only the SHA-2 signature algorithms (rsa-sha2-256/rsa-sha2-512); the SHA-1 ssh-rsa signature algorithm is refused like everywhere else in the profile.
private SshPublicKeyInfo publicKey_private Ed25519PrivateKey ed25519_private RSAPrivateKey rsa_SshPublicKeyInfo publicKey() @property constReturns: the public key offer built from the private key, never null.SshSignResult sign(scope const(ubyte)[] requestData,
string signatureAlgorithm)Signs the request data with the loaded key.SshSignResult signChecked(scope const(ubyte)[] requestData,
string signatureAlgorithm)this(SshPublicKeyInfo publicKey)Parsed PBES2 parameters of an EncryptedPrivateKeyInfo.
const(ubyte)[] saltPBKDF2 salt.uint iterationsPBKDF2 iteration count.uint keyLengthCipher key length in bytes implied by the encryption scheme.string cipherNameHuman-readable encryption scheme name, e.g. AES-256-CBC.const(ubyte)[] ivCipher IV.uint prfShaHMAC-SHA variant for the PBKDF2 PRF: 1, 256, or 512.const(ubyte)[] encryptedDataEncrypted body.SshSigner loadSshPrivateKeyFile(const(ubyte)[] fileBytes)Loads an unencrypted SSH private key file.SshSigner loadSshPrivateKeyFile(const(ubyte)[] fileBytes,
SshPassphraseProvider provider)Loads a private key file, decrypting encrypted containers with a passphrase acquired from provider.T withPassphraseRetries(T)(SshPassphraseProvider provider,
string container,
scope T delegate(const(ubyte)[] passphrase) attempt)Runs one decryption attempt per passphrase obtained from provider, retrying a rejected passphrase until maxPassphraseAttempts is exhausted.SshSigner loadEncryptedPkcs8(const(ubyte)[] der,
SshPassphraseProvider provider)Loads an EncryptedPrivateKeyInfo, decrypting it through the passphrase retry loop when provider is given.Pbes2Params parsePbes2Params(const(ubyte)[] der)Parses the PBES2 parameters of an EncryptedPrivateKeyInfo (RFC 8018 appendix A.4), restricting the profile to PBKDF2 with HMAC-SHA-1/-SHA-256/-SHA-512 and AES-128/192/256-CBC.SshSigner decryptPbes2Attempt(const Pbes2Params params,
const(ubyte)[] passphrase)Performs one PBES2 decrypt-and-adopt attempt.SshSigner decryptOpenSshPrivateSection(const(ubyte)[] privateBlob,
const(ubyte)[] salt, uint rounds,
const SshParsedPublicKey parsedPublic, const(ubyte)[] publicBlob,
const(ubyte)[] passphrase)Decrypts one encrypted openssh-key-v1 private section attempt.SshSigner parseOpenSshPrivateSection(const(ubyte)[] section,
const SshParsedPublicKey parsedPublic, const(ubyte)[] publicBlob,
bool encrypted)Parses a (decrypted or plaintext) openssh-key-v1 private section.SshSigner parseOpenSshPrivateKey(ref SshWireReader reader,
const SshParsedPublicKey parsedPublic, const(ubyte)[] publicBlob)maxPassphraseAttempts = 3Bounded retry policy: the maximum number of passphrase attempts made against one encrypted container before giving up.
openSshMagic = "openssh-key-v1\0"