Кодировать в Laravel, декодировать в Python

Кодировать в Laravel, декодировать в Python

04.10.2018 08:38:52 Просмотров 51 Источник

Я использую метод encryptString Laravel для шифрования некоторых данных на моем веб-сайте. Это использует 256-битное шифрование OpenSSL AES-CBC без какой-либо сериализации. Теперь я пытаюсь расшифровать эти данные в Python, но я продолжаю получать ошибки о длине ключа и не могу понять, почему.

Example data to decrypt: eyJpdiI6ImdxY0VcLzFodmpISFV4allSWmJDdEpRPT0iLCJ2YWx1ZSI6IkxXd0ZJaUd2bTUweW5pNm0wUjQwOFM2N1wvWEs5SlYrNB4xNlR7Qkh1U3FvPSIsIm1hYyI6Ijc5ZWM0YTYxYjljZGFiNzgwNjY2NDU1ZmQ5Yjc1ZmJlOGU4NzBkMjQzMzA3MmVhYzE3NzY4ZmU1MWIyMjZlOTQifQ==

Example Key to use for decryption (from laravel .env):
base64:/AZejP0lh3McL/+Vy5yZcADdTcR65qnx5Jqinuw7raK=

Я изменил эти значения, поэтому на самом деле расшифровка с этими значениями не даст никаких реальных данных, просто подумал, что это было бы хорошо, например. Затем я пытаюсь расшифровать эти данные в Python 3.7 с помощью:

import base64
from Crypto.Cipher import AES

def decrypt(enc, key):
    IV = 16 * '\x00'
    decobj = AES.new(key, AES.MODE_CBC, IV)
    data = decobj.decrypt(base64.b64decode(enc))
    print(str(data.decode()))

if __name__ == "__main__":
    key = b"/AZejP0lh3McL/+Vy5yZcADdTcR65qnx5Jqinuw7raK="
    decrypt("eyJpdiI6ImdxY0VcLzFodmpISFV4allSWmJDdEpRPT0iLCJ2YWx1ZSI6IkxXd0ZJaUd2bTUweW5pNm0wUjQwOFM2N1wvWEs5SlYrNB4xNlR7Qkh1U3FvPSIsIm1hYyI6Ijc5ZWM0YTYxYjljZGFiNzgwNjY2NDU1ZmQ5Yjc1ZmJlOGU4NzBkMjQzMzA3MmVhYzE3NzY4ZmU1MWIyMjZlOTQifQ==", key)

И кажется, что это должно работать, но когда я запускаю его, я получаю ошибку: ValueError: Incorrect AES key length (60 bytes), поэтому я не уверен, что я делаю неправильно. Я пробовал заполнять / распаковывать данные / ключ, но это, похоже, ничего не меняет. Мне интересно, получаю ли я неправильный ключ для расшифровки от Laravel, но из того, что я мог бы сказать в связанной документации, это должен быть просто APP_KEY в моем .env файл.

Если бы кто-нибудь мог помочь мне или указать мне в правильном направлении, это было бы удивительно!

Этот вопрос является уникальным на другие подобные вопросы, потому что я пытаюсь выяснить, в первую очередь, если я получаю правильный ключ AES. с что Laravel, я на самом деле не слишком нужна помощь в расшифровке, я просто думаю, что я взял не тот ключ с фреймворк Laravel.

Изменить: новый код, который кажется, что он работает:

import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

def decrypt(enc, key):
    IV = 16 * '\x00'.encode()
    decobj = AES.new(key, AES.MODE_CBC, IV)
    data = decobj.decrypt(pad(base64.b64decode(enc), 16))
    print(base64.b64decode(data))

