Why have so many methods to generate OTPs, why not just use just random strings?
Just using random strings is simple and often reasonable solution. However, if you have significant customer base, it can become too expensive, because all of those random strings need to be stored.
But in short, these more complex schemes are mainly for reducing storage requirements and amount of entropy needed. Note: I am partially building this reply on previous two replies.
Reducing required entropy and storage requirements
Just generating random strings means need to generate and store lot more random bits than many of more well thought OTP mechanisms. For instance, S/KEY needs to generate and store just one value, even there can be e.g. one hundred passwords, thus reducing storage costs to one (theoretically) up-to one hundredth of random strings. Because less random bits (entropy) are needed, the OTP mechanism is easier to test and validated.
(Note: to handle transitions and expirations smoothly, usually more than one value needs to be stored.).
I agree to some degree with md_1976, however, I disagree on amount of information stored on the server. Time-based OTP schemes typically still need some information on user account, like serial number of user's authentication device (hardware device). In case there is software implementation of time-based OTP, server likely needs to know the public key of user's device or possibly the server and device needs a shared secret. One possible issue with time-based OTP schemes is that they tend to require special client-side software or hardware. One the other hand traditional OTP schemes can work even just via e.g. letter and phone network.
In time-based scheme with client side hardware device, typical information to store per account could be serial number and or other identification codes of the device.
Sizes of stored values
For purposes of comparing cost. (The possible other values e.g. account id or timestamps not considered.)
- Original S/KEY (RFC 1760) - this is based on MD4 hash function, which is considered broken. Not recommended to be used.
- OTP (RFC 2289), based on MD4/MD5, or SHA1. 64 bits storage needed, per OTP key.
- HOTP (RFC 4226): Shared Secret is 128-bits or more (recommended 160-bits).
- TOTP (RFC 6238): Uses same sized shared secret as HOTP.
My opinion on “Random vs. TOTP (Time-based OTP)”.
With a random token, you need to keep track of what was generated for whom, when it expires, and you need to purge the expired tokens. A (TOTP) has the inherent feature of be being useful for a defined period of time.
If the server receives an OTP for an account, the server can generate OTPs for that account starting N minutes in the past and work up to the present (or go the other way). If any of those server-generated OTPs match the given OTP, then you know…
- it's valid and
- it was created within a given time frame in the past.
There is nothing else that the server needs to keep track of to validate a TOTP.
And how do you propose to generate those strings "randomly"? That becomes the real problem. If you use the output of rand(), then the security of your algorithm is no better than the unpredictability of your random number generator.
Random number generators have to be carefully designed for cryptographic use. Most rand() functions use some fairly simple math to produce "statistically random" values, not "unpredictably random values".
Here's an example of what happens if you use a random number generator that is predictable: http://blog.cryptographyengineering.com/2013/09/the-many-flaws-of-dualecdrbg.html
Storage is the big problem here, also if the storage server gets hacked, then the randomness of your infintely larger string would not matter. Instead, servers generate a OTP based on some seed value (randomly generated / time value / etc). This required no storage, a little bit of computing power, that's it.