for a university exercise I want to develop a simple hotp server-client system in python. In this case the client sends a password and a one time password to the server. The server knows the secret, calculates the current hotp and compares the values it receives. So far, so good. With plaintext this works perfectly fine and the calculated values are the same I get when I use the iOS App "OTP Auth". But there is also the possibility to calculate the OTP in combination with base32. So I added a few lines to encode the plaintext to base32 but now the output in not correct.
Let's assume we're using the secret "1234" so the plaintext output would be "110366". That's working. But if I'm encoding the secret to base32 the output should be "807244" but my program calculates "896513". Anybody know why this is happening?
I've already tried to use different secrets and checked it on different apps. Always the same result.
import hmac
import hashlib
import array
import base64
counter = 0
digits = 6 #Anzahl der Zeichen
def hotp(secret, c):
global digits
counter = extendCounter(c)
hmac_sha1 = hmac.new(secret, counter, hashlib.sha1).hexdigest()
return truncate(hmac_sha1)[-digits:]
def truncate(hmac_sha1):
offset = int(hmac_sha1[-1], 16)
binary = int(hmac_sha1[(offset * 2):((offset * 2) + 8)], 16) & 0x7fffffff
return str(binary)
def extendCounter(long_num):
byte_array = array.array('B')
for i in reversed(range(0, 8)):
byte_array.insert(0, long_num & 0xff)
long_num >>= 8
return byte_array
def main():
secret = "1234"
bSecret = secret.encode("UTF-8")
bSecret = base64.b32encode(bSecret)
otp = hotp(bSecret, counter)
one_time_password = otp
I expect 807244 as the output but the output is 896513
Found the mistake: Instead of translating the secret to base32, the secret must be a Base32 decoded value. Also instead of encoding this value, it must be decoded ("base64.b32decode(bytes(saved_secret, 'utf-8'))")
So the correct main looks like this:
def main():
secret = "V6X27L5P" #Base32 value
secret = base64.b32decode(bytes(secret, 'utf-8'))
one_time_password = hotp(secret, counter)