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:

Google Authenticator is an implementation of the latter and a number of other applications also support RFC6238 too.

RFC6238..what the?

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.

The implementation

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:

  1. this javascript implementation
  2. 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:

  1. Generate a new secret key 16 bytes long made up of random bytes: GetNewKey
  2. Convert a secret key to the base32 representation: GetBase32Key
  3. Calculate the TOTP for the secret key at a given epoch point in time: GetTOTPToken
  4. Check a user supplied candidate OTP against the device calculated TOTP: IsTokenValid
  5. Render a Google Authenticator compatible QR code: GetQrCodeImageUri

Dependencies (all on github)

Sample usage

Checkout the sample code here that demonstrates use of this library: https://github.com/jjssoftware/ESP8266TOTP/blob/master/examples/basic.ino

Screenshots

Here’s a bunch of screenshot of this thing implemented in my own firmware:

Security options page link:

TOTP deactivated:

TOTP QR code enabled for scanning:

TOTP code confirmed:

Google Authenticator:

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 :)

Updates

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.

As a result of this change to ESP8266TOTP, I’ve updated my own implementation to render the QR code in javascript using https://github.com/lrsjng/jquery-qrcode and this is working well for me. As an alternative you might choose to generate the QR code on the ESP8266.