Skip to content

Composite Hybrid Keys — Troubleshooting Guide

Common issues and solutions when working with quantum-resistant composite cryptography.


Common Errors

Error: "Security level mismatch"

Full error:

{
  "error": "SECURITY_LEVEL_MISMATCH",
  "message": "Classical component security level (3) does not match PQC component security level (1)"
}

Cause: Classical and PQC algorithms have different NIST security levels.

Solution: Use matching security levels:

Security Level Classical PQC KEM PQC Signature
Level 1 X25519 ML-KEM-512 ML-DSA-44
Level 3 (recommended) X25519 ML-KEM-768 ML-DSA-65
Level 5 RSA-4096 ML-KEM-1024 ML-DSA-87

Example fix:

{
  "components": [
    {"role": "classical", "algorithm": "X25519"},
    {"role": "pqc", "algorithm": "ML-KEM-768"}  // Was ML-KEM-512 (Level 1)
  ]
}


Error: "DUALSIGN requires signature algorithms"

Full error:

{
  "error": "INVALID_COMPONENT_TYPE",
  "message": "DUALSIGN mode requires signature algorithms, but received KEM algorithm ML-KEM-768"
}

Cause: Used encryption algorithm (ML-KEM) in DUALSIGN mode which requires signature algorithms.

Solution: Use signature algorithms for DUALSIGN:

{
  "mode": "DUALSIGN",
  "components": [
    {"role": "classical", "algorithm": "Ed25519"},      // Signature
    {"role": "pqc", "algorithm": "ML-DSA-65"}          // Signature (not ML-KEM)
  ]
}

Error: "Cannot decrypt with single component"

Full error:

{
  "error": "AND_DECRYPT_REQUIREMENT_NOT_MET",
  "message": "Composite key requires BOTH classical and PQC components for decryption"
}

Cause: Attempted to decrypt with only one component of a composite key.

Explanation: This is the AND-decrypt security model working correctly. Both components are required.

Solution: Ensure both component private keys are available: - Classical component (X25519, RSA, etc.) - PQC component (ML-KEM)

If key is lost: Data cannot be recovered (by design). Always backup composite keys securely.


Error: "Verification policy not satisfied"

Full error:

{
  "error": "VERIFICATION_POLICY_NOT_MET",
  "message": "Policy ALL requires both signatures valid, but classical signature verification failed"
}

Cause: DUALSIGN verification policy requires both signatures to be valid, but one failed.

Solution: Check verification policy:

Policy Requirement
ALL Both classical AND PQC must verify
ANY At least one must verify
CLASSICAL_REQUIRED Classical must verify (PQC optional)
PQC_REQUIRED PQC must verify (classical optional)

Debugging steps: 1. Verify both component private keys are available 2. Check signature was created with same key 3. Ensure document wasn't modified after signing


Performance Issues

Issue: Slower than expected

Symptom: Composite key operations take ~2-5ms, simple keys take ~3ms.

Expected behavior: Composite keys are ~2.0x slower than simple keys.

Operation Simple ML-KEM Composite (X25519+ML-KEM)
Encryption ~3 ms ~5 ms (1.7x)
Decryption ~3 ms ~5 ms (1.7x)
Signature ~4 ms ~8 ms (2.0x)

This is normal. Composite keys perform two cryptographic operations instead of one.

Mitigation strategies: - Use simple keys for high-frequency operations (>1000 ops/sec) - Use composite keys only for high-value data (10+ year retention) - Enable caching for frequently accessed keys - Use streaming APIs for large files (avoids memory overhead)


Issue: Large ciphertext size

Symptom: Composite key ciphertext is larger than simple key ciphertext.

Explanation: Composite keys use JWE General JSON Serialization (RFC 7516 §7.2) which includes metadata for both components.

Size comparison: - Simple keys: ~1.2× plaintext (compact format) - Composite keys: ~1.3× plaintext (JSON format)

Difference: ~8% larger (minor overhead for enhanced security).

If size is critical: Use simple keys for bandwidth-constrained scenarios or compress ciphertext before transmission.


Format Detection Issues

Issue: Content-Type confusion

Symptom: Client expects compact JWE string but receives JSON object (or vice versa).

Cause: Simple keys use compact format, composite keys use JSON format.

Solution: Detect format using Content-Type header:

EncryptResult result = sdk.encrypt(kid, plaintext);

if ("application/jose+json".equals(result.getContentType())) {
    // Composite key - JSON format
    Map<String, Object> jwe = result.getJweAsMap();
    // Handle as JSON object
} else {
    // Simple key - compact format
    String jwe = result.getJweAsString();
    // Handle as string
}

Auto-detection pattern:

Object jwe = result.getJwe();
if (jwe instanceof Map) {
    // Composite key (JSON)
} else if (jwe instanceof String) {
    // Simple key (compact)
}


Issue: Client-side parsing failure

Symptom: External JOSE library fails to parse composite key output.

Cause: Many JOSE libraries only support compact serialization, not General JSON Serialization.

