rnso
rnso

Reputation: 24555

Python2 version of this python3 code for encoding

I am trying to run code from the answer in this post (which works perfectly with python3 version 3.5.3) with python2 version 2.7.13:

def myencode_str(ori_str, key):
    enc = []
    for i in range(len(ori_str)):
        key_c = key[i % len(key)]
        enc_c = (ord(ori_str[i]) + ord(key_c)) % 256
        enc.append(enc_c)
    return (base64.urlsafe_b64encode(bytes(enc))).decode("utf-8") 

I am using following decode fn:

def mydecode(enc_str, key):
    dec = []
    enc_str = base64.urlsafe_b64decode(enc_str)
    for i in range(len(enc_str)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + enc_str[i] - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

But I get following error message:

    dec_c = chr((256 + enc_str[i] - ord(key_c)) % 256)
TypeError: unsupported operand type(s) for +: 'int' and 'str'

I tried code with following changes but they also do not work:

    dec_c = chr((256 + int(enc_str[i]) - int(ord(key_c))) % 256)
ValueError: invalid literal for int() with base 10: '\xc3'

Where is the problem and how can it be solved?

Upvotes: 1

Views: 302

Answers (1)

Serge Ballesta
Serge Ballesta

Reputation: 148965

The problems is that bytes constructor has changed between Python2 and Python3, when it receives an list of integers:

  • in Python3, it builds a byte string where each byte receives a code from the list
  • in Python2, it just converts the list to a string (by using the representation or the string)

And in Python3 a byte string is an iterable of bytes (which are directly convertible to integers) while it is a mere string in Python2.

So your functions have to be a little changed:

def myencode_str(ori_str, key):
    enc = []
    for i in range(len(ori_str)):
        key_c = key[i % len(key)]
        enc_c = (ord(ori_str[i]) + ord(key_c)) % 256
        enc.append(enc_c)
    return (base64.urlsafe_b64encode(''.join([chr(i) for i in enc])))

def mydecode(enc_str, key):
    dec = []
    enc_str = [ord(i) for i in base64.urlsafe_b64decode(enc_str)]
    for i in range(len(enc_str)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + enc_str[i] - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

In fact, it is possible to write those functions so that same code can be used in both Python2 and Python3 with the help of the bytearray class which has same behaviour in both versions. Simply you must choose whether the input is a byte string or a unicode string. As the algorythm is based on bytes, I choosed to process byte strings in following code. You would need to encode the original string and key (using 'utf8' for full portability) and decode the decoded string to process unicode strings:

def myencode_str(ori_str, key):
    enc = []
    b = bytearray(ori_str)
    k = bytearray(key)
    for i, c in enumerate(b):
        key_c = k[i % len(key)]
        enc_c = (c + key_c) % 256
        enc.append(enc_c)
    return (base64.urlsafe_b64encode(bytes(bytearray(enc))))

def mydecode(enc_str, key):
    dec = []
    enc_str = bytearray(base64.urlsafe_b64decode(enc_str))
    k = bytearray(key)
    for i, c in enumerate(enc_str):
        key_c = k[i % len(key)]
        dec_c = (c - key_c) % 256
        dec.append(dec_c)
    return bytes(bytearray(dec))

You can then do in Python2:

>>> myencode_str(b"abcdef", b"XYZ")
'ubu9vL7A'
>>> mydecode('ubu9vL7A', b"XYZ")
'abcdef'

and in Python3:

>>> myencode_str(b"abcdef", b"XYZ")
b'ubu9vL7A'
>>> mydecode(b'ubu9vL7A', b"XYZ")
b'abcdef'

Upvotes: 2

Related Questions