if __name__ == "__main__":
    key = base64.b64decode(b"/AZejP0lh3McL/+Vy5yZcADdTcR65qnx5Jqinuw7raK=")
    decrypt("eyJpdiI6ImdxY0VcLzFodmpISFV4allSWmJDdEpRPT0iLCJ2YWx1ZSI6IkxXd0ZJaUd2bTUweW5pNm0wUjQwOFM2N1wvWEs5SlYrNB4xNlR7Qkh1U3FvPSIsIm1hYyI6Ijc5ZWM0YTYxYjljZGFiNzgwNjY2NDU1ZmQ5Yjc1ZmJlOGU4NzBkMjQzMzA3MmVhYzE3NzY4ZmU1MWIyMjZlOTQifQ==", key)

Оператор печати теперь печатает несколько байтов, но когда я запускаю .decode() на нем я получаю ошибку: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfa in position 0: invalid start byteи не может понять, что мне нужно сделать, чтобы он мог быть напечатан в виде строки.

У вопроса есть решение - Посмотреть?

https://stackoverflow.com/questions/52639703/encode-in-laravel-decode-in-python#comment92213477_52639703
@stovfl, что вопрос выглядит, как это может помочь ответить на мою проблему, но я чувствую, что мой вопрос относится в основном к что Laravel/среды файлов, а не просто пытается исправить ошибку, на мой вопрос, что я прошу, если кто знает, если я на самом деле захват правильный ключ AES. с фреймворк Laravel, а не просто как исправить ошибки в Python.
https://stackoverflow.com/questions/52639703/encode-in-laravel-decode-in-python#comment92214237_52639703
Я понял твою точку зрения. Почему ты думаешь, что взял не тот ключ? Что делает ' php artisan key: generate* команда generate.
https://stackoverflow.com/questions/52639703/encode-in-laravel-decode-in-python#comment92216099_52639703
@stovfl он генерирует ключ, используемый для шифрования в соответствии с stackoverflow.com/a/44839772/8093698 , я также просто попытался перезапустить его, чтобы увидеть, что происходит, но когда я ввожу его в свой код Python, он все еще остается тем же неправильным количеством бит.
https://stackoverflow.com/questions/52639703/encode-in-laravel-decode-in-python#comment92223299_52639703
Вы не смогли base64-декодировать ключ.

Ответы - Кодировать в Laravel, декодировать в Python / Encode in Laravel, decode in Python

Является ответом!
stovfl

04.10.2018 03:41:02

Вопрос:...пытаясь расшифровать эти данные в Python, но я продолжаю получать ошибки о длине ключа

