slackhq/nebula · error

key was not %d bytes, is invalid ed25519 private key

Error message

key was not %d bytes, is invalid ed25519 private key

What it means

After decrypting the payload for a Curve_CURVE25519 (Ed25519) key, the library validates that the plaintext is exactly ed25519.PrivateKeySize (64) bytes. If decryption yielded the wrong length, the plaintext cannot be a valid Ed25519 private key and this error is returned.

Source

Thrown at cert/crypto.go:291

	if err != nil {
		return curve, nil, r, err
	}

	var bytes []byte
	switch ned.EncryptionMetadata.EncryptionAlgorithm {
	case "AES-256-GCM":
		bytes, err = aes256Decrypt(passphrase, &ned.EncryptionMetadata.Argon2Parameters, ned.Ciphertext)
		if err != nil {
			return curve, nil, r, err
		}
	default:
		return curve, nil, r, fmt.Errorf("unsupported encryption algorithm: %s", ned.EncryptionMetadata.EncryptionAlgorithm)
	}

	switch curve {
	case Curve_CURVE25519:
		if len(bytes) != ed25519.PrivateKeySize {
			return curve, nil, r, fmt.Errorf("key was not %d bytes, is invalid ed25519 private key", ed25519.PrivateKeySize)
		}
	case Curve_P256:
		if len(bytes) != 32 {
			return curve, nil, r, fmt.Errorf("key was not 32 bytes, is invalid ECDSA P256 private key")
		}
	}

	return curve, bytes, r, nil
}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Re-obtain or re-copy the encrypted key file — it is likely truncated or corrupted
  2. If a wrong passphrase is involved, verify the passphrase; though AEAD auth normally fails earlier, validate the source key
  3. Regenerate the signing key with nebula-cert and re-sign affected certificates
Defensive patterns

Strategy: try-catch

Try / catch

curve, key, rest, err := cert.DecryptAndUnmarshalSigningPrivateKey(pass, b)
if err != nil {
	if strings.Contains(err.Error(), "invalid ed25519 private key") {
		return fmt.Errorf("decrypted Ed25519 key has wrong length; key file is corrupt or truncated, restore from backup: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: DecryptAndUnmarshalSigningPrivateKey with an Ed25519 banner whose decrypted ciphertext is not 64 bytes — caused by a wrong passphrase producing garbage (though AEAD should usually fail first), a truncated/corrupted key file, or ciphertext that was re-encrypted from wrong-length plaintext.

Common situations: Truncated key files from bad transfer/storage, corrupted ciphertext, or mismatched key material produced by buggy tooling.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/47ab0e3c6a923c4c. Report an issue: GitHub.