{"record":{"id":"cbc48ee8bb055ebd","repo":"quarkusio/quarkus","slug":"salt-length-must-be-exactly-16-bytes","errorCode":null,"errorMessage":"Salt length must be exactly 16 bytes","messagePattern":"Salt length must be exactly 16 bytes","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/elytron-security-common/runtime/src/main/java/io/quarkus/elytron/security/common/BcryptUtil.java","lineNumber":71,"sourceCode":"     * Produces a Modular Crypt Format bcrypt hash of the given password, using the specified salt and the specified iteration\n     * count.\n     *\n     * @param password the password to hash\n     * @param iterationCount the number of iterations to use while hashing\n     * @param salt the salt to use while hashing\n     * @return the Modular Crypt Format bcrypt hash of the given password\n     * @throws NullPointerException if the password or salt are null\n     * @throws IllegalArgumentException if the iterationCount parameter is negative or zero, or if the salt length is not equal\n     *         to 16\n     */\n    public static String bcryptHash(String password, int iterationCount, byte[] salt) {\n        if (iterationCount <= 0) {\n            throw new IllegalArgumentException(\"Iteration count must be greater than zero\");\n        }\n        Objects.requireNonNull(password, \"password is required\");\n        Objects.requireNonNull(salt, \"salt is required\");\n        if (salt.length != BCryptPassword.BCRYPT_SALT_SIZE) {\n            throw new IllegalArgumentException(\"Salt length must be exactly \" + BCryptPassword.BCRYPT_SALT_SIZE + \" bytes\");\n        }\n\n        PasswordFactory passwordFactory;\n        try {\n            passwordFactory = PasswordFactory.getInstance(BCryptPassword.ALGORITHM_BCRYPT, provider);\n        } catch (NoSuchAlgorithmException e) {\n            // can't really happen\n            throw new RuntimeException(e);\n        }\n\n        IteratedSaltedPasswordAlgorithmSpec iteratedAlgorithmSpec = new IteratedSaltedPasswordAlgorithmSpec(iterationCount,\n                salt);\n        EncryptablePasswordSpec encryptableSpec = new EncryptablePasswordSpec(password.toCharArray(), iteratedAlgorithmSpec);\n\n        try {\n            BCryptPassword original = (BCryptPassword) passwordFactory.generatePassword(encryptableSpec);\n            return ModularCrypt.encodeAsString(original);\n        } catch (InvalidKeySpecException e) {","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/elytron-security-common/runtime/src/main/java/io/quarkus/elytron/security/common/BcryptUtil.java#L53-L89","documentation":"BcryptUtil.bcryptHash(password, iterationCount, salt) requires the salt byte array to be exactly BCryptPassword.BCRYPT_SALT_SIZE (16) bytes, matching Elytron's BCrypt specification. Any other length throws IllegalArgumentException, because BCrypt's algorithm fixes the salt size.","triggerScenarios":"Passing a salt generated with a different length — e.g. Base64-decoded string of the wrong size, a 32-byte SHA-256 digest used as salt, or a salt taken from another algorithm's output.","commonSituations":"Generating the salt with new SecureRandom().generateSeed(24) or similar; reusing a salt string stored with encoding that changes its byte length; hard-coding a sample salt shorter than 16 bytes in tests.","solutions":["Generate the salt as exactly 16 random bytes: new SecureRandom().generateSeed(16) or a 16-byte array.","If deriving the salt from a string, decode to exactly 16 bytes or pad/trim deterministically before calling.","Prefer the 1-arg BcryptUtil.bcryptHash(password), which generates a compliant salt internally."],"exampleFix":"// before\nbyte[] salt = new SecureRandom().generateSeed(32);\nString hash = BcryptUtil.bcryptHash(pwd, 10, salt);\n// after\nbyte[] salt = new byte[16];\nnew SecureRandom().nextBytes(salt);\nString hash = BcryptUtil.bcryptHash(pwd, 10, salt);","handlingStrategy":"validation","validationCode":"// ensure a compliant 16-byte salt before hashing\nbyte[] salt = new byte[16];\nnew SecureRandom().nextBytes(salt);\nif (salt.length != 16) throw new IllegalStateException();\nString hash = BcryptUtil.bcryptHash(password, 10, salt);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer BcryptUtil.bcryptHash(password) which generates its own salt.","Always allocate salt arrays of exactly BCryptPassword.BCRYPT_SALT_SIZE (16).","Don't reuse digests (SHA-256 output is 32 bytes) as bcrypt salts.","Document the 16-byte requirement wherever salt generation happens."],"tags":["security","bcrypt","salt","password-hashing"],"backgroundTag":"invalid-argument-value","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}