Почему результаты AES-256-CBC в PHP и Python различаются при использовании одних и тех же ключей и данных?

Я пытаюсь зашифровать одну и ту же строку в PHP и Python, используя AES-256-CBC, с теми же ключами и IV. Однако результаты обоих языков разные, хотя я использую один и тот же метод шифрования и одни и те же данные.

В PHP я использую openssl_encrypt, а в Python — pycryptodome с дополнением PKCS7. Ниже приведены два фрагмента кода, которые я использую, и результаты, которые я получаю.

Вот мой PHP-код:

<?php
$plaintextstr = 'AAAAAAAAAAAAAAAA';
$encrypt_method = "AES-256-CBC";
$secret_key = "SSSSSSSSSSSS";
$secret_iv = "LLLLLLLLLLLL";
$key = substr(hash('sha256', $secret_key), 0, 32);
$iv = substr(hash('sha256', $secret_iv), 0, 16);
$encrypted_str = openssl_encrypt($plaintextstr, $encrypt_method, $key, 0, $iv);
echo base64_encode($encrypted_str);
?>

Вот мой код Python:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from hashlib import sha256
import base64

plaintextstr = 'AAAAAAAAAAAAAAAA'
secret_key = "SSSSSSSSSSSS"
secret_iv = "LLLLLLLLLLLL"

# Generar key y iv
key = sha256(secret_key.encode('utf-8')).digest()[:32]
iv = sha256(secret_iv.encode('utf-8')).digest()[:16]

# Padding
padded_data = pad(plaintextstr.encode('utf-8'), AES.block_size)

# Crear el cifrador
cipher = AES.new(key, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(padded_data)

# Convertir a base64
encrypted_base64 = base64.b64encode(encrypted).decode('utf-8')
print(encrypted_base64)

Я проверил следующее:

  • Ключи и IV на обоих языках генерируются одинаково с использованием SHA-256.
  • Я использую режим CBC и применяю дополнение PKCS7 на обоих языках.
  • Оба результата закодированы в Base64.

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

🤔 А знаете ли вы, что...
Python популярен в анализе данных и машинном обучении с помощью библиотеки scikit-learn.


2
50
1

Ответ:

Решено

Функция php hash возвращает шестнадцатеричное представление байтов, поэтому сокращение 16 символов с помощью substr приводит к «20139ebeee312271» для вашего IV (аналогичный результат для ключа). Это не настоящие байты, это символы диапазона [0-9a-f]. Это не то, что вы собираетесь делать.

Функция Python sha256.digest() возвращает байтовую строку, а не шестнадцатеричное представление. Вырезание 16 символов приводит к получению 16 истинных байтов хеша. Вероятно, это то, что вы намереваетесь сделать.

Результаты будут разными, поскольку вы шифруете разными ключами и векторами инициализации.

Из документации PHP hash может принимать третий параметр binary, который по умолчанию имеет значение false:

 hash(
    string $algo,
    string $data,
    bool $binary = false,
    array $options = []
): string

binary Если установлено значение true, выводятся необработанные двоичные данные. false выводит шестнадцатеричные строчные буквы.

Изменение PHP-кода на:

<?php

$plaintextstr = 'AAAAAAAAAAAAAAAA';
$encrypt_method = "AES-256-CBC";
$secret_key = "SSSSSSSSSSSS";
$secret_iv = "LLLLLLLLLLLL";
$key = substr(hash('sha256', $secret_key, true), 0, 32);
$iv = substr(hash('sha256', $secret_iv, true), 0, 16);
$encrypted_str = openssl_encrypt($plaintextstr, $encrypt_method, $key, 0, $iv);
echo $encrypted_str;
// Result: V7zSp9KHPke9QuPbWoUNvjCHVJ7giluD9YaOnX9E57k=

дает тот же результат, что и код Python.


Интересные вопросы для изучения