{"record":{"id":"2b292f21bace662a","repo":"nautechsystems/nautilus_trader","slug":"failed-to-decode-rsa-private-key","errorCode":null,"errorMessage":"Failed to decode RSA private key","messagePattern":"Failed to decode RSA private key","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cryptography/src/signing.rs","lineNumber":59,"sourceCode":"/// - `data` is empty.\n/// - `private_key_pem` is not a valid PEM-encoded PKCS#8 RSA private key or cannot be parsed.\n/// - Signature generation fails due to key or cryptographic errors.\npub fn rsa_signature(private_key_pem: &str, data: &str) -> anyhow::Result<String> {\n    if data.is_empty() {\n        anyhow::bail!(\"Query string cannot be empty\");\n    }\n\n    // Remove PEM headings and decode to DER bytes using the `pem` crate\n    let pem = pem::parse(private_key_pem.trim())\n        .map_err(|e| anyhow::anyhow!(\"Failed to parse PEM: {e}\"))?;\n\n    // Ensure this is a private key\n    if !pem.tag().ends_with(\"PRIVATE KEY\") {\n        anyhow::bail!(\"PEM does not contain a private key\");\n    }\n\n    // Construct RSA key pair from PKCS#8 DER bytes\n    let key_pair = KeyPair::from_pkcs8(pem.contents())\n        .map_err(|_| anyhow::anyhow!(\"Failed to decode RSA private key\"))?;\n\n    // Prepare RNG and output buffer (signature length = modulus length)\n    let rng = lc_rand::SystemRandom::new();\n    let mut signature = vec![0u8; key_pair.public_modulus_len()];\n\n    key_pair\n        .sign(\n            &lc_signature::RSA_PKCS1_SHA256,\n            &rng,\n            data.as_bytes(),\n            &mut signature,\n        )\n        .map_err(|_| anyhow::anyhow!(\"Failed to generate RSA signature\"))?;\n\n    Ok(BASE64_STANDARD.encode(signature))\n}\n","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/cryptography/src/signing.rs#L41-L77","documentation":"The PEM parsed and passed the private-key tag check, but `KeyPair::from_pkcs8` could not decode the DER contents as a valid PKCS#8 RSA private key (ring rejects it). The underlying error is deliberately discarded, so the message is generic; it means the key material is structurally invalid, not RSA/PKCS#8, corrupted, or encrypted.","triggerScenarios":"Calling `rsa_signature` with PEM contents that are valid PEM with a private-key-looking tag but whose DER is not parseable PKCS#8 RSA — e.g. an 'ENCRYPTED PRIVATE KEY' block, an Ed25519/EC key, truncated base64 that still parses, or a PKCS#1 body mislabeled as 'PRIVATE KEY'.","commonSituations":"Using an encrypted (passphrase-protected) key without decrypting; keys generated in another format (PKCS#1 'BEGIN RSA PRIVATE KEY' bodies relabeled, or SEC1 EC keys); corrupted copy/paste; cloud secrets returning an unexpected key type.","solutions":["Convert the key to unencrypted PKCS#8: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_pkcs8.pem","Decrypt if prompted for a passphrase and re-export without encryption before use","Verify the key type: openssl pkey -in key.pem -text -noout (must show an RSA private key)","Regenerate the keypair if the material is truncated or corrupted"],"exampleFix":"// before\nlet sig = rsa_signature(&encrypted_pem, query)?; // ENCRYPTED PRIVATE KEY\n// after\n// openssl pkcs8 -topk8 -nocrypt -in encrypted.pem -out decrypted.pem\nlet sig = rsa_signature(&std::fs::read_to_string(\"decrypted.pem\")?, query)?;","handlingStrategy":"validation","validationCode":"// reject encrypted or non-RSA keys up front\nif key_text.contains(\"ENCRYPTED PRIVATE KEY\") {\n    return Err(anyhow::anyhow!(\"decrypt the key to PKCS#8 first\"));\n}\n// convert: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_pkcs8.pem","typeGuard":"fn is_pkcs8_rsa_private_key(s: &str) -> bool {\n    s.contains(\"-----BEGIN PRIVATE KEY-----\") && !s.contains(\"ENCRYPTED\")\n}","tryCatchPattern":"match rsa_signature(&key, query) {\n    Ok(sig) => use(sig),\n    Err(e) if e.to_string().contains(\"Failed to decode RSA private key\") => {\n        tracing::error!(\"key is not unencrypted PKCS#8 RSA; re-export with openssl\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Standardize on unencrypted PKCS#8 ('BEGIN PRIVATE KEY') for all keys","Decrypt passphrase-protected keys before automated use","Verify key type/format with openssl before deployment"],"tags":["rust","cryptography","rsa","pkcs8","key-format"],"backgroundTag":"invalid-argument-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}