1

I have a serial to TCP device which is receiving data via rs232, encrypting that data, then forwarding to a TCP server. The documentation for the device's encryption methodology is borderline nonexistent, only that its 128, 192, or 256 bit AES encryption(configurable). Judging from some other context clues in the documentation, I'm seeing that it is likely utilizing either CBC or CFB mode of operation(though that could be wrong as well). And no, I have no insight into the nature of the IV in the documentation. Perhaps its prepended to the encrypted data?

For development purposes, I have the same RS232 data going to two different devices: one is configured to encrypt the data, the other is configured to send in plaintext. Below is the same data in both plaintext and encrypted format.

Plaintext:

 b'\r\x00\nLocal: \r\x00\nACCESS            by user 5                                    22:49:32 03/07/11\r\x00\n'

Encrypted:

b'$+\xf5Sq\x1aBC\xbe\t\x8f2\x0b\xf9\xdc!\x80By2\xbb\x10k\x03G\xbb\x85\xd5u\x1dM\xeb\xfd\xa8\xf4\xa13GX|\x06\x0e\xa7K\x0f\xbc\xca\x82js)Q\xff\xbc\xbd\xe2\x05mfJ\xe7g\xdc\xd3b\xff_O\xaeNDH\xb4\x8e\xb7\xbf$2\xba\xe6\xd1\x1bu\n\xe2\x05\xae\x1a\xfc\xd7v\x06\xe6/^&v\xd4\x1a-\x0f\x16o\xc7\xeb\xc4\x90h\xe9'

Key is 64 hex characters (obviously I'll change this): 566B59703373367638792F423F4528482B4D6251655468576D5A713474377721

So when I run the following code against it, (attempting both CFB and CBC mode) I don't get anything human-readable.

from Crypto.Cipher import AES

encrypted_data = b"$+\xf5Sq\x1aBC\xbe\t\x8f2\x0b\xf9\xdc!\x80By2\xbb\x10k\x03G\xbb\x85\xd5u\x1dM\xeb\xfd\xa8\xf4\xa13GX|\x06\x0e\xa7K\x0f\xbc\xca\x82js)Q\xff\xbc\xbd\xe2\x05mfJ\xe7g\xdc\xd3b\xff_O\xaeNDH\xb4\x8e\xb7\xbf$2\xba\xe6\xd1\x1bu\n\xe2\x05\xae\x1a\xfc\xd7v\x06\xe6/^&v\xd4\x1a-\x0f\x16o\xc7\xeb\xc4\x90h\xe9"

key = bytes.fromhex("566B59703373367638792F423F4528482B4D6251655468576D5A713474377721")


def decrypt(data, key):

    print("Encrypted data: ", data)


    #trying CFB mode
    cipher = AES.new(key, AES.MODE_CFB)
    pt = cipher.decrypt(data)
    print("CFB mode outputs: ", pt)

    #now trying CBC mode
    #padding data per CBC requirements
    length = 16 - (len(data) % 16)
    data += bytes([length]) * length
    cipher = AES.new(key, AES.MODE_CBC)
    pt = cipher.decrypt(data)
    print("CBC mode outputs: ", pt)


decrypt(encrypted_data, key)

Output:

Encrypted data:  b'$+\xf5Sq\x1aBC\xbe\t\x8f2\x0b\xf9\xdc!\x80By2\xbb\x10k\x03G\xbb\x85\xd5u\x1dM\xeb\xfd\xa8\xf4\xa13GX|\x06\x0e\xa7K\x0f\xbc\xca\x82js)Q\xff\xbc\xbd\xe2\x05mfJ\xe7g\xdc\xd3b\xff_O\xaeNDH\xb4\x8e\xb7\xbf$2\xba\xe6\xd1\x1bu\n\xe2\x05\xae\x1a\xfc\xd7v\x06\xe6/^&v\xd4\x1a-\x0f\x16o\xc7\xeb\xc4\x90h\xe9'
CFB mode output:  b'\xd3I\x95@[\xbeA\x15"W\xf4|\x7f\x93\x9d]\r\x10\xca\x9e\xc2\x9f\x8b\xfcDp :\x94\xdb\x85tS\xc4\xf4Lc\xe4\xa45\xa1{\x07\x0fOT\xbe\xe7u\x82\x8d\x01\x9a\x91A\xd6\x0f\x83\xe8\xf8\x80HP\x83 pu\xbaG\xae\xeb.\x9cTF\x17!\xa6\x0c) \xa8\xe7\x07\xf6J\'\xa7\xbc\x05\xcf\\\x7f\x1a.\xe83n\xe2<\xb7\xe51\xdcZ\\\x8b\xb2\xf2'
CBC mode output:  b'\x8d\x1f\xaf@\x8c\xab\xb7\xf5\x1a}\x05b@\xcf\xd7L\xaa\xcc\x1a6\x82\xd3)\xee\xc2\x03\xc7\xe6k\x04P+\x0b>\xc1\x9d\xf5S\x0c\x17\xaf\xf6\x1dV\xe2\xa4\x0e\x98[\xdd\xcd6\xb6\xde,\x8f\xdfS\xc2\xc3h\xc7x\xee\x10IFM\xb0\x11K\xd87\xec\x86\xc8\xac\xff\xdb\t\x19i9\xa1\xbe\xf5\x153\xfdv)\x8d\x0b\x1e\x0e\xa7I!vb\xe4\x87X6\x14\xb0\x87D\xdc\x10\x7f\x98'

How do I get this code to output something human-readable? Any advice would be helpful! Thank you!

-B

1 Answers1

2

CFB is a stream cipher mode and does not require padding. There are different CFB variants, e.g. CFB1, CFB8, CFB128. CFB128 is also often referred to as CFB.

The numerical value describes the number of plaintext bits encrypted per encryption step.

The posted ciphertext can be successfully decrypted with CFB128.

In PyCryptodome the numerical value is specified with the parameter segment_size, here

In addition, the encrypted data contains the 16 bytes IV placed in front (as you already assumed), so that the IV and the actual ciphertext must be separated first.

The following code decrypts the ciphertext:

from Crypto.Cipher import AES

encrypted_data = b"$+\xf5Sq\x1aBC\xbe\t\x8f2\x0b\xf9\xdc!\x80By2\xbb\x10k\x03G\xbb\x85\xd5u\x1dM\xeb\xfd\xa8\xf4\xa13GX|\x06\x0e\xa7K\x0f\xbc\xca\x82js)Q\xff\xbc\xbd\xe2\x05mfJ\xe7g\xdc\xd3b\xff_O\xaeNDH\xb4\x8e\xb7\xbf$2\xba\xe6\xd1\x1bu\n\xe2\x05\xae\x1a\xfc\xd7v\x06\xe6/^&v\xd4\x1a-\x0f\x16o\xc7\xeb\xc4\x90h\xe9"

key = bytes.fromhex("566B59703373367638792F423F4528482B4D6251655468576D5A713474377721")

def decrypt(data, key):

    #print("Encrypted data: ", data)

    iv = data[:16]                                             # Separate IV
    ciphertext = data[16:]                                     # and actual ciphertext

    #trying CFB mode
    cipher = AES.new(key, AES.MODE_CFB,iv=iv,segment_size=128) # Specify CFB128
    pt = cipher.decrypt(ciphertext)
    print("CFB mode outputs: ", pt) 

decrypt(encrypted_data, key)

with the output:

CFB mode outputs:  b'\r\nLocal: \r\nACCESS            by user 5                                    22:49:32 03/07/11\r\n'
Topaco
  • 40,594
  • 4
  • 35
  • 62