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

Incorrect secret #7

Closed xiajiok closed 10 years ago

xiajiok commented 10 years ago

onetimepassinit.py", line 100, in get_hotp

Incorrect secret

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

tadeck commented 10 years ago

@xiajiok, could you give me the source of your secret? Where did you get it from?

The script expects secrets that are base32-encoded, while yours clearly is not a valid base32 representation.

xiajiok commented 10 years ago

yes,not base32-encoded check,here is the code:

secret_feed = string.letters[:26] + string.digits secret = ''.join([choice(secretfeed) for in xrange(16)]).upper()

now i changed "secret_feed" to :secret_feed = string.letters[:26] it worked now. seem like secret is better Uppercase letter,

how you guys generate a valid secret key? i not quite understant base32-encode,for now:)

tadeck commented 10 years ago

@xiajiok: so the secret was generated by you? Or was it taken from some other site?

I need to know the source to tell you exactly, whether the cause is on your end, or onetimepass library just lacks support for some new service / use case.

xiajiok commented 10 years ago

@tadeck :yes, generated by myself, not form other site.

below is the source code for secret:

secret_feed = string.letters[:26] + string.digits secret = ''.join([choice(secretfeed) for in xrange(16)]).upper()

tadeck commented 10 years ago

@xiajiok: I am assuming you are generating your secret yourself, so let me give you a hint on how you can do it. Also please let me know, if it was taken from other service - I will need to check it.

base32 is a way to encode binary data and string.letters[:26] + string.digits is not a valid set of base32 characters (proof: base32 has 32 characters, not 36). You can find a mapping to all valid characters this way:

>>> import base64
>>> print base64._b32alphabet
{0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E', 5: 'F', 6: 'G', 7: 'H', 8: 'I',
9: 'J', 10: 'K', 11: 'L', 12: 'M', 13: 'N', 14: 'O', 15: 'P', 16: 'Q',
17: 'R', 18: 'S', 19: 'T', 20: 'U', 21: 'V', 22: 'W', 23: 'X',
24: 'Y', 25: 'Z', 26: '2', 27: '3', 28: '4', 29: '5', 30: '6', 31: '7'}

The problem with your secret was, that it contained characters that are not valid for base32 (0, 1, 8, 9 are all invalid and three of them were in your secret).

The safer way to generate random base32-encoded secret is to actually:

  1. Make it really random,
  2. Make it really base32-encoded (so also do not limit characters to 26 letters, but also use digits),

Example on how to do that:

import base64
import hashlib
import os

my_secret = base64.b32encode(hashlib.sha512(os.urandom(8192)).digest())[:16]

where you can replace 16 with any valid length.

Since it looks like this is the case, I am closing the ticket.

Cheers, T.

xiajiok commented 10 years ago

Since i get the point,

Thanks for you patience.

Cheers.