speakeasyjs / speakeasy

**NOT MAINTAINED** Two-factor authentication for Node.js. One-time passcode generator (HOTP/TOTP) with support for Google Authenticator.
MIT License
2.68k stars 229 forks source link

Base32 secrets with a length not a multiple of 8 may produce incorrect codes #135

Open tommilligan opened 3 years ago

tommilligan commented 3 years ago

Due to an underlying bad base32 implementation (https://github.com/speakeasyjs/base32.js/issues/4), base32 encoded secrets that are not of length 8, 16, 24, 32 etc. may produce invalid codes.

This behaviour depends on the value of the secret itself. For a comparison with Python's pyotp libaray, see these examples: https://github.com/pyauth/pyotp/issues/115

This may be the underlying cause of the following issues:


Example: an incorrect code is generated for the secret S46SQCPPTCNPROMHWYBDCTBZXV (length 26).

> speakeasy.totp({"secret":"S46SQCPPTCNPROMHWYBDCTBZXV","encoding":"base32","time":1612380872})
'184825'

The python pyotp library produces a different value for the same inputs.

In [16]: pyotp.totp.TOTP("S46SQCPPTCNPROMHWYBDCTBZXV").at(datetime.fromtimestamp(1612380872))
Out[16]: '100172'