slackhq/nebula · error

bytes did not contain a proper nebula encrypted Ed25519/ECDS

Error message

bytes did not contain a proper nebula encrypted Ed25519/ECDSA private key banner

What it means

After a PEM block is successfully decoded, DecryptAndUnmarshalSigningPrivateKey checks the PEM block Type against the known encrypted Nebula private key banners (EncryptedEd25519PrivateKeyBanner, EncryptedECDSAP256PrivateKeyBanner). This error means the PEM parsed fine but its type banner is not one of those, so the library refuses to treat it as an encrypted Nebula signing key.

Source

Thrown at cert/crypto.go:269

}

// DecryptAndUnmarshalSigningPrivateKey will try to pem decode and decrypt an Ed25519/ECDSA private key with
// the given passphrase, returning any other bytes b or an error on failure
func DecryptAndUnmarshalSigningPrivateKey(passphrase, b []byte) (Curve, []byte, []byte, error) {
	var curve Curve

	k, r := pem.Decode(b)
	if k == nil {
		return curve, nil, r, fmt.Errorf("input did not contain a valid PEM encoded block")
	}

	switch k.Type {
	case EncryptedEd25519PrivateKeyBanner:
		curve = Curve_CURVE25519
	case EncryptedECDSAP256PrivateKeyBanner:
		curve = Curve_P256
	default:
		return curve, nil, r, fmt.Errorf("bytes did not contain a proper nebula encrypted Ed25519/ECDSA private key banner")
	}

	ned, err := UnmarshalNebulaEncryptedData(k.Bytes)
	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)
	}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Confirm the PEM header is '-----BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY-----' or '-----BEGIN NEBULA ECDSA P256 ENCRYPTED PRIVATE KEY-----'
  2. Pass the correct file: an encrypted Nebula signing private key, not a cert or public key
  3. Regenerate or re-encrypt the key with EncryptAndMarshalSigningPrivateKey / nebula-cert if it has a foreign banner

Example fix

// before
b, _ := os.ReadFile("host.crt") // PEM type CERTIFICATE
k, _, _, err := cert.DecryptAndUnmarshalSigningPrivateKey(pass, b)
// after
b, _ := os.ReadFile("host.key") // PEM type NEBULA ED25519 ENCRYPTED PRIVATE KEY
k, _, _, err := cert.DecryptAndUnmarshalSigningPrivateKey(pass, b)
Defensive patterns

Strategy: validation

Validate before calling

func isEncryptedSigningKey(b []byte) bool {
	blk, _ := pem.Decode(b)
	if blk == nil {
		return false
	}
	switch blk.Type {
	case cert.EncryptedEd25519PrivateKeyBanner, cert.EncryptedECDSAP256PrivateKeyBanner:
		return true
	}
	return false
}

Try / catch

curve, key, rest, err := cert.DecryptAndUnmarshalSigningPrivateKey(pass, b)
if err != nil {
	if strings.Contains(err.Error(), "proper nebula encrypted") {
		return fmt.Errorf("wrong PEM type for encrypted signing key (got a different banner); check you are using the private key file: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling DecryptAndUnmarshalSigningPrivateKey with a PEM block whose Type is e.g. 'CERTIFICATE', 'NEBULA X25519 PUBLIC KEY', 'OPENVPN PRIVATE KEY', or any unencrypted/foreign key banner instead of the encrypted Ed25519/ECDSA private key banner.

Common situations: Passing a certificate or public key PEM where the encrypted private key is expected, using an OpenSSL-generated key file instead of one from nebula-cert, or a key file from an older/other tool with a different banner naming.

Related errors


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