Repository navigation
Conversation
Introduce an Android counterpart to MASTG-TEST-0211 covering MessageDigest MD5/SHA-1 usage, a semgrep rule on reversed Java, and a MASTestApp demo. Update MASTG-TEST-0014 covered_by. Closes OWASP#3933
Clarify that SHA1 is the same algorithm as SHA-1 and is included because Android code often uses that alias.
Extend the semgrep rule to Guava Hashing and Apache DigestUtils and point testers to MASTG-TECH-0018 for native MD5/SHA-1.
|
Thank you for your contribution! However, this PR does not reference any issues. To contribute to this project, please:
Please reopen this PR once you have linked it to an issue you are assigned to. |
|
Thanks for addressing #3933! A few points before review:
Thanks again for filling this Android coverage gap. |
- Clarify MD5 collision practicality and cite RFC 6151 §2.2 regarding theoretical preimage complexity - Cite SHA-1 is a Shambles for chosen-prefix collisions alongside SHAttered - Update demo SHA-256 PASS case to hash ordinary document data instead of a password (per Password Storage Cheat Sheet) - Clarify contextual validation requirement for non-security MD5 checksums
|
Thanks @cpholguera for reopening the PR! And thank you @phplego for the thorough, high-quality cryptographic review:
Pushed these changes in commit 21df7dc. |
There was a problem hiding this comment.
🟡 Changes recommended
Three moderate Semgrep-rule findings remain, along with documentation and metadata nits.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds an Android counterpart for broken hashing algorithm detection, including a Semgrep rule, test documentation, demo artifacts, and updated coverage metadata.
Changes:
- Adds
MASTG-TEST-0x01mapped toMASWE-0008. - Adds detection for broken hashing APIs and a MASTestApp demo.
- Updates
MASTG-TEST-0014coverage references.
File summaries
| File | Changes and final review findings |
|---|---|
tests/android/MASVS-CRYPTO/MASTG-TEST-0014.md |
Updates coverage references. No final comments. |
tests-beta/android/MASVS-CRYPTO/MASTG-TEST-0x01.md |
Adds the Android hashing test. Nit (3 votes): add required metadata and prerequisites. Nit (1 vote): clarify the security-context condition in the failure sentence. Nit (1 vote): use Hashing.md5 and Hashing.sha1 without parentheses. |
rules/mastg-android-broken-hashing-algorithms.yaml |
Adds Semgrep detections. Moderate (2 votes): support case-insensitive algorithm names and provider overloads. Moderate (1 vote): use the correct Apache Commons getMd5Digest() and getSha1Digest() methods. Moderate (1 vote): support qualified API receivers. |
demos/android/MASVS-CRYPTO/MASTG-DEMO-0x01/run.sh |
Runs Semgrep. No final comments. |
demos/android/MASVS-CRYPTO/MASTG-DEMO-0x01/output.txt |
Stores sample findings. No final comments. |
demos/android/MASVS-CRYPTO/MASTG-DEMO-0x01/MastgTest.kt |
Provides vulnerable and safe examples. No final comments. |
demos/android/MASVS-CRYPTO/MASTG-DEMO-0x01/MastgTest_reversed.java |
Provides reversed Java sample code. No final comments. |
demos/android/MASVS-CRYPTO/MASTG-DEMO-0x01/MASTG-DEMO-0x01.md |
Documents the demo. Nit (2 votes): add Android/platform, IDE, and device environment details. |
Review details
Suppressed comments (4)
rules/mastg-android-broken-hashing-algorithms.yaml:31
- These are not the Apache Commons Codec factory method names:
DigestUtilsexposesgetMd5Digest()andgetSha1Digest(). As written, the rule misses code that obtains a broken digest through those common wrappers and includes patterns that cannot match the actual API; replace these patterns with theget...Digest()calls.
- pattern: DigestUtils.md5Digest(...)
- pattern: DigestUtils.sha1Digest(...)
rules/mastg-android-broken-hashing-algorithms.yaml:14
- These patterns only match a bare
MessageDigestreceiver, so a valid fully qualified call such asjava.security.MessageDigest.getInstance("MD5")is missed by the rule; the same limitation applies to theHashingandDigestUtilsalternatives below. That creates a false negative for an API this test claims to cover, so add qualified-name or type-aware patterns and cover the form in the demo or document it as a limitation.
- pattern: MessageDigest.getInstance("MD2")
- pattern: MessageDigest.getInstance("MD2", ...)
- pattern: MessageDigest.getInstance("MD4")
- pattern: MessageDigest.getInstance("MD4", ...)
- pattern: MessageDigest.getInstance("MD5")
tests-beta/android/MASVS-CRYPTO/MASTG-TEST-0x01.md:45
- The failure sentence treats every occurrence as a failure, but the following block explicitly permits non-security checksums and requires contextual validation. State the security-relevant-context condition here so the test's evaluation does not contradict its own checksum exception.
The test case fails if you can find the use of broken hashing algorithms. For example:
tests-beta/android/MASVS-CRYPTO/MASTG-TEST-0x01.md:30
- These method names are inline identifiers, so the backticks should omit the call parentheses (
Hashing.md5andHashing.sha1), per the project's Markdown identifier rules. Keeping them asHashing.md5()andHashing.sha1()violates the enforced style.
Third-party wrappers such as Guava `Hashing.md5()` / `Hashing.sha1()` and Apache Commons Codec `DigestUtils` may call the same algorithms. Native libraries (for example OpenSSL `MD5_*` / `SHA1_*`) can implement hashing without going through `MessageDigest`.
- Files reviewed: 8/8 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Fix dead NIST SHA-1 announcement URL (404) in MASTG-TEST-0x01 - Support case-insensitive algorithm matching and provider overloads in semgrep rule - Support fully qualified receivers (java.security, Guava, Apache Commons) - Use correct Apache Commons DigestUtils method names (getMd5Digest, getSha1Digest, getDigest) - Add prerequisites metadata to MASTG-TEST-0x01 - Remove parentheses from inline identifiers Hashing.md5 and Hashing.sha1 - Clarify security-relevant context requirement in evaluation failure sentence - Refresh MASTG-DEMO-0x01 output.txt
TheDauntless
left a comment
There was a problem hiding this comment.
Thanks for contributing! I've added some comments, can you take a look?
|
|
||
| Android exposes hash functions through the Java Cryptography Architecture (JCA) [`MessageDigest`](https://developer.android.com/reference/java/security/MessageDigest) class. Applications select an algorithm with `MessageDigest.getInstance`. Overloads either use the first registered provider that implements the requested algorithm or select a provider by name or object. | ||
|
|
||
| Android's `MessageDigest` implementation supports MD5, SHA-1, and the SHA-2 family, including SHA-224, SHA-256, SHA-384, and SHA-512. Algorithm names and aliases are defined by the Java Security Standard Algorithm Names specification. The selected instance exposes its canonical algorithm name and provider through `getAlgorithm` and `getProvider`. |
There was a problem hiding this comment.
This doesn't appear to be true: getAlgorithm returns whatever you specified in getInstance; not the canonical name.
| Some broken hashing algorithms include: | ||
|
|
||
| - **MD5**: Collision attacks are practical (producing collisions in seconds). While preimage attacks remain theoretical (costing ~2^123.4 operations per [RFC 6151 §2.2](https://www.rfc-editor.org/rfc/rfc6151.html#section-2.2)), practical collision attacks and precomputed dictionary/rainbow table lookups make MD5 completely inadequate for cryptographic protection, digital signatures, or credential storage. It is not approved by NIST for cryptographic use. | ||
| - **SHA-1**: Collision attacks are practical: identical-prefix collisions were demonstrated by [SHAttered](https://shattered.io/), and practical chosen-prefix collisions were demonstrated by [SHA-1 is a Shambles](https://sha-mbles.github.io/). NIST has [deprecated and retired SHA-1](https://www.nist.gov/news-events/news/2022/12/nist-retires-sha-1-cryptographic-algorithm) for all cryptographic applications. |
There was a problem hiding this comment.
SHA1 has been disallowed for cryptographic signatures (so not 'all cryptographic applications') with a total ban end of 2030:
"NIST has announced the retirement of SHA-1, with a phase-out deadline of 31 December 2030."
| If an Android app uses broken hashing algorithms such as MD5 or SHA-1 to protect sensitive data (e.g., credentials, tokens, or integrity checks), attackers can exploit practical collision attacks to forge data or leverage high-speed brute-force and dictionary attacks against unsalted or weakly hashed secrets. To test for this, we need to focus on APIs from cryptographic frameworks and libraries that are used to perform hashing operations. | ||
|
|
||
| - **Java Cryptography Architecture (JCA)**: [`MessageDigest.getInstance`](https://developer.android.com/reference/java/security/MessageDigest#getInstance(java.lang.String)) initializes a `MessageDigest` object for hashing. The `algorithm` parameter can be one of the [supported algorithms](https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest). Common JCA names and aliases include: | ||
| - `MD2` |
There was a problem hiding this comment.
Does it make sense to have MD2 and MD4, which aren't supported on Android? (MD4 is included in the regexes)
| - `MD2` | ||
| - `MD5` | ||
| - `SHA-1`, `SHA1`, `SHA` (aliases of SHA-1) | ||
| - `SHA-224` |
There was a problem hiding this comment.
Also only available on specific versions of Android
|
|
||
| // PASS: [MASTG-TEST-0x01] The app hashes non-sensitive file/document data with SHA-256. | ||
| val sha256 = MessageDigest.getInstance("SHA-256") | ||
| val sha256Document = sha256.digest(fileContents.toByteArray(Charsets.UTF_8)).toHex() |
There was a problem hiding this comment.
The code hashes the string readme.txt, not the content of the file. This is not in line with what the documentation / test evaluation says.
Closes #3933
Description
Adds an Android counterpart to MASTG-TEST-0211: Broken Hashing Algorithms.
MASTG-TEST-0014 (v1) is currently marked as covered only by MASTG-TEST-0312, which checks explicit JCA providers and does not evaluate the selected hashing algorithm. A call such as
MessageDigest.getInstance("MD5")is therefore out of scope for the existing v2 tests.This PR adds:
MASTG-TEST-0x01: static/code/manual test mapped to MASWE-0008, with the required prerequisites, knowledge, and best-practice referencesmastg-android-broken-hashing-algorithmsfor reversed Java: case-insensitiveMessageDigest.getInstancematching, including provider overloads and common aliases, plus GuavaHashingand Apache CommonsDigestUtilswrappersMASTG-DEMO-0x01: MASTestApp sample, jadx-reversed Java, Semgrep output, and the exact validation environmentcovered_byupdate on MASTG-TEST-0014Fake IDs (
MASTG-TEST-0x01,MASTG-DEMO-0x01,MASTG-KNOW-0x01, andMASTG-BEST-0x01) follow the project instructions until real IDs are assigned before merge.The demo APK was built with MASTestApp, installed on a Pixel 7 Android Virtual Device running Android 13, and exercised via the Start button. The rule was also checked with lowercase and mixed-case algorithm names, provider overloads, fully qualified receivers, Guava and Apache Commons wrappers, and a SHA-256 negative control. It reports the five broken-hash cases and does not flag SHA-256. Running it on the stored reversed Java reports the expected four findings with no errors.
AI Tool Disclosure
Check exactly one option.
This contribution does not include AI-generated content.
This contribution includes AI-generated content.
AI tools used: xAI Grok and OpenAI Codex
Models and versions: Grok 4.6 and GPT-6
Prompt summary: Draft an Android counterpart to MASTG-TEST-0211 using the MASTG test, demo, and rule writing instructions; validate the sample on MASTestApp reversed Java. Review PR Add Android counterpart to MASTG-TEST-0211 for broken hashing algorithms #3952, implement the remaining review feedback, verify the Semgrep rule with positive and negative controls, run the project checks, and update the PR.
Your mobile security expertise level: high
Author of this PR and all commits: Sevban Dönmez (@jankesec). I reviewed, edited, built, and ran the demo. Commit history has an initial content commit followed by review commits.
Contributor Checklist