{"record":{"id":"cc3a5c3eb6775a6a","repo":"rustdesk/rustdesk-server","slug":"invalid-secret-key-cc3a5c","errorCode":null,"errorMessage":"Invalid Secret key","messagePattern":"Invalid Secret key","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/utils.rs","lineNumber":44,"sourceCode":"\nfn gen_keypair() {\n    let (pk, sk) = sign::gen_keypair();\n    let public_key = base64::encode(pk);\n    let secret_key = base64::encode(sk);\n    println!(\"Public Key:  {public_key}\");\n    println!(\"Secret Key:  {secret_key}\");\n}\n\nfn validate_keypair(pk: &str, sk: &str) -> ResultType<()> {\n    let sk1 = base64::decode(sk);\n    if sk1.is_err() {\n        bail!(\"Invalid secret key\");\n    }\n    let sk1 = sk1.unwrap();\n\n    let secret_key = sign::SecretKey::from_slice(sk1.as_slice());\n    if secret_key.is_none() {\n        bail!(\"Invalid Secret key\");\n    }\n    let secret_key = secret_key.unwrap();\n\n    let pk1 = base64::decode(pk);\n    if pk1.is_err() {\n        bail!(\"Invalid public key\");\n    }\n    let pk1 = pk1.unwrap();\n\n    let public_key = sign::PublicKey::from_slice(pk1.as_slice());\n    if public_key.is_none() {\n        bail!(\"Invalid Public key\");\n    }\n    let public_key = public_key.unwrap();\n\n    let random_data_to_test = b\"This is meh.\";\n    let signed_data = sign::sign(random_data_to_test, &secret_key);\n    let verified_data = sign::verify(&signed_data, &public_key);","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/rustdesk/rustdesk-server/blob/a7736be5e40f85bfc141120dce587e836e5d4b80/src/utils.rs#L26-L62","documentation":"After the secret key successfully base64-decodes, validate_keypair feeds the decoded bytes to sign::SecretKey::from_slice; sodium's constructor requires exactly 64 bytes, so if the decoded length is wrong it returns None and the code bails with \"Invalid Secret key\". The input was valid base64 but not a valid Ed25519 secret key.","triggerScenarios":"Supplying a base64 string that decodes to a byte length other than 64 - e.g. a public key (32 bytes) pasted where the secret key belongs, a hex-encoded key, or a truncated key.","commonSituations":"Swapping the -k (secret) and -p/-K (public) arguments; using a key from a different library/format (hex instead of base64); truncated paste of a 64-byte key.","solutions":["Ensure you pass the SECRET key (decodes to exactly 64 bytes) to -k, not the public key.","Check decoded length: `echo '<sk>' | base64 -d | wc -c` must print 64.","Regenerate the keypair with the bundled key generator and use the freshly printed 'Secret Key' value."],"exampleFix":"// before: public key (32 bytes) passed as secret\nhbbs --doctor -k 'OeVuKk5nlHiXp+ApNYY=...' // 32-byte pk\n// after: the 64-byte secret key\nhbbs --doctor -k '<64-byte-base64-secret-key>'","handlingStrategy":"validation","validationCode":"let decoded = base64::decode(sk.trim())?;\nassert_eq!(decoded.len(), 64, \"Ed25519 secret key must decode to 64 bytes, got {}\", decoded.len());","typeGuard":"fn is_secret_key_b64(s: &str) -> bool { base64::decode(s).map(|b| b.len() == 64).unwrap_or(false) }","tryCatchPattern":null,"preventionTips":["Label key files clearly (secret vs public) and never swap CLI flags.","Check decoded length (64) before invoking the validator.","Store keys in fixed-format files and read them rather than pasting."],"tags":["base64","ed25519","key-validation","cryptography"],"backgroundTag":"invalid-argument-format","analyzedSha":"a7736be5e40f85bfc141120dce587e836e5d4b80","analyzedAt":"2026-09-09T21:56:29.933Z","contentChangedAt":"2026-09-09T21:56:29.933Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}