Google OAuth in Python 3 error - python

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!

hmac.new() returns a string of bytes. In Python 3 this is an array of integers. Hence h[19] is an integer. Just use that int instead of calling ord(). Or decode h to str.

Related

About to_bytes() method of int type

I have a question about to_bytes method of int type in Python.
Say, a = 100.
Why is a.to_bytes(2, "big") not b"\x00\x64" but b"\x00d"?
Seems to me that b"\x00d" is not even 2 bytes.
b"\x00d" means 2 bytes: \x00 and d but for values which are correct char codes (which are "printable") Python displays chars instead of codes. It makes it more readable when it may have readable text.
And chr(0x64) gives d
But if you use .hex() then you can get string 0064, and with .hex(":") you can get 00:64 (but it can't use .hex("\\x"))
If you want only codes \x... then you may have to convert it to string on your own (for example using for-loop and f-string)
a = 100
b = a.to_bytes(2, "big")
print('chr(0x64) :', chr(0x64))
print('b :', b)
print('b.hex() :', b.hex())
print('b.hex(":"):', b.hex(':'))
# ------------------------------------
items = []
for value in b:
items.append( f'\\x{value:02x}' )
text = "".join(items)
print('text:', text)
# shorter
print('text:', "".join(f'\\x{q:02x}' for q in b) )
Result:
chr(0x64) : d
b : b'\x00d'
b.hex() : 0064
b.hex(":"): 00:64
text: \x00\x64
text: \x00\x64

split python bytearray character by character

So, I've got some python code
string = "Python is interesting."
arr = bytearray(string, 'utf-8')
arr.split(b'\'')
which I adapted from Split String by char Character
but it returns a
[bytearray(b'Python is interesting.')]
I was hoping to split it byte-by-byte. The end goal is to pass this to a C++ boost wrapper which expects an array of bytes character-by-character. I'm using a bytearray because I'm actually working with sockets and for a given large message I want to accumulate them.
expected_length = _get_obj_size(socket)
running_length = 0
accumulator = bytearray(b'')
while running_length < expected_length:
msg = socket.recv(BUFFER_SIZE)
if msg:
running_length += len(msg)
accumulator += msg
logger.debug("Finished reading in payload")
^ the above isn't particularly relevant but I felt like it might be useful to show why I'm doing what I'm doing.
Taking the hint from #Epsi95 what about:
[chr(x) for x in list(arr)]

Bytes with escape for re module

import re
a = 0xf27f28d7
b = a.to_bytes(4, 'little')
with open(fimage, 'rb') as f:
print([hex(m.start(0)] for m in re.finditer(b, f.read()))
# b = b'\xd7(\x7f\xf2'
above code return error:
missing ), unterminated subpattern at position 1
I know the bytes includes a (. It should be \(. How to convert to byte to ensure no error with escape?
I am using Python 3.6. Thanks in advance.
You can convert your bytes somehow like that
b = b'\xd7(\x7f\xf2'
b = ''.join(['\\x'+hex(c)[2:] for c in b]).encode()
You can use re.escape(), but it will also escape bytes that don't correspond to printable characters, so you'll need to filter them out.
import re
b = b'\xd7(\x7f\xf2'
k = []
for i in b:
i_bytes = bytes([i])
if i < 0x80 and chr(i).isprintable():
i_bytes = re.escape(i_bytes)
k.append(i_bytes)
print(b''.join(k)) # -> b'\xd7\\(\x7f\xf2'
I'm sure this code could be improved, just not sure how.

How to resolve AssertionError for converting string characters to bytes using run length encoding?

I have a problem to solve but once I submit my solution the result shows an AssertionError.
I want to be able to convert my string of characters into a byte format using a technique called run-length encoding - https://en.wikipedia.org/wiki/Run-length_encoding
I was doing some research on it and found that what I felt done by me was correct but the solution was apparently not correct on the website and I get this: AssertionError: 'a5b6c4' is not an instance of <class 'bytes'> : compress('') should return bytes
My code:
from collections import OrderedDict
def compress(raw=str)->bytes:
dict=OrderedDict.fromkeys(my_str_as_bytes, 0)
for ch in my_str_as_bytes:
dict[ch] += 1
output = ''
for key,value in dict.items():
output = output + key + str(value)
return output
my_str_as_bytes = "aaaaabbbbbbcccc"
print (bytes(compress(my_str_as_bytes,),encoding='UTF-8'))
The result on my IDE was:
b'a5b6c4'
I'm not sure of what I did is encoding the string and changing it into a byte or not. Any help would be appreciated.
Few of the links I checked:
https://www.tutorialspoint.com/run-length-encoding-in-python
https://www.geeksforgeeks.org/run-length-encoding-python/

Backporting bytearray to Python 2.5

I'm trying to convert this websocket example for use in Python 2.5, but am running into errors with the use of the bytearray type.
The code stops working for Python 2.5 here (in the send_text method of websocket_server/websocket_server.py):
FIN = 0x80
OPCODE = 0x0f
def send_text(self, message):
header = bytearray();
payload = encode_to_UTF8(message)
payload_length = len(payload)
header.append(FIN | OPCODE_TEXT)
header.append(payload_length)
self.request.send(header + payload)
The message variable stores the string input that is sent to clients.
It attempts to create an array of bytes and send that using the self.request.send method. How would I change this to make it work in Python 2.5 which doesn't have the bytes type or bytearray?
Using struct MIGHT work, I haven't tested this.
What I would do, as a workaround, would be to use struct.pack to pack byte by byte.
mensaje = "saludo"
FIN = 0x80
OPCODE = 0x0f
payload = ''
for c in mensaje:
payload += struct.pack("H", ord(c))
msj = struct.pack("H",FIN | OPCODE )
msj+= struct.pack("H",len(payload))
print msj + payload
I'm using "H" as the 'fmt' parameter in the struct.pack function, but you better check how is your package sent and how many bytes per 'character' (since I'm guessing you're using unicode, I'm using 'H', unsigned short = 2 bytes).
More info: https://docs.python.org/2/library/struct.html, section 7.3.2.1 and 7.3.2.2.
EDIT:
I'll answer here, what do I mean by using 'chr()' instead of 'struct.pack()':
mensaje = "saludo"
FIN = 0x80
OPCODE = 0x0f
payload = mensaje
msj = chr( FIN | OPCODE )
msj+= chr(len(payload))
print msj + payload
if you print the message, then you should see the same output when using struct.pack("B", ord(something)) than when using ord(something), I just used struct.pack() because I thought your message was two bytes per char (as unicode).

Categories