A One-Time Password System
Extracted elements (30)
All hash outputs are stored in little-endian format before the 64-bit fold (even SHA-1 which is natively big-endian) for historical compatibility with the original Bellcore MD4/MD5 reference implementations, ensuring interoperability across hardware architectures.
The one-time password is folded to 64 bits: long enough for security against brute-force guessing, yet short enough to be entered manually as six short words when automatic cut-and-paste is unavailable.
The seed is transmitted in clear text alongside the challenge so that a user can employ the same secret pass-phrase on multiple machines (using different seeds) and safely recycle pass-phrases by changing the seed, without exposing the pass-phrase.
The server verifies an OTP by hashing it once and comparing to the stored previous OTP (Lamport's technique), meaning the server stores only the hash of the next expected password and never the secret pass-phrase, so no secret information need be stored on the server.
RFC 2289 obsoletes RFC 1938. The standard six-word dictionary was originally specified in the S/KEY One Time Password System (RFC 1760); all OTP servers and generators must use this identical dictionary for interoperability.
Words in an alternate dictionary MUST NOT overlap the standard dictionary words and MUST NOT be comprised solely of the letters A–F (to avoid ambiguity with hexadecimal). This allows the server to distinguish encoding type without knowing which alternate dictionary was used.
All conforming implementations of both server and generators MUST support MD5. They SHOULD support SHA and MAY also support MD4. The generator and server must use the same algorithm to interoperate.
All conforming server implementations MUST protect against the race condition in which an attacker listens to most of a one-time password, guesses the remainder, and races the legitimate user to complete authentication.
ALL hashes incorporated into the OTP protocol MUST store the output of their hash function in LITTLE ENDIAN format BEFORE the bit folding to 64 bits occurs. SHA1 requires explicit reordering since its native output is big-endian.
All implementations of the server software MUST accept case-insensitive hexadecimal as well as six-word format. Servers are REQUIRED to ignore all white space in hexadecimal representations.
All OTP generators MUST calculate the two-bit checksum (sum of bit-pairs, two LSBs encoded as the last two bits of the six-word sequence) and all OTP servers MUST verify this checksum explicitly when decoding six-word format.
Character string pass-phrases MUST contain at least 10 characters to reduce risk from exhaustive search or dictionary attacks. All implementations MUST support pass-phrases of at least 63 characters.
Generators producing six-word format MUST present words in upper case with single spaces as separators. All servers MUST accept six-word format without regard to case and any whitespace as separator.
Implementations MUST provide a means to reinitialize the OTP sequence that does not reveal the user's secret pass-phrase, such as through explicit specification of the first one-time password.
Servers SHOULD accept the alternate dictionary encoding described in Appendix B in addition to the standard six-word and hexadecimal encodings. Words in alternate dictionaries are case sensitive and MUST be preserved.
The challenge MUST be in the standard syntax 'otp-<algorithm identifier> <sequence integer> <seed>', with tokens separated by whitespace, the entire string terminated by a space or newline, and the string 'otp-' in lower case.
The seed MUST consist of purely alphanumeric characters, MUST be 1 to 16 characters in length, MUST NOT contain blanks, MUST be case insensitive, and MUST be internally converted to lower case before processing.
To allow interchangeability of generators, all generators MUST support a secret pass-phrase of 10 to 63 characters. Implementations MAY support longer pass-phrases but risk loss of interchangeability.
To resolve ambiguity between six-word and hexadecimal encodings, all implementations MUST first attempt to decode as six-word standard dictionary; if invalid, attempt hexadecimal decoding.
When the sequence of one-time passwords is reinitialized, implementations MUST verify that the seed or the pass-phrase is changed. Installations SHOULD discourage sending the secret pass-phrase over the network in clear-text.
A sequence of one-time passwords is produced by applying a secure hash function N times to (seed || pass-phrase). Each successive authentication uses N-1 iterations, so an eavesdropper cannot derive the next password without inverting the hash.
Alternative dictionary encoding allows language-specific or friendly words where each word W at position N obeys: hash(W) % 2048 == N. The server decodes without needing the specific alternate dictionary, making acceptance of one alternate dictionary imply acceptance of all.
The server stores for each user the one-time password from the last successful authentication (or the first OTP of a newly initialized sequence) and the corresponding sequence number. Authentication succeeds when hash(received OTP) equals the stored OTP.
The standard six-word dictionary contains exactly 2048 words from Appendix D (originally from S/KEY RFC 1760). Interoperability requires all OTP servers and generators to use this same dictionary.
A race attack is possible: an attacker who observes most of a transmitted six-word OTP can guess the last word (1-in-2048 per attempt) and race the legitimate user. Servers MUST defend, e.g., by serializing authentication sessions with a timeout to prevent denial-of-service.
If a server supports multiple hash algorithms it is only as secure as its weakest algorithm. MD4 is believed to be less strong than MD5; a server offering MD4 downgrades overall security.
OTP protects only against passive eavesdropping/replay attacks. It does not provide privacy for transmitted data and does not protect against active attacks such as TCP session hijacking. IPsec is recommended for protection against session hijacking.
OTP sequence lifecycle: INITIALIZED (server stores OTP[N] and count N) → AUTHENTICATING (server receives OTP[N-1], verifies hash(OTP[N-1]) == OTP[N], stores OTP[N-1] and count N-1) → EXHAUSTED (count reaches 1, user cannot change seed/count) → REINITIALIZED (new seed or pass-phrase, new count).
The one-time password is 64 bits, optionally encoded as six short words (1–4 letters each) from a 2048-word dictionary at 11 bits per word (66 bits total including a 2-bit checksum), or as 16 hexadecimal digits.
The OTP challenge string has the format 'otp-<alg> <seq> <seed>' where alg is one of 'md4', 'md5', or 'sha1'; seq is the sequence integer; and seed is 1–16 alphanumeric characters. Tokens are separated by whitespace and the string is terminated by a space or newline.