1

I've got a encrypt/decrypt class setup based on this SO answer. I've tested it and it works fine. It's not working for a new API I'm pulling information from. The new API is built with PHP and is using the following package to encrypt information: https://laravel.com/docs/8.x/encryption using Laravel Crypt() command. All encrypted values are encrypted using OpenSSL and the AES-256-CBC cipher.

The enc value after the first line of the decrypt method

def decrypt(self, enc):
    enc = base64.b64decode(enc)
    iv = enc[:AES.block_size]
    cipher = AES.new(self.key, AES.MODE_CBC, iv)
    return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')

looks like this (Don't worry, this is just non-sensitive demo data):

b"{'iv': 'Ld2pjRJqoKcWnW1P3tiO9Q==', 'value': 'M9QeHtbybeUxAVuIRcQ3bA==', 'mac': 'xxxxxx......'}"

, which basically looks like a byte-string JSON. The testing encryption key is base64:69GnnXWsW1qnW+soLXOVd8Mi4AdXKBFfkw88/7F2kSg=.

I know I can turn it into a dictionary like this

import json
d = json.loads(enc)

How should I manipulate values from this dictionary to prepare it to be decrypted like other encrypted text this class can successfully decrypt?

Update:

Based on comments I've tried to modify the method to look like this:

def decrypt(self, encrypted):
    enc = base64.b64decode(encrypted)
    if b'{"iv":' == enc[:6]:
        d = json.loads(enc)
        iv = base64.b64decode(d['iv'])
        val = base64.b64decode(d['value'])
    else:
        iv = enc[:AES.block_size]
        val = enc[AES.block_size:]
    cipher = AES.new(self.key, AES.MODE_CBC, iv)
    return self._unpad(cipher.decrypt(val)).decode('utf-8')

This still does not work. It doesn't crash, but I'm getting a blank string back ('') and I know that's not what was encrypted. The answer should be 'Demo'

Jed
  • 1,823
  • 4
  • 20
  • 52
  • Presumably you only have to read IV and ciphertext (`value`) from the dictionary and Base64 decode both. The IV is to be passed as the 3. parameter in `AES.new()`, the ciphertext to `cipher.decrypt()`. The MAC is normally used to authenticate the encrypted data. Since you didn't specify how the MAC was generated, not much more can be said here. Btw, you should not use legacy PyCrypto, but the backwards compatible PyCryptodome, which also supports padding in contrast to PyCrypto. – Topaco Feb 26 '21 at 19:28
  • I am actually using PyCryptodome, sorry for the misinformation. – Jed Feb 26 '21 at 23:04
  • It would be helpful if you post sample data (key, plaintext and ciphertext) and the encryption code as well (possibly the logic is different than you assume; also the authentication logic is currently unclear). – Topaco Feb 27 '21 at 07:20

1 Answers1

0

The code in the "Update" section of the question will work without any changes. You just need to make sure to remove the "base64:" prefix in the encryption key provided. Once that is removed, it will work as expected.

Jed
  • 1,823
  • 4
  • 20
  • 52