
How I Reverse-Lookup M-Pesa's Hashed Phone Numbers Using a 7.2 GB Binary File and One S3 Request
At some point, Safaricom quietly changed the M-Pesa Daraja C2B callback payload. The MSISDN field — which used to contain a partially-masked phone number like 2547*****126 — started returning something like this: fc418dcfe94c732a57f109e85e54d6c2e86f7c2afe6a2a5a6a5e5a9a9a9a9a9 A SHA256 hash. No announcement, no migration guide. Your integration just quietly broke. This is how I solved it. The problem SHA256 is a one-way function. You cannot mathematically reverse it. The only way to recover the original phone number is to hash every possible candidate and check for a match. For Kenyan Safaricom numbers the search space is 2547XXXXXXXX and 2541XXXXXXXX — exactly 200 million candidates . Hashing all of them on every callback request takes roughly 2 minutes. That's not a solution, that's a timeout. Why the obvious approaches don't work Approach Lookup time Problem Brute-force per request ~2 min Kills every callback before Safaricom's 5-second timeout SQLite file ~5–50 ms ~15 GB with indexe
Continue reading on Dev.to DevOps
Opens in a new tab


