I followed this awesome answer for implementing Google OAuth in Python. However, when I tried running in Python 3, I get this error:
TypeError: ord() expected string of length 1, but int found
This error is thrown by this line:
o = ord(h[19]) & 15
Trying o = ord(str(h[19])) & 15
resulted in:
TypeError: ord() expected a character, but string of length 3 found
This happens in Python 3, but not in Python 2, which makes me think that some types have changed between versions. This is the relevant code:
def get_hotp_token(secret, intervals_no):
key = base64.b32decode(secret)
msg = struct.pack(">Q", intervals_no)
h = hmac.new(key, msg, hashlib.sha1).digest()
o = ord(h[19]) & 15
h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
return h
I tried to follow this question's answers, but they did not help. The first answer did not help because I am not using a string literal for key
or msg
. This was my attempt at implementing the second answer's suggestion:
def get_hotp_token(secret, intervals_no):
key = base64.b32decode(secret)
key_bytes = bytes(key, 'latin-1')
msg = struct.pack(">Q", intervals_no)
msg_bytes = bytes(msg, 'latin-1')
h = hmac.new(key_bytes, msg_bytes, hashlib.sha1).digest()
o = ord(h[19]) & 15
h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
return h
This code threw this error on the key_bytes = <...>
and msg_bytes = <...>
:
TypeError: encoding without a string argument
Using utf-8
instead of latin-1
had the same result.
If I print(key, msg)
, I get this, which suggests that they are already in a byte-like form:
b'fooooooo37' b'\x00\x00\x00\x00\x02\xfa\x93\x1e'
The msg
printed explains the ... string of length 3 found
error above.
I am unsure where to go from here. Any suggestions/solutions would be great!