tadeck / onetimepass

One-time password library for HMAC-based (HOTP) and time-based (TOTP) passwords
http://otp.readthedocs.org/
MIT License
681 stars 101 forks source link

Can't use leading digit in secret #12

Closed dbuckman closed 9 years ago

dbuckman commented 9 years ago

Maybe I am doing something wrong, but when a secret has a digit in the first position generating a OTP fails. Is this by design or am I doing something wrong?

my_secret = 'aaaaaaaaaaaaaaaa' my_token = otp.get_totp(my_secret)

my_secret = '1aaaaaaaaaaaaaaa' my_token = otp.get_totp(my_secret) Traceback (most recent call last): File "", line 1, in File "/var/www/project/lib/python2.7/site-packages/onetimepass/init.py", line 162, in get_totp token_length=token_length, File "/var/www/project/lib/python2.7/site-packages/onetimepass/init.py", line 113, in get_hotp raise TypeError('Incorrect secret') TypeError: Incorrect secret

Thanks for the help

tadeck commented 9 years ago

@dbuckman: It is a coincidence, that "aaaaaaaaaaaaaaaa" is valid secret (eg. both "aaaaaaaaaaaaaaa" and "aaaaaaaaaaaaaaaaa" are not). The underlying rule is that secret must be a valid argument for base64.b32decode().

Does that answer your question?

dbuckman commented 9 years ago

Well it does answer that I was doing it wrong and need to understand base64.b32decode() better. I have some reading to do. Thanks for the help

tadeck commented 9 years ago

Well it does answer that I was doing it wrong and need to understand base64.b32decode() better. I have some reading to do. Thanks for the help

If you are generating secret yourself, I suggest:

  1. Generating binary secret (currently you seem to be using a subset of available characters) and then passing it to base64.b32encode(); the result will be passable as secret, or
  2. Passing your own secret as argument to base64.b32encode() and using the result as secret; or
  3. Wrapping onetimepass.get_totp() in your own function, that will do the conversion (using base64.b32encode()) on your behalf,

Example of how to use '1aaaaaaaaaaaaaaa' as secret:

>>> from base64 import b32encode
>>> import onetimepass as otp
>>> secret = '1aaaaaaaaaaaaaaa'
>>> otp.get_totp(b32encode(secret))
706607

That would allow you to continue without need to understand base64.b32decode(). Hope that helps.