I am working on a One Time Password to control a Relay. I have some of the code completed. I do not know where the error in my coding is. I have no compiling errors and it runs the code just fine but when it goes to output what the 6 digit code should be it is always blank. below is the code and the output.
Output
TOTP Door lock
New code inserted: 111111
Wrong code... the correct was:
#include <Arduino.h>
#include <RTClib.h>
#include <DS3231.h>
#include <Wire.h>
#include <RTClib.h>
#include <Time.h>
#include <Keypad.h>
#include <sha1.h>
#include <TOTP.h>
DS3231 RTC;
#define DS3231_I2C_ADDRESS 0x68
// debug print, use #define DEBUG to enable Serial output
#define DEBUG
#ifdef DEBUG
#define DEBUG_PRINT(x) Serial.print(x)
#define DEBUG_PRINTLN(x) Serial.println(x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#endif
// shared secret
uint8_t hmacKey[] = {0x34, 0x67, 0x78, 0x71, 0x40, 0x6d, 0x5a, 0x3b, 0x7e, 0x4e};
TOTP totp = TOTP(hmacKey, 10);
// keypad configuration
const byte rows = 4;
const byte cols = 3;
char keys[rows][cols] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[rows] = {2, 3, 4, 5};
byte colPins[cols] = {6, 7, 8};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);
char* totpCode;
char inputCode[7];
int inputCode_idx;
void setup() {
Serial.begin(9600);
DEBUG_PRINTLN("TOTP Door lock");
DEBUG_PRINTLN("");
Wire.begin();
// reset input buffer index
inputCode_idx = 0;
}
void loop() {
char key = keypad.getKey();
// a key was pressed
if (key != NO_KEY) {
// # resets the input buffer
if(key == '#') {
DEBUG_PRINTLN("# pressed, resetting the input buffer...");
inputCode_idx = 0;
}
else {
// save key value in input buffer
inputCode[inputCode_idx++] = key;
// if the buffer is full, add string terminator, reset the index
// get the actual TOTP code and compare to the buffer's content
if(inputCode_idx == 6) {
inputCode[inputCode_idx] = '\0';
inputCode_idx = 0;
DEBUG_PRINT("New code inserted: ");
DEBUG_PRINTLN(inputCode);
RTCDateTime now = RTC.getDateTime();
unsigned long EST = now.unixtime;
char* newCode = totp.getCode(EST);
// code is ok :)
if(strcmp(inputCode, totpCode) == 0) {
DEBUG_PRINTLN("Code ok");
// code is wrong :(
} else {
DEBUG_PRINT("Wrong code... the correct was: ");
DEBUG_PRINTLN(totpCode);
}
}
}
}
}
The reason: You are comparing your input to the totpCode, which you never attribute any value.
Modify this line:
char* totpCode;
To:
char totpCode[7] = "123456";
So, the correct password will be 123456.
Test it.
That worked. Now the trick is to generate the OTP within the code to go into the totpCode.
Now, if you have a string (char array + NULL terminator) with the generated OTP, you can copy to totpCode using the function strncpy():
strncpy(totpCode,generatedOTP,6);
Where would I put that line? I have tried in the loop due to the OTP changing but is giving an error that generatedOTP was not declared in this scope.
No,no, this was just an example.
The generatedOTP would be the variable where you get the generated OTP.
But you still need to get it first.
I have this line where the totp is to pull the OTP.
uint8_t hmacKey[] = {0x34, 0x67, 0x78, 0x71, 0x40, 0x6d, 0x5a, 0x3b, 0x7e, 0x4e};
TOTP totp = TOTP(hmacKey, 10);
This part of your code:
char* newCode = totp.getCode(EST);
// code is ok :)
if(strcmp(inputCode, totpCode) == 0) {
DEBUG_PRINTLN("Code ok");
// code is wrong :(
} else {
DEBUG_PRINT("Wrong code... the correct was: ");
DEBUG_PRINTLN(totpCode);
}
In exact this:
char* newCode = totp.getCode(EST);
The newCode variable stores the new 6 digit password?
That is what it is meant to do.
Thanks for your sharing! Now I know what TOTP is and how to use it.
Replace this line:
char* newCode = totp.getCode(EST);
with:
strncpy(totpCode,totp.getCode(EST),6);
And now you have the TOTP working!
I change that line and now it gets stuck in a loop on the serial monitor of the same code forever.
Example of output
New code inserted: 123456
e Time Password
w code inserted: 123456
e Time Password
w code inserted: 123456
e Time Password
w code inserted: 123456
e Time Password
Did you modified this line in one my previous asnwer
char* totpCode;
To:
char totpCode[7] = "123456";
?
If yes, take out this line:
strncpy(totpCode,totp.getCode(EST),6);
and modify this line:
if(strcmp(inputCode, totpCode) == 0) {
to:
if(strcmp(inputCode, totp.getCode(EST)) == 0) {
I made the changes. Here is the updated code and the output.
Output
One Time Password
New code inserted: 111111
the correct was:
#include <Arduino.h>
#include <RTClib.h>
#include <DS3231.h>
#include <Wire.h>
#include <RTClib.h>
#include <Time.h>
#include <Keypad.h>
#include <sha1.h>
#include <TOTP.h>
DS3231 RTC;
#define DS3231_I2C_ADDRESS 0x68
// debug print, use #define DEBUG to enable Serial output
#define DEBUG
#ifdef DEBUG
#define DEBUG_PRINT(x) Serial.print(x)
#define DEBUG_PRINTLN(x) Serial.println(x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#endif
// shared secret
uint8_t hmacKey[] = {0x34, 0x67, 0x78, 0x71, 0x40, 0x6d, 0x5a, 0x3b, 0x7e, 0x4e};
TOTP totp = TOTP(hmacKey, 10);
// keypad configuration
const byte rows = 4;
const byte cols = 3;
char keys[rows][cols] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[rows] = {2, 3, 4, 5};
byte colPins[cols] = {6, 7, 8};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);
char* totpCode;
//char totpCode[7];
char inputCode[7];
int inputCode_idx;
void setup() {
Serial.begin(9600);
DEBUG_PRINTLN("One Time Password");
DEBUG_PRINTLN("");
Wire.begin();
// reset input buffer index
inputCode_idx = 0;
}
void loop() {
char key = keypad.getKey();
// a key was pressed
if (key != NO_KEY) {
// # resets the input buffer
if(key == '#') {
DEBUG_PRINTLN("# pressed, resetting the input buffer...");
inputCode_idx = 0;
}
else {
// save key value in input buffer
inputCode[inputCode_idx++] = key;
// if the buffer is full, add string terminator, reset the index
// get the actual TOTP code and compare to the buffer's content
if(inputCode_idx == 6) {
inputCode[inputCode_idx] = '\0';
inputCode_idx = 0;
DEBUG_PRINT("New code inserted: ");
DEBUG_PRINTLN(inputCode);
RTCDateTime now = RTC.getDateTime();
unsigned long EST = now.unixtime;
// char* newCode = totp.getCode(EST);
// strncpy(totpCode,totp.getCode(EST),6);
// code is ok :)
//if(strcmp(inputCode, totpCode) == 0) {
if(strcmp(inputCode, totp.getCode(EST)) == 0) {
DEBUG_PRINTLN("Code ok");
// code is wrong :(
} else {
DEBUG_PRINT("the correct was: ");
DEBUG_PRINTLN(totpCode);
}
}
}
}
}
As now you aren't saving the TOTP password, but rather, comparing it directly, you get no Serial output.
Seeing the code in the previous answer, were you using char totpCode[7]; rather than char* totpCode; when you posted the stuck problem?
Do you need to save it the generated password?
Are you inserting the password that is supposed to be correct?
Copy and paste this code, then test it:
#include <Arduino.h>
#include <RTClib.h>
#include <DS3231.h>
#include <Wire.h>
#include <RTClib.h>
#include <Time.h>
#include <Keypad.h>
#include <sha1.h>
#include <TOTP.h>
DS3231 RTC;
#define DS3231_I2C_ADDRESS 0x68
// debug print, use #define DEBUG to enable Serial output
#define DEBUG
#ifdef DEBUG
#define DEBUG_PRINT(x) Serial.print(x)
#define DEBUG_PRINTLN(x) Serial.println(x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#endif
// shared secret
uint8_t hmacKey[] = {0x34, 0x67, 0x78, 0x71, 0x40, 0x6d, 0x5a, 0x3b, 0x7e, 0x4e};
TOTP totp = TOTP(hmacKey, 10);
// keypad configuration
const byte rows = 4;
const byte cols = 3;
char keys[rows][cols] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[rows] = {2, 3, 4, 5};
byte colPins[cols] = {6, 7, 8};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);
char totpCode[7];
char inputCode[7];
int inputCode_idx;
void setup() {
Serial.begin(9600);
DEBUG_PRINTLN("One Time Password");
DEBUG_PRINTLN("");
Wire.begin();
// reset input buffer index
inputCode_idx = 0;
}
void loop() {
char key = keypad.getKey();
// a key was pressed
if (key != NO_KEY) {
// # resets the input buffer
if(key == '#') {
DEBUG_PRINTLN("# pressed, resetting the input buffer...");
inputCode_idx = 0;
}
else {
// save key value in input buffer
inputCode[inputCode_idx++] = key;
// if the buffer is full, add string terminator, reset the index
// get the actual TOTP code and compare to the buffer's content
if(inputCode_idx == 6) {
inputCode[inputCode_idx] = '\0';
inputCode_idx = 0;
DEBUG_PRINT("New code inserted: ");
DEBUG_PRINTLN(inputCode);
RTCDateTime now = RTC.getDateTime();
unsigned long EST = now.unixtime;
strcpy(totpCode,totp.getCode(EST));
// code is ok :)
if(strcmp(inputCode, totpCode) == 0) {
DEBUG_PRINTLN("Code ok");
// code is wrong :(
} else {
DEBUG_PRINT("the correct was: ");
DEBUG_PRINTLN(totpCode);
}
}
}
}
}
I do not need to save it as it only lasts 30 seconds in Google Authentication. the TOTP line is what takes the hex code and generates the 6 digit code from Google.
I have tried both correct and incorrect codes and it gives me the same output.
That code work it is now giving codes. the only problem is the unix time is GMT not EST where I am so the codes on my phone are not the same. How would I change the unix time from GMT to EST?
Add this line to the setup():
RTC.setDateTime(F(__DATE__), F(__TIME__));
And test it again!
If this don't work, search (google) the algorithm to convert from GMT to EST.
This is all!
Thank you for the help. The GMT is the correct time zone for Google Authentication. I think there is something wrong with my TOTP library encrypting and decrypting the OTP. I will work on the libraries. Again thank you for all the help.