lucadentella / TOTP-Arduino

152 stars 33 forks source link

Codes don't match #17

Closed Fufs closed 3 years ago

Fufs commented 3 years ago

I've flashed esp8266 with the given example and the codes don't match. I have generated a 16 character long key that generates OTPs that are in sync between Home Assistant and Google Authenticator, but not with the module. I've added couple of debug lines from which I can see that the key is stored correctly, and the time is in sync with pool.ntp.org (UTC). I've tried to mess with ntp time offsets but it only makes the didn't fix it anyways (They shouldn't have either way, since Google Authenticator uses UTC). What am I doing wrong?

Fufs commented 3 years ago

Here's my code:

// TOTP DEMO, v1.0
//
// Requires a WiFi-capable board (for example esp32)
// and NTPClient library: https://github.com/arduino-libraries/NTPClient
//
// Change the wifi settings and enter your hmacKey
//
// To generate the hmacKey and initialize the smartphone app
// you can use my tool: http://www.lucadentella.it/OTP
//
// Tested with Arduino 1.8.12, NTPClient 3.2.0 and esp32 1.0.4

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <TOTP.h>
#include <WiFiUdp.h>

// change the following settings according to your WiFi network
char ssid[] = "some_ssid";
char password[] = "some_password";

// enter your hmacKey (10 digits)
uint8_t hmacKey[] = {0x32, 0x5a, 0x32, 0x57, 0x55, 0x37, 0x56, 0x55, 0x41, 0x47, 0x44, 0x36, 0x56, 0x46, 0x47, 0x55};

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP,"pool.ntp.org");
TOTP totp = TOTP(hmacKey, 16);

String totpCode = String("");

void setup() {

  Serial.begin(9600);
  while (!Serial);

  Serial.println("TOTP demo");
  Serial.println();
  for(int i = 0; i < 16; i++) Serial.print(char(hmacKey[i]));
  Serial.println();

  // connect to the WiFi network
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Establishing connection to WiFi...");
  }
  Serial.print("Connected to WiFi with IP: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  // start the NTP client
  timeClient.begin();
  Serial.println("NTP client started");
  Serial.println();
}

void loop() {

  // update the time 
  timeClient.update();

  // generate the TOTP code and, if different from the previous one, print to screen
  String newCode = String(totp.getCode(timeClient.getEpochTime()));
  if(totpCode!= newCode) {
    totpCode = String(newCode);
    Serial.print("TOTP code: ");
    Serial.print(newCode);
    Serial.print("\tTime: ");
    Serial.println(timeClient.getEpochTime());
  }
}

Edit: I'm using platformio as my environment

lucadentella commented 3 years ago

I've just tested your secret key with both Google Authenticator and Dan Hersam website and it works with my demo code.

Your secret key: {0x32, 0x5a, 0x32, 0x57, 0x55, 0x37, 0x56, 0x55, 0x41, 0x47, 0x44, 0x36, 0x56, 0x46, 0x47, 0x55}

translated into ASCII is 2Z2WU7VUAGD6VFGU (you can manually translate it using an ASCII table or https://tomeko.net/online_tools/hex_to_ascii.php?lang=en)

Now if you generate the Base32 encoded string of it you get GJNDEV2VG5LFKQKHIQ3FMRSHKU====== (my website can help http://www.lucadentella.it/OTP/)

and if you use that key for Google Auth or https://totp.danhersam.com/?key=GJNDEV2VG5LFKQKHIQ3FMRSHKU====== you get the same sequence of OTP codes as it is generated by the sketch:

image

Fufs commented 3 years ago

I've tested the base32 encoded string and it now works. So my understanding is that I put the secret key in the code and everything else (i.e. Authenticator app) uses a Base32 encoded string of that key? Why so?

lucadentella commented 3 years ago

Google decided to use Base32 encoding (https://en.wikipedia.org/wiki/Google_Authenticator) and some websites/applications adopted the same encoding.

Some didn't, so I preferred to use a plain version of the key in my library and let the user convert it in what it is expected from the application he chose.