TOTP without a smartphone

When I decided to get rid of the need to constantly carry a smartphone with me, one of the problems turned out to be two-factor authentication (2FA, Google Authenticator app). It was unacceptable to be left without the ability to log in to multiple services; an alternative was needed.

A quick search brought me to the utility oathtool: command line, POSIX, O.S.S. – everything is as I like it, the problem is basically solved. But like most CLI utilities, it is convenient to use it in combination with other utilities, and for this it is useful to write a script framework. Actually, I decided to share this harness, as well as my experience of using it.

About 2FA in general and TOTP in particular

Registration in the system using a login/password pair is the oldest, most common and, perhaps, the most criticized authentication method. Actually, I was prompted to write this article by the publication Why are passwords hopelessly outdated and why are they still used? and especially the comments to it.

Why is password authentication bad (more precisely, what are its main problems)? Firstly, this is the notorious human factor — weak passwords, one password for many resources, and the like. Secondly, this is a long lifespan of passwords – few people voluntarily change them often enough, and over time, the chances of leakage in various ways only increase.

The idea has long been born to support password authentication with something else. The “answer to the security question” came from the banking sector, but in essence it was like a second password, weak and long-lived. But one-time passwords (OTP) this was already significantly better. At first, they were sent via SMS or in the form of a hard copy (a printed list of a dozen or two codes; when exhausted, you had to get a new one) – this was not always convenient, not always safe, and not always free.

It turned out to be a good idea to generate OTP simultaneously on the server and client sides based on a certain shared secret (shared secret) and a constantly increasing number (for example, a counter of registration attempts). Of these two entities, they clearly constituted message (message) and then using the SHA-1 hash function to obtain HMAC. This is how it appeared HOTP (described in RFC 4226December 2005).

HOTP turned out to have two imperfections: possible desynchronization of the counter (on the client side, generation can be called more often than successful authentications were performed; re-synchronization is discussed in §7.4 of the RFC) and an unlimited lifetime of OTP (could pose a threat when using phishing “pads”). And then an expansion was proposed TOTP (described in RFC 6238May 2011).

In this extension, it was proposed to take the current UNIX time (the number of seconds that have passed since 01/01/1970 00:00:00 UTC) divided by the length of the OTP validity interval (30 seconds by default) as an ever-increasing number. Thus, if the clocks on the server and client are synchronized (a few seconds back and forth do not matter), then with the same shared secret the generated TOTP values ​​will match – which is what is required authentication confirmation!

Formulation of the problem

Of course, if available oathtool TOTP generation is possible immediately, directly:

$ oathtool -b -t SKEY

But it is better to store the initialization key encrypted and transmit it not on the command line, but through a pipeline. In the manual for oathtool There is a recipe on how to organize this using GNU Privacy Guard (gpg):

$ gpg --decrypt --quiet ~/.my-totp-secret.asc | oathtool --totp -

We could stop here, but besides the need to remember / type a lot of letters, there is another TOTP-specific feature: with a standard time slice of 30 seconds, you can start generation at a moment when the generated code will expire in a couple of seconds, and you can not have time to select / copy / paste / send it.

So I decided to write a script (I'll call it mytotp.sh) with the following functionality:

  • mytotp.sh displaying the names of all added services

  • mytotp.sh SERVICE TOTP output for the specified service with maximum validity time

Already during the writing of the article I wanted to add mytotp.sh --help display hints on how to use and mytotp.sh --add SERVICE adding an initialization key for SERVICE. But in time I remembered the principle YAGNI and slapped myself for trying to turn a simple script into Software.

Prerequisites

Actually the utility itself oathtool (depending on the OS used, it can be installed as part of the package oathtool or oath-toolkit) and GNU Privacy Guard (gpg, most likely already installed). To store TOTP initialization keys, I will use asymmetric GPG encryption, so I need a private/public key pair (you can use an existing one, or generate a new one, specifically for TOTP).

Generating a key pair for GPG specifically for TOTP

It’s better to put your own passphrase instead Slozhnyj-passwordtwo spaces between $ and gpg are not an accident – if the environment variable HISTCONTROL=ignoreboth is set, the line will not go into history.

$  gpg --yes --batch --passphrase 'Slozhnyj-parol' --quick-generate-key "My TOTP"

And to store all the initialization keys in one place you need to create a directory:

$ mkdir -p ~/.config/mytotp && chmod 0700 ~/.config/mytotp

Implementation

As a matter of fact, the script itself is very trivial, so I’ll hide it under a spoiler. The only one highlight — delay in TOTP generation until the nearest :00 or :30 seconds, so that the received code is valid for as long as possible (all 30 seconds).

For those interested – the script code and a link to GitHub
#!/bin/bash
#
# Put TOTP key for service SERVID to GPG file crypted for 'My TOTP'
#  gpg -e -r 'My TOTP' > ~/.config/mytotp/SERVID.gpg

KEYDIR=~/.config/mytotp
KEYEXT=.gpg
SERVID=$1

if [ -z "${SERVID}" ] ; then
  echo -e "Usage: $0 SERVID\n\tSERVID is a service ID, abbreviated, w/o ext:"
  find ${KEYDIR}/*${KEYEXT} | sed -e 's/\/home.*\//  /; s/\.gpg//'
  exit 2
fi

if [ ! -f "${KEYDIR}/${SERVID}${KEYEXT}" ] ; then
  echo "No key for ${KEYDIR}/${SERVID}${KEYEXT}"
  exit 1
fi

SKEY=$(gpg -d --quiet "${KEYDIR}/${SERVID}${KEYEXT}")

NOWS=$(date +'%S')
WAIT=$((60 - NOWS))
if [ ${WAIT} -gt 30 ]; then
  WAIT=$((WAIT - 30))
fi
echo -n "Seconds :${NOWS} (wait ${WAIT}) ... "
sleep ${WAIT}

TOTP=$(echo "${SKEY}" | oathtool -b --totp - )

echo "${TOTP}"
OKEY="none"

exit 0

I used to always make do with SVN, but since Git is now “stylishly fashionable for youth,” I’ll try to match: mytotp repository.

Usage (using GitHub as an example)

I go to github.com, Account / Settings / Password and authentication / Enable two-factor authentication. Under the QR code I find and click “setup key”, copy the line “Your two-factor secret” (just in case, I save it in the password manager, in the login card on GitHub). I execute in the console:

$ gpg -e -r 'My TOTP' > ~/.config/mytotp/github.gpg
XXXXXXXXXXXXXXXX	(нажимаю Ctrl+V)
(Ctrl+D)

Afterwards I launch mytotp.sh githubI enter the passphrase for the key, wait for the 6-digit code to appear, enter it on the website – 2FA is activated and verified, without a smartphone!

TOTP generation: it was and is now

TOTP generation: it was and is now

Conclusion

I wrote for myself because I had to. I decided to share, in case someone else finds it useful. The plans may take into account options when for some service the number of digits is not 6, and/or the HMAC function is not SHA-1. But so far everything is working for me, so YAGNI.

Yes, as expected, it does not work with MicroSoft, since they traditionally did not limit themselves to standard TOTP.

Good advice to everyone (even those who do not plan to give up their smartphone and happily scan QR codes): when enabling 2FA on the service, also save the text initialization key! When you decide to switch to another application, it will come in handy!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *