WOGSD: Introducing Waluthy, an open source, CLI-based Authy client
Winter of Getting Stuff Done is a seasonal theme I have set for Winter Season of 2020, based on CGP Grey's video. It's about getting stuff that I wanted to finish for some time done and not jumping onto new ideas all the time.
I've been meaning to figure out a promising alternative to Authy ever since Chrome Apps got killed back in 2017, especially as that was the only way to use Authy on a desktop computer back then.
Since then, Authy made their own electron app, which is the same thing as the chrome app, it just runs a separate chromium instance.
Initially, this covered my needs. I could access my tokens on my laptop, and that's sort of all I asked for.
But each time I launched it, waited for a couple seconds for it to load, scrambled in it to find the right entry, hit copy, alt-tabbed, pasted, alt-tabbed again and shut down Authy Desktop, I died a bit more inside. It just took too long, and required way too much interaction. Surely, there must be a better way to do this, right?
Sadly, I couldn't find any. So I took my time reverse engineering Authy, and hackily reimplemented the parts I needed to get it to work. It took me a weekend, but I had it done back in November and I did find a crypto weakness (more on that later), though I hadn't implemented everything back then. Notably, while I had code for Authy OTP generation, I hadn't actually implemented the API for it, especially as it had a more sophisticated sync mechanism.
Still, out of dozens of keys, only 3 required use me to launch Authy's desktop app, which was good enough. And I could just drop to a terminal, type
cauthy hetz and I'd immediately have Hetzner's TOTP code in my clipboard.
Sadly (and thankfully), the “died inside more as I did this” thing still happened ever time I had to do it. I wanted to implement other stuff I wanted to implement, but my laziness kept winning.
Until today (well, yesterday).
Yesterday night, I sat down and started implementing more and more APIs.
After an hour or two, I got far enough that I was able to do authentication:
After a short break, I returned and implemented Authy TOTPs:
I asked for a better name for the project than “authy-cli”, especially as I wanted to make it clear that it's not affiliated with Authy, so I asked in our discord guild. This particular reply led to the cursed name of the project:
After this I extended argparser support so that I could have authentication, sync and token copying etc done from one single script, and finally implemented an interactive authentication:
And I silently released it around UTC+3 4AM. The release was silent mostly because I wanted to get some more work done on it before I posted it (also I wanted this blog post done).
Today, I went back and fixed a couple bugs, moved accounts into config file and implemented a local encryption feature (hopefully without the same crypto weaknesses I detailed below) so that data isn't stored plaintext.
I think it's ready enough for me to make a less-silent release, so here it is. The louder release of Waluthy.
The (Small) Crypto Weaknesses
Basically, there's 2 weaknesses that I spotted, both related to the “Backup Password” feature:
The IV is 0x00*16, effectively meaning that their AES-128-CBC is actually AES-128-ECB.
The key is derived using PBKDF2 HMAC using user's password, which is good. However, depending on the settings you use, it can be a make or break. Authy uses SHA1 with 1000 rounds.
Going by this old, 2017 gist, you can get upwards of 101.3 GH/s with a 8x1080Ti rig, which, if I'm interpreting stuff properly, means around 100M password attempts per second.
Neither of these are big issues, but all in all I do not trust the backup password feature to protect my TOTP tokens anymore in the event that my Authy account (or Authy servers) get breached.
Why didn't I report these to Authy, you might ask. Simple: They're owned by Twilio, and their bugcrowd is shared with Twilio. While it is in scope...
It is considered “Other”, which means that I'd practically get no bounty nor kudos for this:
I'm fine with that, it's a free service without ads or in-app purchases after all, but...
Yeah, no, that's not okay. Users deserve to know that this is the case, or if it gets fixed, was the case.