{"record":{"id":"ae0e7d0c0682e047","repo":"jwtk/jjwt","slug":"derivedkeybitlength-may-not-exceed-bitsmsg-max-d","errorCode":null,"errorMessage":"derivedKeyBitLength may not exceed ${bitsMsg(MAX_DERIVED_KEY_BIT_LENGTH)}. Specified size: ${bitsMsg(derivedKeyBitLength)}.","messagePattern":"derivedKeyBitLength may not exceed (.+?)\\. Specified size: (.+?)\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/security/ConcatKDF.java","lineNumber":95,"sourceCode":"     * @param otherInfo           any additional party info to be associated with the derived key. May be null/empty.\n     * @return the derived key\n     * @throws UnsupportedKeyException if unable to obtain {@code sharedSecretKey}'s\n     *                                 {@link Key#getEncoded() encoded byte array}.\n     * @throws SecurityException       if unable to perform the necessary {@link MessageDigest} computations to\n     *                                 generate the derived key.\n     */\n    public SecretKey deriveKey(final byte[] Z, final long derivedKeyBitLength, final byte[] otherInfo)\n            throws UnsupportedKeyException, SecurityException {\n\n        // sharedSecretKey argument assertions:\n        Assert.notEmpty(Z, \"Z cannot be null or empty.\");\n\n        // derivedKeyBitLength argument assertions:\n        Assert.isTrue(derivedKeyBitLength > 0, \"derivedKeyBitLength must be a positive integer.\");\n        if (derivedKeyBitLength > MAX_DERIVED_KEY_BIT_LENGTH) {\n            String msg = \"derivedKeyBitLength may not exceed \" + bitsMsg(MAX_DERIVED_KEY_BIT_LENGTH) +\n                    \". Specified size: \" + bitsMsg(derivedKeyBitLength) + \".\";\n            throw new IllegalArgumentException(msg);\n        }\n        final long derivedKeyByteLength = derivedKeyBitLength / Byte.SIZE;\n\n        final byte[] OtherInfo = otherInfo == null ? EMPTY : otherInfo;\n\n        // Section 5.8.1.1, Process step #1:\n        final double repsd = derivedKeyBitLength / (double) this.hashBitLength;\n        final long reps = (long) Math.ceil(repsd);\n        // If repsd didn't result in a whole number, the last derived key byte will be partially filled per\n        // Section 5.8.1.1, Process step #6:\n        final boolean kLastPartial = repsd != (double) reps;\n\n        // Section 5.8.1.1, Process step #2:\n        Assert.state(reps <= MAX_REP_COUNT, \"derivedKeyBitLength is too large.\");\n\n        // Section 5.8.1.1, Process step #3:\n        final byte[] counter = new byte[]{0, 0, 0, 1}; // same as 0x0001L, but no extra step to convert to byte[]\n","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/security/ConcatKDF.java#L77-L113","documentation":"IllegalArgumentException from ConcatKDF.deriveKey when the requested derived key bit length exceeds MAX_DERIVED_KEY_BIT_LENGTH (the library's safety ceiling for NIST SP 800-56A Concat KDF output). The KDF will not produce keys longer than this bound.","triggerScenarios":"Calling ConcatKDF.deriveKey(relatedData, keyBytes, derivedKeyBitLength) with a derivedKeyBitLength larger than the library maximum (must also be a positive multiple representable as bytes).","commonSituations":"Custom key-derivation code requesting, say, 4096-bit derived keys; porting code that used another KDF without length caps; miscomputing bit length by passing byte counts instead of bit counts.","solutions":["Request a derivedKeyBitLength <= MAX_DERIVED_KEY_BIT_LENGTH (check ConcatKDF.MAX_DERIVED_KEY_BIT_LENGTH).","If you need larger keys, derive multiple keys or chain KDFs deliberately.","Confirm you passed bits, not bytes (multiply byte length by 8 correctly, e.g. 256 not 32).","Ensure the value is positive; zero/negative is rejected by the preceding Assert.isTrue."],"exampleFix":"// before\nConcatKDF kdf = new ConcatKDF(jcaDigest);\nSecretKey k = kdf.deriveKey(info, sharedSecret, 8192); // exceeds max\n// after\nSecretKey k = kdf.deriveKey(info, sharedSecret, 256); // within MAX_DERIVED_KEY_BIT_LENGTH","handlingStrategy":"validation","validationCode":"static void checkDerivedLength(int derivedKeyBitLength) {\n    if (derivedKeyBitLength <= 0 || derivedKeyBitLength > ConcatKDF.MAX_DERIVED_KEY_BIT_LENGTH)\n        throw new IllegalArgumentException(\"derivedKeyBitLength out of range\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return kdf.deriveKey(info, sharedSecret, bitLen);\n} catch (IllegalArgumentException e) {\n    throw new IllegalStateException(\"Unsupported derived key length: \" + bitLen, e);\n}","preventionTips":["Read ConcatKDF.MAX_DERIVED_KEY_BIT_LENGTH before choosing a size","Pass bits, not bytes (256 for a 32-byte key)","Clamp or wrap requested lengths in a helper before calling deriveKey"],"tags":["java","jjwt","concat-kdf","key-derivation","jwe"],"backgroundTag":"value-out-of-range","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}