Adding another layer..
In my previous article that talked about beefing up security on public internet facing IOT devices, I mentioned one of a number of potential improvements that I could introduce to my own stuff was two factor authentication. After a little thought I decided to have a go at implementing it.
RFC6238 / Google Authenticator support looked like a good fit for me because it’s a purely mathematical self contained algorithm based on HMAC and epoch time so it’s all done in software with no hardware dependencies. Add to that other people have had a go at it in the past also made it a decent choice.
Two factor authentication strengthens security by adding a second layer of security to systems and devices by it being ‘the thing you have’ i.e. your phone, email address etc. in addition to ‘the thing you know’ i.e. your username/password pair in traditional system authentication. There’s also ‘the thing you are’ i.e. fingerprint, iris recognition, biometrics etc which some systems do support nowadays - some smartphones have a fingerprint scanner.
Systems, platforms and devices implement two factor authentication in different ways, a few examples being:
- a unique code sent via sms
- a code sent via email
- a key fob or card physically inserted into a machine
- use of an application to determine a unique code
Google Authenticator is an implementation of the latter and a number of other applications also support RFC6238 too.
So just what is RFC6238? I could say RTFM but no-one normal likes trying to read and understand RFCs. To be fair this RFC is better than some I’ve suffered because this one actually includes a reference implementation (in java code). RFC6238 basically describes a method where a One Time Password (OTP) can be calculated using a Hashing Message Authentication Code (HMAC) calculated from a secret key and the time at that point in time when the OTP is calculated.
So to calculate an RFC6238 OTP, you need a secret key (really secret, don’t divulge it to anyone) and accurate time wherever you’re calculating the OTP. The Google Authenticator app runs on a smartphone so it has an accurate view of the time so long as the time is correct on the phone. To calculate an OTP on an ESP8266 device, you need either NTP time enabled or some other method of accurately determining the time.
My home grown firmware which has been in incubation for about a year is based on the Arduino Core for ESP8266 so this implementation is in that arena. At the beginning of this mini-project I started out by looking at various pieces of arduino and ESP8266 OTP C/C++ code people had pushed onto github and forums posts here and there. The lack of documentation in these pieces left much to be desired. The code that I came across was also not re-usable in an easy way; it was largely hard welded into sample .ino sketches, some of which looked like it flat-out just didn’t work at all.
Actual good resources included:
- the Google Authenticator source code
I set myself the goal of implementing something reasonably clean in the style of a library that will hopefully be easily re-usable by anyone developing ESP8266 arduino core code and this is the end result:
I’ve included methods to:
- Generate a new secret key 16 bytes long made up of random bytes:
- Convert a secret key to the base32 representation:
- Calculate the TOTP for the secret key at a given epoch point in time:
- Check a user supplied candidate OTP against the device calculated TOTP:
- Render a Google Authenticator compatible QR code:
Dependencies (all on github)
- Arduino.h. This the arduino core project esp8266/arduino https://github.com/esp8266/arduino
- Base32.h, cpp-base32 for base32 functionality https://github.com/jjssoftware/cpp-base32
- sha1.h, Cryptosuite for sha1 and hmac functionality https://github.com/jjssoftware/Cryptosuite
- ESP8266TrueRandom.h, ESP8266TrueRandom for random number functionality https://github.com/jjssoftware/ESP8266TrueRandom
Checkout the sample code here that demonstrates use of this library: https://github.com/jjssoftware/ESP8266TOTP/blob/master/examples/basic.ino
Here’s a bunch of screenshot of this thing implemented in my own firmware:
Security options page link:
TOTP QR code enabled for scanning:
TOTP code confirmed:
TOTP required at logon time:
The obligatory video..
No crappy music here, it’s like most of my vids in silent movie style
Feel free to use ESP8266TOTP in your own stuff if you find it useful / easy to read and use. Code review comments are welcome below thanks :)
Update #1: Github user ccoenen was correct to highlight in issue #1 that it really was a bad idea to depend on / make a request to chart.googleapis.com to render a QR code for the secret key for subsequent scanning into Google Authenticator. This issue is now fixed.