Solution: 1. Use AnkaSecure SDK (handles both formats automatically) 2. Use JOSE library with General JSON support (e.g., Nimbus JOSE+JWT 9.0+) 3. Keep composite keys server-side (don't expose to external clients)

Interoperability note: Composite keys are designed for AnkaSecure ecosystem. For maximum interoperability with external systems, use simple keys.


Integration Issues

Issue: "Key not found"

Full error:

{
  "error": "KEY_NOT_FOUND",
  "message": "Composite key with kid 'my-composite-key' not found"
}

Debugging steps: 1. Verify key was created successfully:

curl -X GET /api/key-management/keys/my-composite-key

  1. Check key status (must be "active"):

    {
      "kid": "my-composite-key",
      "status": "active"  // Not "retired" or "revoked"
    }
    

  2. Verify tenant context (multi-tenant environments):

  3. Ensure JWT token has correct tenant claim
  4. Keys are tenant-scoped (not shared across tenants)

Issue: Migration from simple to composite fails

Symptom: Re-encryption from simple key to composite key returns error.

Possible causes:

  1. Source key retired: Simple key was retired before migration
  2. Solution: Reactivate source key temporarily

  3. Target key wrong mode: Target key is DUALSIGN but source was encrypted

  4. Solution: Use HYBRID_KEM_COMBINE for encryption migration

  5. Insufficient permissions: API token lacks re-encryption permission

  6. Solution: Request elevated permissions from admin

Correct migration workflow:

# 1. Generate composite key
curl -X POST /api/key-management/composite-keys -d '{
  "kid": "composite-replacement",
  "mode": "HYBRID_KEM_COMBINE",
  "components": [
    {"role": "classical", "algorithm": "X25519"},
    {"role": "pqc", "algorithm": "ML-KEM-768"}
  ]
}'

# 2. Re-encrypt (source must be active)
curl -X POST /api/crypto/re-encrypt -d '{
  "sourceKid": "old-simple-key",
  "targetKid": "composite-replacement",
  "jweToken": "eyJhbGci..."
}'

# 3. Verify
curl -X POST /api/crypto/decrypt-jwe -d '...'


API Errors

HTTP 400 (Bad Request)

Common causes: - Missing required field (kid, mode, components) - Invalid algorithm name (typo: "ML-KEM-786" instead of "ML-KEM-768") - Invalid JSON syntax

Solution: Validate request against API spec before sending.


HTTP 422 (Unprocessable Entity)

Common causes: - Security level mismatch (X25519 + ML-KEM-512) - Wrong component type for mode (KEM in DUALSIGN) - Invalid KDF for combination (unsupported KDF)

Solution: Check error message for specific validation failure.


HTTP 500 (Internal Server Error)

Common causes: - Cryptographic library failure (rare) - HSM unavailability (if using HSM-backed keys) - Database connection issue

Solution: Retry with exponential backoff. If persistent, contact support.


Debugging Techniques

Enable debug logging (SDK)

AnkaSecureSdk sdk = AnkaSecureSdk.builder()
    .baseUrl("https://api.ankatech.co")
    .bearerToken("YOUR_TOKEN")
    .enableDebugLogging(true)  // Logs all requests/responses
    .build();

Output:

[DEBUG] POST /api/key-management/composite-keys
[DEBUG] Request: {"kid": "test-key", "mode": "HYBRID_KEM_COMBINE", ...}
[DEBUG] Response: 201 Created
[DEBUG] {"kid": "test-key", "components": [...]}

Trace correlation IDs

Every API response includes X-Correlation-ID header. Use it to trace request through logs:

curl -v -X POST /api/crypto/encrypt -d '...'
# Response header: X-Correlation-ID: abc123-def456

# Contact support with correlation ID for investigation

FAQ

Q: Do I need to change my code to use composite keys? A: No. The API is transparent — same endpoints as simple keys.

Q: What's the performance impact? A: ~2.0x slower than simple keys (~5ms vs ~3ms per operation). Acceptable for high-value data.

Q: Can I mix simple and composite keys in the same application? A: Yes. Use composite for sensitive data (10+ year retention) and simple for everything else.

Q: How do I detect if a response is from a simple or composite key? A: Check Content-Type header: application/jose (simple) vs application/jose+json (composite).

Q: Can external JOSE libraries decrypt composite key output? A: Only if they support General JSON Serialization (RFC 7516 §7.2). Use AnkaSecure SDK for best compatibility.

Q: What happens if I lose one component of a composite key? A: Data cannot be decrypted (AND-requirement). Always backup both components securely.

Q: Can I migrate from composite back to simple? A: Yes, using re-encryption API. But you lose quantum resistance — not recommended.

Q: How do I test composite keys before production? A: Use sandbox environment with test keys. See Quick Start Guide.


Need Help?

Documentation: - Composite Keys Quick Start - Flow 29 SDK Example - Best Practices

Support: - Email: [email protected] - Include correlation ID from X-Correlation-ID header - Provide full error message and request/response (redact sensitive data)


Document Version 3.0.0 -- updated December 2025 © 2025 ANKATech Solutions INC. All rights reserved.