Внедрить шифрование OpenSSL AES в Python

Я пытаюсь реализовать в Python следующее: openssl enc -e -aes-256-cbc -base64 -k «Секретная кодовая фраза» -in plaintext.txt -out ciphertext.txt

openssl enc -d -aes-256-cbc -base64 -k "Секретная кодовая фраза" -in ciphertext.txt -out verify.txt

Я пробовал несколько разных модулей, PyCrypto, M2Crypto и т. Д., Но, похоже, не могу получить правильную комбинацию изменения пароля на ключ правильного размера и правильного кодирования всего. Я нашел https://github.com/nvie/SimpleAES, но это в основном запускает OpenSSL по команде линия, которой я бы предпочел избежать.


person PizzaPanther    schedule 17.12.2012    source источник
comment
У меня тот же вопрос, вы в конечном итоге использовали ответ ниже в качестве своего решения? (Это не было принято в качестве ответа, поэтому мне было интересно, решили ли вы это по-другому)   -  person fuzzi    schedule 02.03.2019
comment
Если я правильно помню, я тоже не думаю, что это сработало. Я думаю, что проблема, которую я пытался решить, заключалась в использовании одного и того же алгоритма шифрования в Python и JS, поэтому я немного повернулся. Вместо этого я использовал криптографию и реализацию Fernet. cryptography.io/en/latest/fernet, а затем что-то вроде этого в JS: github.com/csquared/fernet.js   -  person PizzaPanther    schedule 03.03.2019


Ответы (1)


Кодирование и декодирование Base 64 можно легко выполнить с помощью стандартного модуля base64.

Расшифровка и шифрование AES-256 в режиме CBC поддерживаются как PyCrypto, так и M2Crypto.

Единственная нестандартная (и самая сложная) часть - это вывод IV и ключа из пароля. OpenSSL делает это с помощью своей собственной EVP_BytesToKey функции, которая описана на этой странице руководства. .

Эквивалент Python:

def EVP_BytesToKey(password, salt, key_len, iv_len):
    """
    Derive the key and the IV from the given password and salt.
    """
    from hashlib import md5
    dtot =  md5(password + salt).digest()
    d = [ dtot ]
    while len(dtot)<(iv_len+key_len):
        d.append( md5(d[-1] + password + salt).digest() )
        dtot += d[-1]
    return dtot[:key_len], dtot[key_len:key_len+iv_len]

где key_len - 32, а iv_len - 16 для AES-256. Функция возвращает ключ и IV, которые вы можете использовать для расшифровки полезной нагрузки.

OpenSSL помещает и ожидает "соль" в первых 8 байтах зашифрованной полезной нагрузки.

Наконец, AES в режиме CBC может работать только с данными, выровненными по 16-байтовой границе. Используемое заполнение по умолчанию - PKCS # 7.

Таким образом, шаги для шифрования следующие:

  1. Сгенерируйте 8 байтов случайных данных в виде соли.
  2. Получите ключ AES и IV из пароля, используя соль из шага 1.
  3. Дополните входные данные PKCS # 7.
  4. Зашифруйте дополнение с помощью AES-256 в режиме CBC с ключом и IV из шага 2.
  5. Закодируйте в Base64 и выведите соль с шага 1.
  6. Закодируйте в Base64 и выведите зашифрованные данные с шага 4.

Шаги от расшифровки обратные:

  1. Декодируйте входные данные из Base64 в двоичную строку.
  2. Считайте первые 8 байтов декодированных данных солью.
  3. Получите ключ AES и IV из пароля, используя соль из шага 1.
  4. Расшифруйте оставшиеся декодированные данные с помощью ключа AES и IV из шага 3.
  5. Проверьте и удалите отступ PKCS # 7 из результата.
person SquareRootOfTwentyThree    schedule 17.12.2012
comment
Почти согласен. Формат openssl enc - это 8-байтовый литерал Salted__, 8-байтовое значение соли, затем зашифрованный текст, все в формате base64 как единое целое. Объедините шифрование №5 и №6 плюс эту константу и измените дешифрование №2 на [8:16] и №4 на [16:]. - person dave_thompson_085; 12.08.2019