What are 2FA codes?

Simply put, 2FA or two-factor authentication refers to adding a second defense line to the login process of an online service by requiring proof based on a second factor.

Authentication factors are

  1. something you know (e.g. password, security questions),
  2. something you have (e.g. smart phone, a cryptographic key), and
  3. something you are (e.g. biometric).

2FA codes commonly refer to time-based one-time passwords (TOTP) that are generated client-side (e.g. by a smartphone app). They change every 30 seconds and depend on a shared secret exchanged during the setup process. As such, they prove that you have the device used during 2FA setup and provide the factor “something you have".

How to enable 2FA?

First, you choose a 2FA code generator app for your device, for example, Authy, 1Password, or Google Authenticator (to name a few).

2FA codes are usually set up in the account settings of an online service. Here, a shared secret is randomly generated and presented as a QR code or alternatively as text. You add the service to the generator app by scanning the QR code in the app or copying the text to it. Finally, an initial one-time password confirms the proper configuration and makes 2FA codes mandatory for this service.

How are one-time passwords generated?

These are the steps of the TOTP algorithm that turn a shared secret and the current time into a 6-digit code:

  1. The current Unix timestamp (the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970) is divided by 30 seconds, rounded down, and encoded as an unsigned 64-bit integer.
  2. An HMAC-SHA1 digest is generated using the 8 bytes from the previous step as the message and the raw shared secret as the key.
  3. The 4 last bits of the digest are turned into a number. This number specifies the left offset in the digest from which 4 bytes are extracted. Finally, we drop the first bit from the extract. This step is called “truncation”.
  4. The 31 bits from the previous step are interpreted as an unsigned 32-bit integer. The resulting number is formatted in decimal form and the last 6 digits are displayed.

The precise algorithm is described in RFC 6238 and RFC 4226. It assumes the Big-endian byte order for binary operations.