Generating OTP in Arduino and PHP?

I am trying to generate a one-time password on the Arduino and a server independently using a shared seed but not sure if there are functions that are shared between C++ and PHP to ensure that the same password is generated.

If not, how does one go about writing a cryptographic function for this purpose (it does not actually need to uncrackable, just moderately secure)?

You need to use database, In database table, there are at least two columns: otp and timestamp.

I am not sure about your application. But I suppose it works as follow:

  • Arduino makes HTTP request to PHP to request for OTP
  • PHP generate OTP randomly, store OTP and current time stamp to database, and send back OTP to Arduino
  • Arduino displayed OTP on something such as LCD, serial monitor ...
  • You access another PHP page from a web browser, and input OTP, send to web server.
  • Web server verify whether OTP is correct and timestamp is valid

abval:
I am trying to generate a one-time password on the Arduino and a server independently using a shared seed but not sure if there are functions that are shared between C++ and PHP to ensure that the same password is generated.

If not, how does one go about writing a cryptographic function for this purpose (it does not actually need to uncrackable, just moderately secure)?

Could you use well-known message digest algorithm like SHA? The two ends would share a seed, which would just be 128 random bits. To log in, one side would send another random 128 bits as well as the SHA digest of those bits concatenated with the shared seed. The receiver could validate that the digest is correct, and there you go.

There is almost certainly an SHA library for arduino and for whatever server you are using.

--- edit ---

Actually, you'd want to have the first side send some bits, too. So:

Client sends 128 random bits.
Server replies with 128 random bits.
Client concatenates the shared seed, its 128, and the server's 128, then takes the SHA of the whole thing and sends that to the server.
The server verifies that the hash that the client sent is correct, and the session is then authenticated.

IoT_hobbyist:
You need to use database, In database table, there are at least two columns: otp and timestamp.

This would perhaps work but unfortunately I can not have communication between the server and client. So the Arduino can't be communicating with the server directly at all, they need to be generating the password independently.

PaulMurrayCbr:
Could you use well-known message digest algorithm like SHA? The two ends would share a seed, which would just be 128 random bits. To log in, one side would send another random 128 bits as well as the SHA digest of those bits concatenated with the shared seed. The receiver could validate that the digest is correct, and there you go.

Also a good solution, but same issue. The Arduino and Server can not have a direct communication (the situation unfortunately does not allow for this). A user would request a password from the server and need to verify it with the Arduino.

I was thinking that the two would perhaps be able to independently generate a password from a hardware key and a counter. I realize this is not particularly secure, but that is not a huge issue, this would be a four digit pin anyway so not very secure to begin with.

abval:
Also a good solution, but same issue. The Arduino and Server can not have a direct communication (the situation unfortunately does not allow for this). A user would request a password from the server and need to verify it with the Arduino.

I was thinking that the two would perhaps be able to independently generate a password from a hardware key and a counter. I realize this is not particularly secure, but that is not a huge issue, this would be a four digit pin anyway so not very secure to begin with.

This solution would work perfectly well. The server generates some random bits, concatenated that with the shared seed and the user’s userid, and gets a message hash. The one-time-password would be the random bits and the hash.

To make this a one-time password, the client could remember the random bits permanently and never recognise them again. Or, hash in a timestamp - the password becomes the bits, the timestamp, and the digest. This creates a password that only works for a limited amount of time.

PaulMurrayCbr:
This solution would work perfectly well. The server generates some random bits, concatenated that with the shared seed and the user's userid, and gets a message hash. The one-time-password would be the random bits and the hash.

My bad, that would absolutely work! Would the length of the password not be an issue though? If the user needs to enter both the random bits generated by the server and the digest, 4 (or perhaps 6) digits won't really do. It does not have to be particularly secure, but is it even doable with so few digits?

Apologies for my ignorance on the subject, I might be missing something clear here.. really appreciate the help though!

abval:
Would the length of the password not be an issue though?

Yes, of course. Passwords are always a tradeoff.

Base64 encoding converts 8 bits into 6. A time/date accurate to the hour within a 100-year range is 876000 - 20 bits, about 3 and a half characters base64 encoded. Maybe 128 bits of hash is more than you need - 64 bits is 10 characters, base64 encoded. To get 64 bits of hash, take the SHA hash - 128 bits - and just XOR the two halves together. Or - you know what? - just use the first half: probably good enough. You don't need the whole thing, you just need to to be able to compute it at both ends.

And, of course, the password doesn't need to contain the username, just the hashed result, because the user will type in their username. So, a decent 64-bit hash, a time accurate to the hour (within the century), and - say - 32 bits of random salt base 64 encoded is 18-19 characters of password - totally do-able for a OTP.

IOW:

The authentication service makes a 64 bit hash of:
[Hour within the century (time in seconds/3600) mod 2^20]
[Random salt: 32 bits]
[Username]

The password is:
[Hour within the century (time in seconds/3600) mod 2^20: 20 bits]
[Random salt: 32 bits]
[64-bit hash: 64 bits]

This is 116 bits, base64 encoded it becomes 20 characters, eg: Aggf85JhiukgjHJ756B8.

The client service takes the user id, parses out the hour and the salt from the password, and confirms that the calculated digest matches. It can also confirm that the OTP was used within X hours of being issued and refuse access if it is not.

Job done.