Multi-Factor Authentication for People Who Lose Their Phone A Lot

Published on Thu, 25 March, 2021 | 1400 words
Tags: hardware raspberry pi mqtt python sms security mfa

I’m torn on multi-factor authentication. I think it’s a good idea, but it’s usually poorly executed. The biggest bug-bear I have with it is that it almost always involves me having a phone with me.

I know I’m in the minority, but I don’t have easy access to a phone for about 60% of the time I’m awake. I regularly leave my phone at home when I go out, usually through forgetfulness, but also because I just don’t have the deep connection to my phone that so many other people seem to have. When I worked in an office my phone spent most of the day locked in the drawer. Since I’ve been working from home I always know it’s in the house because I can ping it on the local network, but it could be in any one of a number of places in multiple rooms. So this world we’re in the process of creating, in which you need to be able to receive a text message at any given time, just isn’t compatible with my lifestyle.

Perhaps a more serious reason why I don’t like mobile phones being used as methods of security is the fact that you need to give your phone number to a third party in advance in order for them to use it to verify you. Facebook have already been caught using people’s mobile numbers - entrusted to them specifically as MFA methods - to profile them for the purposes of selling them advertising, and I’m certain other companies do the same and just haven’t been caught yet. I’m very aware of the value of my personal data and I don’t give it up easily.

The final reason is, of course, that SMS isn’t actually secure, or reliable. Messages are sent as plaintext (ie not encrypted) and are not guaranteed to arrive at all, as anyone who has ever tried to send a text on new year’s eve will tell you. Pretty much every other communication method - with the possible exception of carrier pigeon - is better than SMS. The fact that some banks use SMS to authenticate people for the purpose of making large financial transactions just blows my mind.

My employer recently decreed that multi-factor authentication will become mandatory when logging into any of their systems in the near future. Like most of the things the IT department do these days, they’ve outsourced it to Microsoft. I’m given three options as my extra factor: install a smartphone app, confirm via phone call to my desk phone, or SMS. The app isn’t available on F-Droid, I don’t have the Google Play Store on my phone, and obviously the pandemic makes the desk phone option impossible. I am not listing my personal phone number as my desk phone; even if I did have my phone with me all the time, I’m not paid enough to effectively be on call 24/7. So the SMS option is the lesser of three evils for me. I’m not entirely happy with having to give my mobile number to Microsoft in order to continue working at my current employer, but at least they’ve got a better track record than Facebook when it comes to abusing personal data. But am I now doomed to a future of having to search the entire house for my phone every time I want to log into Sharepoint? Or is there some way of building a system that allows the authentication system to send me a one-time code via SMS that I receive via a method more convenient to my way of working?

My doorbell uses Twilio to send me a text message when someone is at the door, but I’ve been wondering for a while if it’s possible to send the text message directly rather than go through an outside service. Because of this I had recently became aware of Huawei’s range of USB 4G modems. These are mainly used by laptop users who want to access the internet while not in range of wifi, but they can also send and receive messages via SMS. So I bought myself a couple, and some burner PAYG SIMs, and began trying to get a Raspberry Pi to send and receive text messages.

It turns out there are two different types of USB modem manufactured by Huawei: serial modem type and “Hilink” type, which effectively shows up as an ethernet device and acts as a network router and internet gateway, much like your home broadband router does. Getting an older serial model is essential if following most of the guides online, but this is getting trickier as all the newer devices are Hilink. No matter though, as it turns out, it’s possible to send and receive messages programmatically with either type.

The other thing to note about a lot of the USB 4G modems is that they come with drivers pre-loaded. It’s quite a crafty mechanism. They’re designed for Windows PCs, so when you first plug them in they’re in mass storage mode and show up as a drive containing the driver software. Once you install and run the software, the software sends the modem a signal that causes it to switch to modem mode. So in order to use the thing on a Raspberry Pi or other Linux box, you need to trigger the switch yourself. The simplest way is to actually install the thing on a Windows box, wait for the switch to happen and then plug the newly-switched device into the machine you actually want to use. However there is a software package called usb-modeswitch, which can be installed via apt-get on Raspbian.

A Raspberry Pi with a Huawei 4G modem poking out of the USB port

The other two pieces of software that helped me do what I wanted to do were paho-mqtt, a Python library for publishing to MQTT brokers, and huawei-lte-api, a library that wraps the web interface of the Hilink modems into an easy Python interface. I’ve yet to package my code into anything remotely friendly, but currently I have the following script running every minute from cron…

from huawei_lte_api.Client import Client
from huawei_lte_api.Connection import Connection
from huawei_lte_api.enums.sms import *
import paho.mqtt.client as mqtt
import json, time

config = {"modem_address": "", "mqtt_address": "trypticon", "mqtt_topic": "sms/notify/kickback"}
done = 0

while done == 0:

        conn = Connection('http://' + config['modem_address'] + '/')
        client = Client(conn)
        ret = {}

        while True:

                sms = client.sms.get_sms_list(1, BoxTypeEnum.LOCAL_INBOX, 1, 0, 0, 1)

                if int(sms['Messages']['Message']['Smstat']) == 1:

                ret = sms['Messages']['Message']


        text = json.dumps(ret)
        if len(ret) == 0:
                done = 1
                        broker = mqtt.Client('sms')
                        broker.publish(config['mqtt_topic'], text)
                        done = 1

        if done == 0:

This script creates a connection to the modem’s web interface, and checks for the latest unread message. If it finds one, it marks it read and publishes it as a JSON object to the MQTT broker before waiting 3 seconds and going back for another try. It stops when there are no more messages. I guess if you get over 20 messages per minute this script shouldn’t be called every minute from cron, but if you get that many messages then you probably have bigger problems to worry about.

So what now? Well, I have a window open on my desktop all the time just viewing the MQTT log, so I’m alerted to new messages requesting authenticaton that way, but I can theoretically do anything I like now I’ve got the authentication tokens in ‘my space’. Perhaps I’ll buy one of those basketball scoreboards and have it show auth codes as they’re sent. I have an old Adafruit ticket printer, it’d be fun (if a little environmentally unsustainable) to have that print the auth codes for me. Watch this space for whatever dumb idea I come up with. Rest assured, however, no idea will be more dumb than authenticating financial transactions by SMS.