2

I want to do an AES encryption and decryption to string. but the key and message must be in bytes, so I converted the message to bytes by doing this:

b"string"

This is my AES code:

# Encryption
encryption_suite = AES.new(b'1234567812345678', AES.MODE_OCB)
cipher_text = encryption_suite.encrypt(b"A really secret message. Not for prying eyes.")

# Decryption
decryption_suite = AES.new(b'1234567812345678', AES.MODE_OCB)
plaintext = decryption_suite.decrypt(cipher_text)

however i need to turn the decrypted plain text back to string to be readable. Currently the plaintext looks like this:

b'x\x85\x92\x9d\xe6\x0bJ\xfe\x9b(\x10G\x8e\x05\xc5\xf4\xcdA9\xc18\xb8_\xf9vbmK\x16\xf8\xa3\xb6'

I tried using

plaintext.decode(encoding='windows-1252')

and

plaintext.decode("utf-8").strip('\x00')

but all i get is this:

UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in position 3: character maps to

or this:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb1 in position 1: invalid start byte

I need to convert these bytes back to a readable string.. if you can help, that would be appreciated.

14
  • this question was a lot of help but i couldnt understand how to apply it to my case.. also a lot of the answers were python 2 stackoverflow.com/questions/1220751/… Commented May 23, 2018 at 6:37
  • Hi, if you are getting back the plaintext from above code then something is wrong in your script. The plaintext should look the same as the paintext you use as input at the beginning... so you should be getting Commented May 23, 2018 at 6:54
  • @ZaphoOxx as you can see the encryption and decryption methods are pre-defined so i am sure the output is correct. the problem is that the input has to look like those bytes in order for the functions to work, so naturally the output looks like that too. Commented May 23, 2018 at 7:02
  • Which module are you using to do the crypto? It looks like pycrypto, but I have pycrypto 2.6.1, and it doesn't support AES.MODE_OCB. Commented May 23, 2018 at 7:30
  • 1
    Seriously, how can you think it works if the initial input and decrypted output dont match ? Think about it. b"my message" is encrypted. once you decrypt the cipher you should get back exactly the same. otherwise the whole encryption doesnt make sense. does it ? Commented May 23, 2018 at 8:14

3 Answers 3

13

The main issue with your code is that you don't supply a nonce to AES.new(). OCB requires a nonce; if you don't supply one a random nonce will be created every time you create a new AES object, and so decryption will fail.

From the docs:

nonce (byte string): a non-repeatable value, of length between 1 and 15 bytes.. If not present, a random nonce of the recommended length (15 bytes) will be created.

You have two options, either create a nonce and pass it to AES.new() (in encryption and decryption) or use the random nonce created by AES during encryption.

Next, OCB is an authenticated encryption algorithm but it seems that you don't check the MAC. This is important because the MAC verifies the integrity of the ciphertext.

The encryption and decryption methods of AES accept and return bytes. You can convert the plaintext (if it is text) to string with .decode(). If you want to convert the ciphertext to string you'll have to base64-encode it first, in order to encode the raw bytes to ASCII characters (just remember to decode before decryption). b64encode() also returns bytes but can be converted to string easily.

An example,

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from base64 import b64encode

key = get_random_bytes(16) # A 16 byte key for AES-128
nonce = get_random_bytes(15)
message = "A really secret message. Not for prying eyes.".encode()

cipher = AES.new(key, AES.MODE_OCB, nonce=nonce)
ciphertext, mac = cipher.encrypt_and_digest(message)

cipher = AES.new(key, AES.MODE_OCB, nonce=nonce)
plaintext = cipher.decrypt_and_verify(ciphertext, mac)

print(b64encode(ciphertext).decode())
#CSwHy3ir3MZ7yvZ4CzHbgYOsKgzhMqjq6wEuutU7vJJTJ0c38ExWkAY1QkLO
print(plaintext.decode())
#A really secret message. Not for prying eyes.

Note that if .decrypt_and_verify() fails to verify the MAC a ValueError exception will be raised, so you may want to use a try-except block. The nonce and mac values are not secret and it's safe to store them next to the ciphertext.

Finally, if you plan to derive a key from a passphrase you should use a password-based KDF. KDFs create strong keys, use salt and iterations, and they are very resistant to fruteforce attacks. You will find KDF functions in Crypto.Protocol.KDF.

Sign up to request clarification or add additional context in comments.

3 Comments

thanks that did work! I have another question if you could help: do you know how i could rid the string of " b' ' " ? i tried string[2: ] but it just removes part of the string itself not the b
The b'' means that your string is binary, and it's not part of the actual string. If you want to turn your decrypted plaintext to unicode string, use decode. See updated code. If you want to convert the ciphertext to string, you'll have to base64 encode it first.
Hi @t.m.adam, hope you are doing well. I will be glad if you care to give this post a go to offer any solution. Thanks.
1

You can't convert binary data to a string because it is inherently not a string. It's binary data. The chances of the output of your encryption just happening, by chance, to be a correctly formatted UTF8 string is pretty unlikely.

You should look at base64 instead. It bloats the data (3 bytes to 4 characters) but is better suited for your use case.

EDIT:. My mistake, I misunderstood your question. The output you have isn't correct, the first byte is not a '1' in UTF8. This is likely an issue with the encryption/decryption.

2 Comments

thank you for your response.. i am not trying to convert the cipher text , only the plain text from the decryption.
i tried base64 but its ouptut is like so: ZGF0YSB0byBiZSBlbmNvZGVk. which the aes does not accept
1

I think your encoding is "ISO-8859-1". So you can do:

plaintext.decode("ISO-8859-1")

1 Comment

This should be the correct answer. How did you figure out the encoding?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.