{"id":28113223,"url":"https://github.com/amdelamar/jhash","last_synced_at":"2026-01-16T06:11:22.170Z","repository":{"id":48139835,"uuid":"90088701","full_name":"amdelamar/jhash","owner":"amdelamar","description":"🔑 Password hashing utility in Java ","archived":false,"fork":false,"pushed_at":"2025-03-02T22:36:19.000Z","size":592,"stargazers_count":71,"open_issues_count":3,"forks_count":8,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-05-14T05:13:08.940Z","etag":null,"topics":["bcrypt","hash","password-hash","pbkdf2","pepper","salt","scrypt"],"latest_commit_sha":null,"homepage":"https://amdelamar.com/jhash","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/amdelamar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-02T23:44:38.000Z","updated_at":"2025-04-21T12:20:51.000Z","dependencies_parsed_at":"2022-07-29T01:18:16.026Z","dependency_job_id":null,"html_url":"https://github.com/amdelamar/jhash","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/amdelamar/jhash","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amdelamar%2Fjhash","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amdelamar%2Fjhash/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amdelamar%2Fjhash/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amdelamar%2Fjhash/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amdelamar","download_url":"https://codeload.github.com/amdelamar/jhash/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amdelamar%2Fjhash/sbom","scorecard":{"id":188885,"data":{"date":"2025-08-11","repo":{"name":"github.com/amdelamar/jhash","commit":"d356009adf8aadb4f61d02d9736ab9ef6e40ed52"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/22 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":9,"reason":"binaries present in source code","details":["Warn: binary detected: gradle/wrapper/gradle-wrapper.jar:1"],"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/master-pull-request.yml:1","Warn: no topLevel permission defined: .github/workflows/master-push.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/master-pull-request.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/amdelamar/jhash/master-pull-request.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/master-push.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/amdelamar/jhash/master-push.yml/master?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v2.2.0 not signed: https://api.github.com/repos/amdelamar/jhash/releases/31635861","Warn: release artifact 2.1.0 not signed: https://api.github.com/repos/amdelamar/jhash/releases/11724842","Warn: release artifact 2.0.0 not signed: https://api.github.com/repos/amdelamar/jhash/releases/8968369","Warn: release artifact v1.1.0 not signed: https://api.github.com/repos/amdelamar/jhash/releases/6747982","Warn: release artifact v2.2.0 does not have provenance: https://api.github.com/repos/amdelamar/jhash/releases/31635861","Warn: release artifact 2.1.0 does not have provenance: https://api.github.com/repos/amdelamar/jhash/releases/11724842","Warn: release artifact 2.0.0 does not have provenance: https://api.github.com/repos/amdelamar/jhash/releases/8968369","Warn: release artifact v1.1.0 does not have provenance: https://api.github.com/repos/amdelamar/jhash/releases/6747982"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 16 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-16T20:16:10.672Z","repository_id":48139835,"created_at":"2025-08-16T20:16:10.673Z","updated_at":"2025-08-16T20:16:10.673Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28477633,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T03:13:13.607Z","status":"ssl_error","status_checked_at":"2026-01-16T03:11:47.863Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bcrypt","hash","password-hash","pbkdf2","pepper","salt","scrypt"],"created_at":"2025-05-14T05:01:33.830Z","updated_at":"2026-01-16T06:11:22.159Z","avatar_url":"https://github.com/amdelamar.png","language":"Java","funding_links":[],"categories":["安全"],"sub_categories":[],"readme":"# Jhash\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.amdelamar/jhash.svg)](https://search.maven.org/search?q=a:jhash)\n[![Javadoc](https://www.javadoc.io/badge/com.amdelamar/jhash.svg)](https://www.javadoc.io/doc/com.amdelamar/jhash)\n[![Build](https://github.com/amdelamar/jhash/actions/workflows/master-push.yml/badge.svg)](https://github.com/amdelamar/jhash/actions/workflows/master-push.yml)\n[![Codecov](https://img.shields.io/codecov/c/github/amdelamar/jhash.svg)](https://codecov.io/gh/amdelamar/jhash)\n\nPassword hashing utility in Java. It can hash passwords with PBKDF2 hmac SHA1/SHA256/SHA512, BCRYPT, or SCRYPT, and it salts automatically and has a pepper option.\n\n\n## Download\n\nMaven:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.amdelamar\u003c/groupId\u003e\n    \u003cartifactId\u003ejhash\u003c/artifactId\u003e\n    \u003cversion\u003e2.2.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nGradle:\n\n```gradle\ndependencies {\n    implementation 'com.amdelamar:jhash:2.2.0'\n}\n```\n\nSBT:\n\n```scala\nlibraryDependencies ++= Seq(\n  \"com.amdelamar\" % \"jhash\" % \"2.2.0\"\n)\n```\n\nOr Download the [latest release](https://github.com/amdelamar/jhash/releases).\n\n\n## Usage\n\nEasy hash and verification...\n\n```java\nimport com.amdelamar.jhash.Hash;\n\nchar[] password = \"Hello World!\".toCharArray();\n\n// salt + hash a password. (pbkdf2 hmac sha1)\nString hash = Hash.password(password).create();\n// Example: pbkdf2sha1:64000:18:24:n:LZXY631xphycV5kaJ2WY0RRDqSfwiZ6L:uOw06jt6FvimXSxEJipYYHsQ\n\n// Save the enitre string somewhere safe...\n\n// Verify Login\nif(Hash.password(password).verify(correctHash)) {\n    // Passwords match. Login successful!\n}\n```\n\nMore Options...\n\n```java\n// pbkdf2 hmac sha512 + salt\nString hash = Hash.password(password).algorithm(Type.PBKDF2_SHA512).create();\n// Returns: pbkdf2sha512:64000:18:24:n:EbroMczUKuBRx5sy+hgFQyHmqk2iNtt5:Ml8pGxc3pYoh1z5fkk5rfjM9\n\n// pbkdf2 hmac sha256 + salt + pepper\nString hash = Hash.password(password).pepper(pepper).algorithm(Type.PBKDF2_SHA256).create();\n// Returns: pbkdf2sha256:64000:18:24:y:J84o+zGuJebtj99FiAMk9pminEBmoEIm:4hoNRxgrn79lxujYIrNUXQd1\n\n// pbkdf2 hmac sha512 + salt + pepper + higher salt length\nString hash = Hash.password(password).pepper(pepper).algorithm(Type.PBKDF2_SHA512).saltLength(36).create();\n// Returns: pbkdf2sha512:64000:18:36:y:v+tqRNA5B4cAxbZ4aUId/hvrR+FlS1d8:/R851fqvd7HItsSr0vJEupBf\n\n// bcrypt + salt\nString hash = Hash.password(password).algorithm(Type.BCRYPT).create();\n// Example: bcrypt:13:66:16:n::$2a$10$YQ9urAM3RKuDtl1XaF99HrdpoIlB6ZhfaGR1T4yS4jlfMSPyeXehE.0Dway\n\n// bcrypt + salt + pepper\nString hash = Hash.password(password).pepper(pepper).algorithm(Type.BCRYPT).create();\n// Example: bcrypt:13:66:16:y::$2a$10$UlxpnyYwYmmlLgl7YVGonN9H74ffEttiD1O2uMy8q5Y7YgJc8.YsRa3yOM6\n\n// scrypt + salt\nString hash = Hash.password(password).algorithm(Type.SCRYPT).create();\n// Example: scrypt:16384:80:24:n::$s0$e0801$+nNFxTV9IHyN0cPKn/ORDA==$uPrBpPBQm7GgX+Vcc/8zuFNJZ+8XqDMylpLrOjv6X8w=\n\n// scrypt + salt + pepper\nString hash = Hash.password(password).pepper(pepper).algorithm(Type.SCRYPT).create();\n// Example: scrypt:16384:80:24:y::$s0$e0801$iHSTF05OtGCb3BiaFTZ3BA==$QANWx2qBzMzONIQEXUJTWnNX+3wynikSkGJdO9QvOx8=\n\n// scrypt + salt + pepper + higher complexity factor\nString hash = Hash.password(password).pepper(pepper).algorithm(Type.SCRYPT).factor(1048576).create();\n// Example: scrypt:16384:80:24:y::$s0$e0801$iHSTF05OtGCb3BiaFTZ3BA==$QANWx2qBzMzONIQEXUJTWnNX+3wynikSkGJdO9QvOx8=\n```\n\nNow verify the passwords match. Even if you use a stronger algorithm, longer salt length, or increase the complexity factor, you don't need to provide that information when you `verify()` because the hash output has those values already. But if you used a pepper, you need to provide that when verifying.\n\n```java\n// Verify Login\nif(Hash.password(password).verify(correctHash)) {\n    // Passwords match. Login successful!\n}\n\n// Provide the pepper if you used one.\n// (This is because the pepper isn't stored with the hash!)\nif(Hash.password(password).pepper(pepper).verify(correctHash)) {\n    // Passwords match. Login successful!\n}\n```\n\n## Hash Format\n\nThe hash format is seven fields separated by the colon (':') character.\n\n`algorithm:factor:hashLength:saltLength:pepper:salt:hash`\n\nExamples:\n\n```\npbkdf2sha1:64000:18:24:n:LZXY631xphycV5kaJ2WY0RRDqSfwiZ6L:uOw06jt6FvimXSxEJipYYHsQ\npbkdf2sha256:64000:18:24:n:ZhxPG2klUysxywJ7NIAhFNTtEKa1U2yu:6oeoGuoQAOIKsztgIgPHTC4/\npbkdf2sha256:64000:18:24:y:8MD0yEl5DKz+8Av2L8985h63BhvVppYU:osTwsDh2qo/wgE6g0BrjdeFt\npbkdf2sha512:64000:18:24:n:EbroMczUKuBRx5sy+hgFQyHmqk2iNtt5:Ml8pGxc3pYoh1z5fkk5rfjM9\npbkdf2sha512:64000:18:24:y:v+tqRNA5B4cAxbZ4aUId/hvrR+FlS1d8:/R851fqvd7HItsSr0vJEupBf\nbcrypt:13:66:16:n::$2a$10$YQ9urAM3RKuDtl1XaF99HrdpoIlB6ZhfaGR1T4yS4jlfMSPyeXehE.0Dway\nbcrypt:13:66:16:y::$2a$10$sdreyOHQW0XAGw.LMXbPyayMMGlMuU69htdw8KXjzk5xOrVTFj2aYLxre7y\nscrypt:131072:24:80:n::$s0$e0801$Evw8WPqcEUy1n3PhZcP9pg==$lRbNPFoOdoBMFT0XUcZUPvIxCY8w+9DkUklXIqCOHks=\nscrypt:131072:24:80:y::$s0$e0801$mzUhOD/ns1JCnwhsYPvIkg==$OlipMfOQJkCm62kY1m79AgIsfPzmIDdgz/fl/68EQ+Y=\n```\n\n- `algorithm` is the name of the cryptographic hash function.\n- `factor` parameter for the function. PBKDF2 number of iterations (64000), BCRYPT number of logrounds (2\u003csup\u003e12\u003c/sup\u003e), SCRYPT cpu/mem cost (131072).\n- `hashLength` is the byte length of the `hash`.\n- `saltLength` is the byte length of the `salt`.\n- `pepper` is an indicator that a pepper was used (\"y\" or \"n\"). Peppers aren't stored with the Hashes. They're stored in the application properties.\n- `salt` is the salt. (Note: BCRYPT and SCRYPT salt is embedded in the hash).\n- `hash` is the raw password hash.\n\n\n## Options and Considerations\n\n#### PBKDF2 Options\n\nYou have three options with PBKDF2 hmac: SHA1, SHA256, or SHA512. Test each before you try them, because not all JVM's support the newer hashing methods. Java 8 added support for PBKDF2 with SHA512 in 2014.\n\nThe default iterations = 64,000 but feel free to increase up to 200,000 depending on your server and cpu cost you want. Run some preliminary tests to find out if your server/device can handle the high number of iterations first. There are lots of applications out there that use anywhere from 1,000 to 10k, or 200k, for their storage.\n\n\n#### BCrypt Options\n\nThe default logrounds = 13 but feel free to increase up to 20 depending on the cpu cost you want. Again, run some preliminary tests to find out if hashes are too quick. You'll want **at least 0.5 seconds** per hash and no faster. Here is a quick estimate:\n\n* 12 = About ~250 ms each hash.\n* 13 = About ~500 ms each hash. :key: default\n* 14 = About ~1 second each hash.\n* 15 = About ~2 seconds each hash.\n* 16 = About ~4.5 seconds each hash.\n\nAlso note that BCrypt has a password limit of 72 characters (18 32-bit words). Be sure to truncate before hashing. Its a limitiation of the Blowfish cipher. BCrypt has a default salt length of 16 to remain compatible with the standard formula, but you can increase this if you wish.\n\n\n#### SCrypt Options\n\nThe default cost = 131072 (2\u003csup\u003e17\u003c/sup\u003e) but you can increase this too. Again, run some preliminary tests to find out if the hashes are computed too quickly. You'll want **at least 0.5 seconds** per hash and no faster. Here is a quick estimate:\n\n* 16384  (2\u003csup\u003e15\u003c/sup\u003e) = About ~100 ms each hash.\n* 131072 (2\u003csup\u003e17\u003c/sup\u003e) = About ~800 ms each hash :key: default\n* 262144  (2\u003csup\u003e18\u003c/sup\u003e) = About ~2 seconds each hash.\n* 1048576 (2\u003csup\u003e20\u003c/sup\u003e) = About ~5 seconds each hash.\n\n\n\n## Details\n\nBy default, if you just call `Hash.password(pwd).create()` it uses PBKDF2 hmac SHA1 with 24 bytes (192 bits) of securely random salt and outputs 18 bytes (144 bits). 144 bits was chosen because it is (1) Less than SHA1's 160-bit output (to avoid unnecessary PBKDF2 overhead), and (2) A multiple of 6 bits, so that the base64 encoding is optimal. PBKDF2 hmac SHA1 was chosen for the default mainly for the most compatibility across Java implementations. Although SHA1 has been cryptographically broken as a collision-resistant function, it is still perfectly safe for password storage with PBKDF2. Its my recommendation though to use algorithms like BCRYPT and SCRYPT. As they are 'memory hard', meaning that they don't just need a lot of CPU power to compute, they also require a lot of memory (unlike PBKDF2). This makes them better against brute-force attacks.\n\n\n## Contribute\n\nA project by [Austin Delamar](https://github.com/amdelamar) based off of [Taylor Hornby](https://github.com/defuse/password-hashing), [Damien Miller](https://github.com/jeremyh/jBCrypt), and [Will Grozer](https://github.com/wg/scrypt)'s work and other [contributors](https://github.com/amdelamar/jhash/graphs/contributors).\n\nIf you'd like to contribute, feel free to fork and make changes, then open a pull request to master branch.\n\n\n## License\n\nJHash is licensed as [Apache-2.0](https://github.com/amdelamar/jhash/blob/master/LICENSE)\n\nPBKDF2 is licensed as [BSD-2-Clause](https://github.com/amdelamar/jhash/blob/master/LICENSE)\n\nBCRYPT is licensed as [ISC](https://github.com/amdelamar/jhash/blob/master/LICENSE)\n\nSCRYPT is licensed as [Apache-2.0](https://github.com/amdelamar/jhash/blob/master/LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famdelamar%2Fjhash","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famdelamar%2Fjhash","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famdelamar%2Fjhash/lists"}