Я могу использовать ваш key, в коде связанного ответа, после выполнения .b64decode(....
Пример кода .encode(...и decode(... работает как Терп.
Вывод: с вашим ключом все в порядке!

key = b"/AZejP0lh3McL/+Vy5yZcADdTcR65qnx5Jqinuw7raK="
key = base64.b64decode(key)

Но с вашим кодом я получил TypeError, связанный с параметром IV:

  expect_byte_string(iv)
File "/usr/local/lib/python3.4/dist-packages/Crypto/Util/_raw_api.py", line 172, in expect_byte_string
  TypeError: Only byte strings can be passed to C code

Исправлено с IV = 16 * '\x00'.encode(), приводит к ValueError, связанному с enc:

  data = decobj.decrypt(base64.b64decode(enc))
File "/usr/local/lib/python3.4/dist-packages/Crypto/Cipher/_mode_cbc.py", line 209, in decrypt
  ValueError: Error 3 while decrypting in CBC mode

Это приводит к проблемам github: 10

Ошибка 3 означает " ERR_NOT_ENOUGH_DATA"

Согласно связанной странице GitHub, вы должны перечитывать документацию о заполнении данных во время кодирования .


Рабочий пример на GitHub:

import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

key = b"/AZejP0lh3McL/+Vy5yZcADdTcR65qnx5Jqinuw7raK="
key = base64.b64decode(key)

BLOCK_SIZE = 32
encryption_suite = AES.new(key, AES.MODE_CBC, b'This is an IV...')
cipher_text = encryption_suite.encrypt(pad(b'A really secret message...', BLOCK_SIZE))

decryption_suite = AES.new(key, AES.MODE_CBC, b'This is an IV...')
print(unpad(decryption_suite.decrypt(cipher_text), BLOCK_SIZE).decode())
>>> A really secret message...

Протестировано с Python: 3.4.2

https://stackoverflow.com/questions/52639703/encode-in-laravel-decode-in-python/52646988#comment92238383_52646988
Хммм, я добавил ваш код к моему и сумел добраться до точки, где он печатает байты, но когда я иду, чтобы декодировать его, я получаю ошибку. Я обновлю свой первоначальный вопрос с новым кодом. Спасибо за помощь до сих пор!
https://stackoverflow.com/questions/52639703/encode-in-laravel-decode-in-python/52646988#comment92241096_52646988
@Pecans: обновил мой ответ с рабочим примером. Примечание: Вы должны pad(...перед шифрованием и unpad(... после расшифровки. Ошибка utf-8-это результат, который вы pad(...после кодирования.
Gonzalo Villafañe Tapia

29.10.2019 04:31:47

Я замечаю, что это не было активным в течение некоторого времени, но я пытаюсь сделать то же самое и не могу заставить его работать.

Я заметил, что кодированная строка пароля, сохраненная Laravel, является базовым 64-кодированным объектом json, который не был принят во внимание в исходном вопросе:

pass_obj = base64.b64decode('eyJpdiI6ImdxY0VcLzFodmpISFV4allSWmJDdEpRPT0iLCJ2YWx1ZSI6IkxXd0ZJaUd2bTUweW5pNm0wUjQwOFM2N1wvWEs5SlYrNB4xNlR7Qkh1U3FvPSIsIm1hYyI6Ijc5ZWM0YTYxYjljZGFiNzgwNjY2NDU1ZmQ5Yjc1ZmJlOGU4NzBkMjQzMzA3MmVhYzE3NzY4ZmU1MWIyMjZlOTQifQ==')
print(pass_obj)
>>> b'{"iv":"gqcE\\/1hvjHHUxjYRZbCtJQ==","value":"LWwFIiGvm50yni6m0R408S67\\/XK9JV+4\x1e16T{BHuSqo=","mac":"79ec4a61b9cdab780666455fd9b75fbe8e870d2433072eac17768fe51b226e94"}'

Из этого вы можете получить IV и зашифрованное значение, оба, похоже, закодированы в base64. Но я все еще получаю ошибку декодирования в конце, как;

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

Вот мой полный код;

password = 'eyJpdiI6ImJGNDNNZjN3YWtpcDQ5VEJVXC9IazF3PT0iLCJ2YWx1ZSI6IkNVRW1VQUY1dXArYlFkU3NlY1pnZUE9PSIsIm1hYyI6ImM3ODk0NWQ0NjgxMzM4YjE0M2JhN2MzZWRmOWEwMWJiMjI2Y2FhYmUxYjFhYzAyYjY4YWZkZGE3N2EyMDYwNWYifQ=='
key = 'some secret key that i can't share'.encode()
p_obj = json.loads(base64.b64decode(password).decode())
decobj = AES.new(key, AES.MODE_CBC, base64.b64decode(p_obj['iv']))
data = decobj.decrypt(base64.b64decode(p_obj['value']))
print(data)
>>> b'l\xee:f\x9eZ\x90rP\x99\xca&@\x1d1\x9f'
data.decode()
>>> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xee in position 1: invalid continuation byte

@Pecans ты когда-нибудь это понимал?

Спасибо.


Полный рабочий код править

Я вытерпел это, у меня была проблема с моим ключом изначально. Итак, вот полный фрагмент для дальнейшего использования;

import base64
import json
from phpserialize import unserialize
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

key = b'my secret key'
enc_pass = 'eyJpdiI6ImJGNDNNZjN3YWtpcDQ5VEJVXC9IazF3PT0iLCJ2YWx1ZSI6IkNVRW1VQUY1dXArYlFkU3NlY1pnZUE9PSIsIm1hYyI6ImM3ODk0NWQ0NjgxMzM4YjE0M2JhN2MzZWRmOWEwMWJiMjI2Y2FhYmUxYjFhYzAyYjY4YWZkZGE3N2EyMDYwNWYifQ=='

p_obj = json.loads(base64.b64decode(password).decode())
decobj = AES.new(key, AES.MODE_CBC, base64.b64decode(p_obj['iv']))
data = decobj.decrypt(base64.b64decode(p_obj['value']))
dec_pass = unserialize(unpad(data, 16)).decode()

Вы будете иметь расшифрованный пароль в dec_pass.

Обратите внимание, что иногда Laravel генерирует ключ в base64. В этом случае строка будет чем-то вроде base64:sdfsdjfhjsdf32, тогда вам нужно сначала декодировать.

Ваше здоровье!

Pilatus

10.11.2019 06:23:46

Полный рабочий код с проверкой MAC

Добавляя к представлению Гонсало, зашифрованное сообщение Laravel представляет собой массив с кодировкой base64 json, состоящий из следующих пар ключей:

[
      'iv' => 'generated initialization vector (iv)',
      'value' => 'encrypted, base64ed, signed value',
      'mac'  => 'message authentication code (mac)'
]

"Значение" подписывается с помощью кода проверки подлинности сообщения (MAC), чтобы убедиться, что значение не изменилось во время передачи.

MAC, извлеченный из полезной нагрузки (зашифрованное сообщение) , должен быть проверен на соответствие mac извлекается из "значения" (это можно сделать с помощью ключа, iv и значения). Схему шифрования Laravel можно найти на GitHub: src / Illuminate / Encryption/Encrypter.РНР

Ссылаясь на дискуссионную тему на Laravel, я проследил частичное решение на Github: orian/crypt.py (который является вилкой fideloper/crypt.py ).

Я разветвил код Ориана и исправил проблему с входным параметром. Код работает так, как ожидалось, пока ключ шифрования (переданный в качестве входных данных для decrypt ()) декодируется base64 и не включает ' base64:', который обычно добавляется к назначению строки переменной среды APP_KEY, найденному в .env файл.

Решение : pilatuspc12ng/crypt.py

Фрагмент кода программы crypt.py показано ниже:

import base64
import json
from Crypto.Cipher import AES
from phpserialize import loads
import hashlib
import hmac


def decrypt(payload, key):
    """
    Decrypt strings that have been encrypted using Laravel's encrypter (AES-256 encryption).
    Plain text is encrypted in Laravel using the following code:
    >>> ciphertext = Crypt::encrypt('hello world');
    The ciphertext is a base64's json-encoded array consisting of the following keys:
       [
          'iv' => 'generated initialization vector (iv)',
          'value' => 'encrypted, base64ed, signed value',
          'mac'  => 'message authentication code (mac)'
       ]
    The 'value' is signed using a message authentication code (MAC) so verify that the value has not changed during
    transit.
    Parameters:
    payload (str): Laravel encrypted text.
    key (str): Encryption key (base64 decoded). Make sure 'base64:' has been removed from string.
    Returns:
    str: plaintext
    """

    data = json.loads(base64.b64decode(payload))
    if not valid_mac(key, data):
        return None

    value = base64.b64decode(data['value'])
    iv = base64.b64decode(data['iv'])

    return unserialize(mcrypt_decrypt(value, iv, key)).decode("utf-8")

def mcrypt_decrypt(value, iv, key):
    AES.key_size=128
    crypt_object=AES.new(key=key,mode=AES.MODE_CBC,IV=iv)
    return crypt_object.decrypt(value)

def unserialize(serialized):
    return loads(serialized)

def valid_mac(key, data):
    dig = hmac.new(key, digestmod=hashlib.sha256)
    dig.update(data['iv'].encode('utf8'))
    dig.update(data['value'].encode('utf8'))
    dig = dig.hexdigest()
    return dig==data['mac']
Закрыть X