0

I am making an AES encryption/decryption program using PyAES, and when I print an output, it looks like this:

b'\xb6\xd52#\xb1\xd5a~.L\xc2M\x83U\xb3\xf6' (encrypted)

b'TextMustBe16Byte' (plaintext)

I want to eliminate the b and the apostrophes so that it looks cleaner on the front end.

My code:

import pyaes
import os

# A 256 bit (32 byte) key
key = os.urandom(32)

# For some modes of operation we need a random initialization vector
# of 16 bytes
iv = os.urandom(16)

aes = pyaes.AESModeOfOperationCBC(key, iv = iv)
plaintext = "TextMustBe16Byte"
ciphertext = aes.encrypt(plaintext)

# '\xd6:\x18\xe6\xb1\xb3\xc3\xdc\x87\xdf\xa7|\x08{k\xb6'
print(ciphertext)


# The cipher-block chaining mode of operation maintains state, so
# decryption requires a new instance be created
aes = pyaes.AESModeOfOperationCBC(key, iv = iv)
decrypted = aes.decrypt(ciphertext)
print(decrypted)
Fukiyel
  • 1,166
  • 7
  • 19
Thorn
  • 3
  • 3

1 Answers1

0

bytes objects use their repr (with b and quotes) when stringified normally. If you want to convert to an equivalent string, the simplest approach is to decode them as latin-1 (latin-1 is a 1-1 encoding that converts each byte to the Unicode ordinal of the same value).

So just change:

print(ciphertext)

to:

print(ciphertext.decode('latin-1'))

and:

print(decrypted)

to:

print(decrypted.decode('latin-1'))

It looks like aes.encrypt is implicitly "encoding" the input string in latin-1 (it's doing [ord(c) for c in text] which is effectively encoding to latin-1 without actually checking that the characters are legal latin-1; characters with ordinals above 255 will likely explode later in processing), so this is a reasonable solution, given the limitations of the module. If you want to support non-latin-1 inputs, make sure to encode the input to encrypt with better encoding (e.g. utf-8), and decode with the same encoding at the other end (you'll want to use latin-1 for the ciphertext no matter what though; it's raw random bytes, so any other encoding makes no sense).

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • That returned the error `UnicodeEncodeError: 'charmap' codec can't encode character '\x96' in position 0: character maps to `. – Thorn Mar 08 '19 at 03:50
  • @Thorn: Sounds like your locale encoding doesn't know how to represent that character and is giving up. This is [a known problem on Windows](https://stackoverflow.com/q/32694994/364696). You might be better off doing `print(x.hex())` to get the hex output of the ciphertext (likely more useful than trying to decode at all). – ShadowRanger Mar 09 '19 at 02:29
  • It seemed to be a problem with the script package on Atom, since running with a dedicated Python runner, it worked. However, the string "If Purple People Eaters are real… where do they find purple people to eat?" showed the error `ValueError: bytes must be in range(0, 256)`. – Thorn Mar 09 '19 at 02:46
  • @Thorn: You had an ellipsis (…) in your string, which doesn't occur in `latin-1`. That's why I mentioned switching to `utf-8` to encode the initial string and decode the final string. – ShadowRanger Mar 09 '19 at 15:58