After buying a Garmin Smartwatch, I thought I should be able to check into my gym, LA Fitness, with it. Unfortunately their app uses a rotating QR code, and is only on the apple watch … good thing I’m an engineer!
Step 1: Get a bunch of data
I started by observing the QR code through the mobile app. The first thing I noticed was that the QR code rotated every minute on the minute. I tried signing in with a saved screenshot, but that didn’t work. I had to figure out how they generated new QR codes.
After collecting numberous samples on the minute, every minute, I observed a few trends:
@1 XXXX YYYY ZZZZZ
The immediate quetion was if X was sent by the LA Fitness servers. After putting my phone on airplane mode and restarting the app, I still got QR code generation, so I could determine that the app was generating the value of X itself.
I then plugged in X, Y, and Z into claude, hoping that X was a hash of the already available information. I was not so lucky.
After downloading the LA Fitness APK, I could then reverse engineer their hashing algorithm.
It’s approximately:
digest = HMAC_SHA1(secret_as_int, minutes_since_year_start)
offset = digest[19] & 0x0F
rolling = digest[offset:offset+4] & 0x7FFFFFFF) % 1000000
This might legitimately be the first project I’ve made that improves my life on a daily basis.
You can view the build here!