0

My problem is that when I use pycryptodome for decrypting a string in Python 3.6 with the following code:

from Crypto.Cipher import AES
from Crypto import Random

key = "133BBB3212332231"
key_bytestring = key.encode("utf-8")
iv = Random.new().read(AES.block_size)
cipher = AES.new(key_bytestring, AES.MODE_CFB, iv)
encrypted_string = 'ý\x82iq\x193\x1aÙË\x04Û£¥\x8dbBOW}Vû\x01\x86zÕ¼Ó)áôO\x14'
encrypted_bytes = encrypted_string.encode("utf-8")
decrypted_bytes = cipher.decrypt(encrypted_bytes)
decrypted_string = decrypted_bytes.decode("utf-8")
print(decrypted_string )

Python throws this error: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbf in position 1: invalid start byte

In this line:

decrypted_string = decrypted_bytes.decode("utf-8")

I'm updating some code from Python 2.7, and pycrypto has changed to pycryptdodome. In python 2.7 this works like a charm with pycrypto(I've invented the key so the string is not decrypted well but Python don't throw any error):

from Crypto.Cipher import AES
from Crypto import Random

key = "133BBB3212332231"
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
encrypted_string = 'ý\x82iq\x193\x1aÙË\x04Û£¥\x8dbBOW}Vû\x01\x86zÕ¼Ó)áôO\x14'
decrypted_string = cipher.decrypt(encrypted_string)
print(decrypted_string)

How can I fix this? I'm quite desperate, since I've been trying it for a long time and I did't come to anything. Thank you in advance!

edusan1213
  • 359
  • 5
  • 15
  • I'm getting byte 0xc0 instead of 0xbf. What is the output of the Python 2.7 version? – nnnmmm Jan 31 '18 at 08:46
  • 1
    You changed the key and expect the result of decrypting a string to be valid utf-8? If you encrypt something, the output will be binary data, so having it in the form of an "encrypted string" doesn't make much sense. How exactly did you produce this string? – mata Jan 31 '18 at 08:55
  • This was just an example, because in the real project I receive data in real time. I edited the question with the real KEY and a real encrypted message received, so the key and the data corresponds. Sorry, I thought that an example would be enough to explain the problem – edusan1213 Jan 31 '18 at 09:11
  • Receive from where? How? How did it end up in your code? You probably copied that string from somewhere... What is the result in python2 (`repr(decrypted_string)`)? The string you start with contains non-ascii characters, so its actual content depends on the file encoding. – mata Jan 31 '18 at 13:36

2 Answers2

2

First you should know how Python 3 treats strings differently than in Python 2.

In Python 2, "" is a byte array, but in Python 3 it's a unicode string. Both cipher.encrypt and cipher.decrypt expect byte arrays.

So even though in both pieces of code, the type of your parameter is fine. Your problem in Python 3 is with calling str.encode. It's pretty easy to see that it indeed caused a change by looking at the string length:

>>> len(encrypted_string)
10
>>> len(encrypted_string.encode('utf-8'))
14

The solution:

First of all notice that in Python 2:

>>> "¨vóîÄdX|@9" == '\xc2\xa8v\xc3\xb3\xc3\xae\xc3\x84dX|@9'
True

In Python 3, you need to mark your string with the binary prefix (b""), your new definition should use: encrypted_bytes = b'\xc2\xa8v\xc3\xb3\xc3\xae\xc3\x84dX|@9'

Thus your solution should be:

from Crypto.Cipher import AES
from Crypto import Random

key = "18945BKJVO9W834G"
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
encrypted_bytes = b'\xc2\xa8v\xc3\xb3\xc3\xae\xc3\x84dX|@9'
decrypted_bytes = cipher.decrypt(encrypted_bytes)
print(decrypted_bytes)
Hetzroni
  • 2,109
  • 1
  • 14
  • 29
  • In my real project I receive data in real time in one variable. How can I do this if my string is in one variable?. I've edited my question with the real KEY and a real message received to clarify the problem – edusan1213 Jan 31 '18 at 09:20
  • You need to propagate the transition from `str` to `bytes` back to where you receive the message from. For example, if it's from a file, use `rb` instead of `r`. Remember, you can only encrypt/decrypt byte arrays, not textual strings. – Hetzroni Feb 01 '18 at 10:40
0

like this :

from Crypto.Cipher import AES
from Crypto import Random

key = "18945BKJVO9W834G"
key_bytestring = key
iv = Random.new().read(AES.block_size)
cipher = AES.new(key_bytestring, AES.MODE_CFB, iv)
encrypted_string = "¨vóîÄdX|@9"
encrypted_bytes = encrypted_string 
decrypted_bytes = cipher.decrypt(encrypted_bytes)
decrypted_string = decrypted_bytes
print(repr(decrypted_string))

Short description : Byte and String got same pattern, does not require any correction. Consider how the system is perceived if you do any encoding operation.Cryptographic logic is a byte-based function, which is not very important to which encoding system you are using. If the input/output or output/input is important to you why do you change the encoding setting of the characters? Computers cannot read and write!

dsgdfg
  • 1,492
  • 11
  • 18
  • If I do that, I got this error: **TypeError: Only byte strings can be passed to C code** when I pass encrypted_bytes to decrypt function. I've edited my question with the real KEY and a real message received to clarify the problem – edusan1213 Jan 31 '18 at 09:19
  • You don't undestand my description, key is not important on **same script** ! Your question maybe : `How to protect data on any encode/decode operation ?` **source[Base64] >> target[base64]** if generator and resolver script not same script, got a lot encoding/decoding problems. – dsgdfg Feb 01 '18 at 12:41