High‑performance, single‑file C tool for double brute‑force of RADIUS PAP: it can brute‑force both the shared secret (S) and the user password (P) from an Access‑Request, cross‑checking candidates against the first‑block relation C1 = P1 XOR MD5(S || RA), where RA is the 16‑byte Request Authenticator and P1 is the first 16 bytes of the zero‑padded password. The engine automatically chooses the most efficient search direction (brute‑force S while scanning a small password list, or brute‑force P while scanning a small secret list), minimizing MD5 calls and turning the hot path into 16‑byte comparisons. To keep wall‑clock time low on huge wordlists, it uses memory‑mapped I/O with sequential readahead and per‑thread byte‑range chunking (no shared FILE* contention). On Apple Silicon/macOS it’s optimized for Clang/LTO and leverages fast MD5 implementations, but it remains portable C and can be built on other Unix‑like systems with OpenSSL available.
Re‑implemented natively in C (mmap, LTO, OpenSSL MD5 on AArch64) based on the logic from TheTiinko/Radius_PAP_Password_Decryptor (Python), credit and thanks to the original author for the reference workflow.
- TheTiinko reference:
- Apple Silicon offers strong single‑thread performance and unified memory, which pairs well with memory‑mapped sequential scans of large wordlists.
- OpenSSL on arm64 includes AArch64 assembly for MD5 that meaningfully boosts throughput for digest batches versus generic implementations on M1/M2 class CPUs.
Install OpenSSL if needed:
brew install openssl@3
Compile with Clang:
clang -O3 -ffast-math -flto -std=c11 radius_brute_opt.c -I/opt/homebrew/opt/openssl@3/include -L/opt/homebrew/opt/openssl@3/lib -lcrypto -pthread -o radius_brute_opt
-O3 -ffast-math -flto provides aggressive optimization without current -Ofast deprecation warnings in recent Clang toolchains.
./radius_brute_opt passwords.txt secrets.txt
The program auto‑selects direction to minimize hashing: if secrets are fewer, it precomputes Tj = E XOR MD5(Sj || RA) once per secret and scans the huge password list via mmap with only 16‑byte comparisons per line, and vice versa if passwords are fewer.
These constants are built into the source to let you verify a known pair end‑to‑end:
- Authenticator (RA):
acf627289be7e214c8e328d0d01fcea2 - User‑Password (E/C1):
fe18a76eec4abeeea09eb90e99b359f7
With wordlists containing:
- Password:
Passw0rd2 - Shared secret:
password2
You should see:
Success!!
Password: Passw0rd2
Shared secret: password2
Done!
This matches the first‑block PAP relation C1 = P1 XOR MD5(S || RA) for ≤16‑byte password inputs per RFC 2865 section on User‑Password encoding.
- The largest win is cutting MD5 calls from
P × Stomin(P, S), reducing the hot path to a 16‑byte compare, which aligns directly with the PAP formula for the first block. - mmap +
madvise(MADV_SEQUENTIAL|MADV_WILLNEED)drastically reduces small read()/lock contention and system time when scanning very large files on macOS, especially versus sharing one stdio stream across threads. - OpenSSL’s arm64 MD5 assembly lifts digest throughput for the batch that remains after precomputation, which matters when secrets are numerous and passwords are few.
For passwords >16 bytes, subsequent blocks chain as Ci = Pi XOR MD5(S || Ci-1) and can be added following the same precompute‑and‑compare strategy with careful handling of the chaining value per block as defined in the RFC.