Skip to content

Enhance Cryptographic failures module#596

Open
aashpis wants to merge 38 commits intoSasanLabs:masterfrom
aashpis:master
Open

Enhance Cryptographic failures module#596
aashpis wants to merge 38 commits intoSasanLabs:masterfrom
aashpis:master

Conversation

@aashpis
Copy link
Copy Markdown

@aashpis aashpis commented Apr 24, 2026

Reordered and added new levels, now 1-11, to the Cryptographic failures module according to issue 523.

Additional methods have been added to PasswordHashingUtils for new levels

EncryptionUtils was created as part of the internal.utility package and contains methods related to encryption.

Descriptions for new levels were added to message.properties

New Level Order:

  1. plaintext storage
  2. Base64 encoding is not encryption
  3. Caesar Cipher
  4. Security By Obscurity/Custom logic
  5. MD4 Hash
  6. MD5 Hash
  7. SHA-1 Hash
  8. LM Hash
  9. Unsalted SHA-256
  10. AES with weak key
  11. Secure example: Bcrypt

aashpis and others added 30 commits March 31, 2026 20:36
# Conflicts:
#	src/main/java/org/sasanlabs/service/vulnerability/cryptographicFailures/CryptographicFailuresVulnerability.java
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 24, 2026

Codecov Report

❌ Patch coverage is 0.82645% with 120 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.59%. Comparing base (e3e88be) to head (5bf2e7b).
⚠️ Report is 4 commits behind head on master.

Files with missing lines Patch % Lines
...icFailures/CryptographicFailuresVulnerability.java 0.00% 60 Missing ⚠️
...sanlabs/internal/utility/PasswordHashingUtils.java 2.85% 34 Missing ⚠️
...rg/sasanlabs/internal/utility/EncryptionUtils.java 0.00% 26 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master     #596      +/-   ##
============================================
- Coverage     51.21%   49.59%   -1.63%     
- Complexity      465      466       +1     
============================================
  Files            70       71       +1     
  Lines          2718     2809      +91     
  Branches        287      301      +14     
============================================
+ Hits           1392     1393       +1     
- Misses         1195     1285      +90     
  Partials        131      131              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

LEVEL5_HASH = bytesToHex(hash);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("SHA-256 not available", e);
private static final String LEVEL1_SECRET = "letmein";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should create a table and insert secrets in the table and let user find it out by looking at the table. The challenge should not say what is the secret like in our case level 1 is showing the password. Look at Authentication Vulnerability, we just want to tell user to find out the secret by looking at database. Example:

Image

// Vulnerable: password is exposed in plaintext in the API response
return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(
"CHALLENGE: The system stores passwords in plaintext."
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This challenge should be that password is stored as plain text, look at database to findout what is the password and crack it.

if (password == null || password.isEmpty()) {
return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(
"CHALLENGE: The system 'encrypts' passwords using Base64 encoding."
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont tell it is base64 encoded, let user find it out. The hint should tell it is base64 encoded. i.e.

Image

if (password == null || password.isEmpty()) {
return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(
"CHALLENGE: A user's password is encrypted with a Caesar cipher:"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dont tell it is caesar cipher in challenge. Challenge is finding out password. Hint should tell it is Caesar cipher

private static final String LEVEL2_ENCODED =
Base64.getEncoder().encodeToString(LEVEL2_SECRET.getBytes());

private static final String LEVEL3_SECRET = "helloworld";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to make the secrets little more complex ?

private static final String LEVEL3_ENCRYPTED =
EncryptionUtils.caesarCipher(LEVEL3_SECRET, LEVEL3_CHAR_SHIFT);

private static final String LEVEL4_SECRET = "obscuredpassword";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make it a bit complex

if (password == null || password.isEmpty()) {
return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(
"CHALLENGE: A user's password is stored using custom logic: "
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great !!! we need challenge for user.

if (password == null || password.isEmpty()) {
return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(
"CHALLENGE: A user's password is stored as MD4 hash: "
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great !!!

private static final String LEVEL4_SECRET = "obscuredpassword";
private static final String LEVEL4_ENCRYPTED = EncryptionUtils.customCipher(LEVEL4_SECRET);

private static final String LEVEL5_SECRET = "password123";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make secret really strong in this case.

private static final String LEVEL5_SECRET = "password123";
private static final String LEVEL5_HASH = PasswordHashingUtils.md4Hash(LEVEL5_SECRET);

private static final String LEVEL6_SECRET = "password123";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each level password should be different from other levels.

+ LEVEL3_SECRET
+ " — Enter it below to authenticate!",
false),
"SECURE: This password is hashed with LM. Hash: "
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be CHALLENGE not SECURE

private static final String LEVEL7_SECRET = "admin";
private static final String LEVEL7_HASH = DigestUtils.sha1Hex(LEVEL7_SECRET);

private static final String LEVEL8_SECRET = "admin123";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make it little complex secret

private static final String LEVEL8_SECRET = "admin123";
private static final String LEVEL8_HASH = PasswordHashingUtils.lmHash(LEVEL8_SECRET);

private static final String LEVEL9_SECRET = "qwertyuiop";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add few numbers too as that adds complexity.

return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(
"Incorrect. Hint: Think of common passwords '"
+ LEVEL_10_SECRET
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should not return secret.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

Secret should not be told to user on failure.

EncryptionUtils.encrypt(
LEVEL_10_SECRET, EncryptionUtils.getKeyFromPassword(LEVEL_10_SECRET));

private static final String LEVEL11_SECRET = "uncrackablePassword";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this passwrod random generated on each run as this is very secure and we want to tell that no one can guess this.

} else {
return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(
"Incorrect. Hint: Base64 is not encryption — try decoding '"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tell it is incorrect. let user user hint section to find out that base64 is used.

return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(
"Incorrect. The password has been shifted "
+ LEVEL3_CHAR_SHIFT
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont tell the shift size. let user find it out using hint. just tell that the password is incorrect.

} else {
return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(
"Incorrect. "
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good hiding. Api should return just this.

return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>(
"Incorrect. Your input hashed to: "
+ guessHash
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great !!!! telling guessHash is good as user gets some information using this.

Copy link
Copy Markdown
Member

@preetkaran20 preetkaran20 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall PR looks great. Just some small comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants