osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

py2 to 3 base64 issues


On Fri, Aug 9, 2019 at 3:17 PM MRAB <python at mrabarnett.plus.com> wrote:
>
> On 2019-08-09 19:21, Larry Martell wrote:
> > On Fri, Aug 9, 2019 at 12:23 PM Chris Angelico <rosuav at gmail.com> wrote:
> >>
> >> On Sat, Aug 10, 2019 at 2:09 AM Larry Martell <larry.martell at gmail.com> wrote:
> >> >
> >> > I have some python 2 code:
> >> >
> >> > def decode(key, string):
> >> >        decoded_chars = []
> >> >        string = base64.urlsafe_b64decode(string)
> >> >        for i in range(len(string)):
> >> >            key_c = key[i % len(key)]
> >> >            encoded_c = chr(abs(ord(string[i]) - ord(key_c) % 256))
> >> >            decoded_chars.append(encoded_c)
> >> >        decoded_string = "".join(decoded_chars)
> >> >        return decoded_string
> >> >
> >> > and if I call it like this in py2 it works as expected:
> >> >
> >> > s = 'V3NYVY95iImnnJWCmqphWFFzU1qvqsV6x83Mxa7HipZitZeMxbe709jJtbfW6Y6blQ=='
> >> > key = '!@#$VERYsecRet)('
> >> > decode(key, s)
> >> >
> >> > In py3 it fails with
> >> >
> >> > TypeError: ord() expected string of length 1, but int found
> >> >
> >> > I know that in py3 base64.urlsafe_b64decode is returning bytes not
> >> > chars and that is what that is happening, and I thought the solution
> >> > would be to decode it, but what codec would I use for this?
> >>
> >> Should be safe to decode it as ASCII, since Base 64 uses strictly
> >> ASCII characters. But since you're working with bytes, possibly all
> >> you need to do is remove the ord calls, since ord(u"x") is the same as
> >> b"x"[0]. You'll then need to change the join() at the end to be just
> >> "decoded_string = bytes(decoded_chars)", or possibly that followed by
> >> a decode-to-text, depending on how your data works.
> >
> > That doesn't work:
> >
> > -> encoded_c = chr(abs(string[i] - ord(key_c) % 256))
> > (Pdb) n
> > TypeError: "unsupported operand type(s) for -: 'str' and 'int'"
> > (Pdb) string
> > 'WsXU\x8fy\x88\x89\xa7\x9c\x95\x82\x9a\xaaaXQsSZ\xaf\xaa\xc5z\xc7\xcd\xcc\xc5\xae\xc7\x8a\x96b\xb5\x97\x8c\xc5\xb7\xbb\xd3\xd8\xc9\xb5\xb7\xd6\xe9\x8e\x9b\x95'
> > (Pdb) string[i]
> > '\x8f'
> > (Pdb) bytes(string[i])
> > '\x8f'
> > (Pdb) type(string[i])
> > <type 'str'>
> >
> 'string' is a 'str' (in Python 2 that would've been 'unicode'), so
> string[i] is also a 'str' and you need 'ord':
>
> encoded_c = chr(abs(ord(string[i]) - ord(key_c) % 256))

My bad - I was mistakenly running it in 2.7 - in 3.7 it's working like this:

def decode(key, string):
    decoded_chars = []
    string = base64.urlsafe_b64decode(string)
    for i in range(len(string)):
        key_c = key[i % len(key)]
        encoded_c = chr(abs(string[i] - ord(key_c) % 256))
        decoded_chars.append(encoded_c)
    decoded_string = "".join(decoded_chars)
    return decoded_string

Thanks all!