Reputation: 3529
I'm trying to use pyaes (https://github.com/ricmoo/pyaes/blob/master/README.md) in Python 3 to encrypt and decrypt text using pyaes. When I encrypt text, I give pyaes a str
value i.e.
plaintext = 'plain text'
key = os.urandom(16)
aes = pyaes.AESModeOfOperationCTR(key)
ciphertext = aes.encrypt(plaintext)
when I decrypt though, I get back a bytes
type:
aes = pyaes.AESModeOfOperationCTR(key)
decrypted_plaintext = aes.decrypt(ciphertext)
Printing decrypted_plaintext
produces the following output, which seems to contain the original text:
b'plain text'
But its not quite the same; one is a str
the other is a bytes
:
plaintext == decrypted_plaintext # False
I'm struggling to understand the relationship between bytes
and whatever Python 3's internal representation of str
is. How do I convert the bytes
type into str
to get my plaintext?
I have confirmed that running the examples on the pyaes readme page have the same problem. I'm guessing that is going to be something to do with encodings.
Upvotes: 2
Views: 1715
Reputation: 41
for all others, this can help you: if decrypted.decode('utf-8') == plaintext:
# A 256 bit (32 byte) key
key = b"This_key_for_demo_purposes_only!"
aes = pyaes.AESModeOfOperationCTR(key)
plaintext = "Text may be any length you wish, no padding is required"
ciphertext = aes.encrypt(plaintext)
# '''\xb6\x99\x10=\xa4\x96\x88\xd1\x89\x1co\xe6\x1d\xef;\x11\x03\xe3\xee
# \xa9V?wY\xbfe\xcdO\xe3\xdf\x9dV\x19\xe5\x8dk\x9fh\xb87>\xdb\xa3\xd6
# \x86\xf4\xbd\xb0\x97\xf1\t\x02\xe9 \xed'''
print (repr(ciphertext))
# The counter mode of operation maintains state, so decryption requires
# a new instance be created
aes = pyaes.AESModeOfOperationCTR(key)
decrypted = aes.decrypt(ciphertext)
print(type(decrypted))
print(type(plaintext))
# True
if decrypted.decode('utf-8') == plaintext:
print(plaintext)
print(True)
print(decrypted.decode('utf-8'))
# '''WZ\x844\x02\xbfoY\x1f\x12\xa6\xce\x03\x82Ei)\xf6\x97mX\x86\xe3\x9d
# _1\xdd\xbd\x87\xb5\xccEM_4\x01$\xa6\x81\x0b\xd5\x04\xd7Al\x07\xe5
# \xb2\x0e\\\x0f\x00\x13,\x07'''
print (repr(ciphertext))
Upvotes: 0
Reputation: 6209
In Python 3 str
type represents a string in unicode format. It is composed of relatively abstract codepoints, that is numbers coding characters.
There are several ways to transform (encode) those codepoints to actual bytes which are known as "encodings". utf-8 and utf-16 are some encodings which allow to encode unicode characters.
Note that some encoding (as ASCII) does not allow to encode unicode characters.
When you encode a str
string in Python, you obtain a list of bytes of type bytes
. You can then decode this list of bytes to get a str
string.
The point to keep in mind is that you have to specify an encoding to encode a str
string and you have to know the encoding of a bytes
string to be able to decode it. If you don't specify encoding, Python will try to encode and decode with its default encoding and you could obtain "random" results.
In you specific case, the difference is not visible because all the characters of your strings are ASCII chars and, fortunately, the 128 first codepoints of unicode match the ASCII table.
Try to introduce some 'exeotic' characters (like é, ç or Ë) in your string and you will see a difference.
Now, pyaes does not encrypt/decrypt unicode codepoints but bytes. So you have to encode the strings you encrypt and you have to know the used encoding to decode the decrypted strings.
More information in the Python doc:
Upvotes: 1
Reputation: 17051
decrypted_plaintext.decode()
will give you a str
, which will most likely be what you want. A bytes
object is a raw string of bytes in an unspecified encoding. To convert that to a str
, you have to tell Python to decode it using decode()
. decode()
defaults to UTF-8, but you can tell it which encoding to use.
I just took a glance at the source and I see nothing encoding-specific, so the encoding of the decrypted string should match that of the encrypted string.
Upvotes: 0