rustdesk/rustdesk-server · error

Invalid Secret key

Error message

Invalid Secret key

What it means

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.

Solutions

  1. Ensure you pass the SECRET key (decodes to exactly 64 bytes) to -k, not the public key.
  2. Check decoded length: `echo '<sk>' | base64 -d | wc -c` must print 64.
  3. Regenerate the keypair with the bundled key generator and use the freshly printed 'Secret Key' value.

Example fix

// before: public key (32 bytes) passed as secret
hbbs --doctor -k 'OeVuKk5nlHiXp+ApNYY=...' // 32-byte pk
// after: the 64-byte secret key
hbbs --doctor -k '<64-byte-base64-secret-key>'
Defensive patterns

Strategy: validation

Validate before calling

let decoded = base64::decode(sk.trim())?;
assert_eq!(decoded.len(), 64, "Ed25519 secret key must decode to 64 bytes, got {}", decoded.len());

Type guard

fn is_secret_key_b64(s: &str) -> bool { base64::decode(s).map(|b| b.len() == 64).unwrap_or(false) }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of rustdesk/rustdesk-server@a7736be5e4 (2026-09-09). Data as JSON: /api/errors/cc3a5c3eb6775a6a. Report an issue: GitHub.

Appendix: source

Thrown at src/utils.rs:44

fn gen_keypair() {
    let (pk, sk) = sign::gen_keypair();
    let public_key = base64::encode(pk);
    let secret_key = base64::encode(sk);
    println!("Public Key:  {public_key}");
    println!("Secret Key:  {secret_key}");
}

fn validate_keypair(pk: &str, sk: &str) -> ResultType<()> {
    let sk1 = base64::decode(sk);
    if sk1.is_err() {
        bail!("Invalid secret key");
    }
    let sk1 = sk1.unwrap();

    let secret_key = sign::SecretKey::from_slice(sk1.as_slice());
    if secret_key.is_none() {
        bail!("Invalid Secret key");
    }
    let secret_key = secret_key.unwrap();

    let pk1 = base64::decode(pk);
    if pk1.is_err() {
        bail!("Invalid public key");
    }
    let pk1 = pk1.unwrap();

    let public_key = sign::PublicKey::from_slice(pk1.as_slice());
    if public_key.is_none() {
        bail!("Invalid Public key");
    }
    let public_key = public_key.unwrap();

    let random_data_to_test = b"This is meh.";
    let signed_data = sign::sign(random_data_to_test, &secret_key);
    let verified_data = sign::verify(&signed_data, &public_key);

View on GitHub (pinned to a7736be5e4)