cybersecurity · beginner · ~15 min · safe pentest lab

Flag Weak Cryptographic Algorithms

Practice deny-by-default input validation: match untrusted input against a fixed allow/deny list using a safe, whole-string, bounds-respecting comparison instead of a naive prefix or substring check.

Challenge

Weak-Algorithm Guard

A configuration validator protects an asset: the crypto choices your service is allowed to use. The threat is a developer (or an attacker who can edit config) selecting a broken primitive like MD5, SHA-1, DES, or RC4, silently weakening TLS, password hashing, or token signing. Your job is a deny-by-default allow/deny check: given an algorithm name, decide whether it is a known-weak/broken primitive.

Implement:

int is_weak_algorithm(const char *name);

Return 1 if name matches — case-insensitively — one of the fixed weak primitives md5, sha1, des, 3des, rc4, ecb, md4; otherwise return 0. The comparison must be against the whole string: "sha256" is strong even though it starts with "sha", and "md5sum" is not "md5".

The insecure assumption to avoid is trusting attacker-controlled input length or matching only a prefix. Never read past the terminating NUL, and treat NULL as not-weak (0).

Edge cases

  • NULL input must return 0 (never dereference it).
  • Empty string returns 0.
  • Mixed / upper case ("MD5", "Rc4") still matches.
  • A weak name as a strict prefix or substring of a longer name (e.g. registry entry "md5sum") is not a match.

Example

Given a fixed registry array baked into the harness:

is_weak_algorithm(registry[0])  // "MD5"    -> 1
is_weak_algorithm(registry[1])  // "AES"    -> 0
is_weak_algorithm(registry[4])  // "sha256" -> 0

Input format

A single argument: a NUL-terminated C string name (an algorithm identifier), or NULL. The string is fully attacker-controlled in content and length.

Output format

Return int 1 if name is a known-weak primitive (case-insensitive, whole-string match), otherwise 0. NULL returns 0.

Constraints

C11, freestanding-style function body. Do not allocate. Do not read beyond the terminating NUL of name. Comparison is ASCII case-insensitive over the whole string. The weak set is fixed: md5, sha1, des, 3des, rc4, ecb, md4.

Starter code

int is_weak_algorithm(const char *name)
{
    /* TODO: compare name (case-insensitively, whole string) against the
       weak-primitive list: md5, sha1, des, 3des, rc4, ecb, md4.
       Remember: NULL => 0, and a prefix like "sha" of "sha256" is NOT a match. */
    (void)name;
    return -1;
}

Common mistakes

Dereferencing NULL before the guard; using strncmp/prefix matching so sha256 wrongly flags as sha1; case-sensitive comparison that misses MD5; using strstr so md5sum matches md5; forgetting one list entry (md4 or ecb); reading past the NUL when lengths differ.

Edge cases to handle

NULL pointer -> 0; empty string -> 0; uppercase/mixed case matches (MD5, Rc4); a weak token that is only a prefix or substring of a longer name (sha256, md5sum, des3) must NOT match; exact matches for every listed primitive including the digit-prefixed 3des.

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.