jwtk/jjwt · error · SecurityException

Unable to derive key

Error message

Unable to derive key

What it means

Thrown as a io.jsonwebtoken.SecurityException when PBES2 password-based key derivation fails. The library wraps any exception raised by the JCA SecretKeyFactory (e.g. PBKDF2WithHmacSHA*) used to stretch the caller-supplied Password into an encryption key. It indicates the password-to-key conversion step of a JWE could not be completed, not that the JWT itself is malformed.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/StandardKeyAlgorithms.java:93

                return secretKeyFactory;
            }
        });

        // pre-compute the salt so we don't spend time doing that on each iteration.  Doesn't need to be random for a
        // computation-only test:
        final byte[] rfcSalt = alg.toRfcSalt(alg.generateInputSalt(null));

        // ensure that the bare minimum steps are performed to hash, ensuring our time sampling pertains only to
        // hashing and not ancillary steps needed to setup the hashing/derivation
        return new KeyAlgorithm<Password, Password>() {
            @Override
            public KeyResult getEncryptionKey(KeyRequest<Password> request) throws SecurityException {
                int iterations = request.getHeader().getPbes2Count();
                char[] password = request.getKey().getPassword();
                try {
                    alg.deriveKey(factory, password, rfcSalt, iterations);
                } catch (Exception e) {
                    throw new SecurityException("Unable to derive key", e);
                }
                return null;
            }

            @Override
            public SecretKey getDecryptionKey(DecryptionKeyRequest<Password> request) throws SecurityException {
                throw new UnsupportedOperationException("Not intended to be called.");
            }

            @Override
            public String getId() {
                return alg.getId();
            }
        };
    }

    private static char randomChar() {
        return (char) Randoms.secureRandom().nextInt(Character.MAX_VALUE);

View on GitHub (pinned to fb71496164)

Solutions

  1. Verify the JRE supports the PBKDF2 algorithm (e.g. SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")) and register a provider if not.
  2. Check that the Password passed to Jwts.builder().encryptWith(password, ...) / parser decryptWith has valid non-empty characters.
  3. Inspect the wrapped cause (e.getCause()) to identify the actual JCA failure and fix accordingly.
  4. If on a FIPS or restricted JVM, configure the security policy to permit the required PBKDF2 transformation.

Example fix

// before (may throw on JREs without PBKDF2)
Jwts.parser().decryptWith(password).build().parseEncryptedClaims(token);
// after
try {
    Jwts.parser().decryptWith(password).build().parseEncryptedClaims(token);
} catch (SecurityException e) {
    logger.error("Key derivation failed: " + e.getCause(), e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

try {
    javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
} catch (NoSuchAlgorithmException e) {
    throw new IllegalStateException("JRE lacks PBKDF2 support required for PBES2 JWEs");
}

Type guard

// char[] password != null && password.length > 0 before encryptWith/decryptWith
boolean usablePassword = password != null && password.length > 0;

Try / catch

try {
    Jwts.parser().decryptWith(password).build().parseEncryptedClaims(token);
} catch (SecurityException e) {
    // inspect e.getCause() for the JCA failure
}

Prevention

When it happens

Trigger: Decrypting or encrypting a JWE with a Password key and PBES2 headers (pbes2Count from the header) when the underlying JCA provider cannot run the requested PBKDF2 algorithm, the password/char[] is unusable, or the JRE lacks the algorithm (e.g. older IBM JREs or hardened crypto policies).

Common situations: Running on a JRE without PBKDF2WithHmacSHA256 support, unrestricted-algorithms policies disabled, using a Password with null/blank characters, or provider misconfiguration in restricted environments (FIPS).

Related errors


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/ad2378e8b1094710. Report an issue: GitHub.