Reputation: 553
Trying to import a code from python2 to python 3 and this problem happens
<ipython-input-53-e9f33b00348a> in aesEncrypt(text, secKey)
43 def aesEncrypt(text, secKey):
44 pad = 16 - len(text) % 16
---> 45 text = text.encode("utf-8") + (pad * chr(pad)).encode("utf-8")
46 encryptor = AES.new(secKey, 2, '0102030405060708')
47 ciphertext = encryptor.encrypt(text)
AttributeError:'bytes' object has no attribute 'encode'
If I remove .encode("utf-8")
the error is "can't concat str to bytes". Apparently pad*chr(pad)
seems to be a byte string. It cannot use encode()
<ipython-input-65-9e84e1f3dd26> in aesEncrypt(text, secKey)
43 def aesEncrypt(text, secKey):
44 pad = 16 - len(text) % 16
---> 45 text = text.encode("utf-8") + (pad * chr(pad))
46 encryptor = AES.new(secKey, 2, '0102030405060708')
47 ciphertext = encryptor.encrypt(text)
TypeError: can't concat str to bytes
However, the weird thing is that if i just try the part along. encode() works fine.
text = { 'username': '', 'password': '', 'rememberLogin': 'true' }
text=json.dumps(text)
print(text)
pad = 16 - len(text) % 16
print(type(text))
text = text + pad * chr(pad)
print(type(pad * chr(pad)))
print(type(text))
text = text.encode("utf-8") + (pad * chr(pad)).encode("utf-8")
print(type(text))
{"username": "", "password": "", "rememberLogin": "true"}
<class 'str'>
<class 'str'>
<class 'str'>
<class 'bytes'>
Upvotes: 20
Views: 116009
Reputation: 553
Thanks to @Todd, he solved issue.
(pad * chr(pad))
is bytes while problems lies with aesEncrypt(text, secKey)
. It has been called twice with text
as str
for the first time while as bytes
for the second time.
The solution is to make sure that the input text
is of str
type.
Upvotes: 2
Reputation: 5395
If you don't know if a stringlike object is a Python 2 string (bytes) or Python 3 string (unicode). You could have a generic converter.
Python3 shell:
>>> def to_bytes(s):
... if type(s) is bytes:
... return s
... elif type(s) is str or (sys.version_info[0] < 3 and type(s) is unicode):
... return codecs.encode(s, 'utf-8')
... else:
... raise TypeError("Expected bytes or string, but got %s." % type(s))
...
>>> to_bytes("hello")
b'hello'
>>> to_bytes("hello".encode('utf-8'))
b'hello'
On Python 2 both these expressions evaluate to True
: type("hello") == bytes
and type("hello") == str
. And type(u"hello") == str
evaluates to False
, while type(u"hello") == unicode
is True
.
On Python 3 type("hello") == bytes
is False
, and type("hello") == str
is True
. And type("hello") == unicode
raises a NameError
exception since unicode
isn't defined on 3.
Python 2 shell:
>>> to_bytes(u"hello")
'hello'
>>> to_bytes("hello")
'hello'
Upvotes: 8
Reputation: 1946
Since the first parameter of AES.new
is bytes/bytearray/memoryview, and I assume that text
is already of type bytes
, then we just have to convert the pad part from unicode
to bytes
.
text = text + (pad * chr(pad)).encode("utf-8")
To be extra safe, you may encode text
conditionally before concatenating with pad.
if not isinstance(text, bytes):
text = text.encode('utf-8')
Upvotes: 0