Основная проблема заключается в том, что вы используете другой размер ключа. PHP openssl_encrypt
определяет размер ключа из строки алгоритма шифрования ("aes-256-cbc"
в данном случае), поэтому он ожидает 256-битный ключ. Если ключ короче, он дополняется нулевыми байтами, поэтому фактический ключ, используемый openssl_encrypt
, равен:
"akshayakshayaksh\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
Pycryptodome определяет размер ключа по фактическому размеру ключа, поэтому ваш код Python использует AES-128-CBC. Кроме того, как упомянуто в комментариях от kelalaka, зашифрованный текст кодируется как base64 (openssl_encrypt
base64 кодирует зашифрованный текст по умолчанию - мы можем получить необработанные байты, если мы используем OPENSSL_RAW_DATA
в $options
). Pycryptodome не декодирует зашифрованный текст, поэтому мы должны использовать b64decode()
.
key = b'akshayakshayaksh\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
obj2 = AES.new(key, AES.MODE_CBC, b'0123456789012345')
ciphertext = b"cUXDhOEGz19QEo9XDvMzXkGFmg/YQUnXEqKVpfYtUGo="
print(obj2.decrypt(b64decode(ciphertext)))
#b'message to be encrypted\t\t\t\t\t\t\t\t\t'
Дополнительные \t
символы в конце - это заполнение - CBC требует заполнения. Pycryptodome не удаляет заполнение автоматически, но предоставляет функции заполнения в Crypto.Util.Padding
.
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from base64 import b64decode
key = b'akshayakshayaksh\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
obj2 = AES.new(key, AES.MODE_CBC, b'0123456789012345')
ciphertext = b"cUXDhOEGz19QEo9XDvMzXkGFmg/YQUnXEqKVpfYtUGo="
plaintext = obj2.decrypt(b64decode(ciphertext))
plaintext = unpad(plaintext, AES.block_size)
Хотя PHP openssl принимает ключи произвольного размера, лучше всего использовать размер ключа, указанный в строке алгоритма, чтобы, по крайней мере, избежать путаницы. Также ключевые байты должны быть как можно более случайными.
Как отметил Мартен Бодевес в комментариях , этот ключ использует ограниченный диапазон байтов и поэтому он очень слабый. Кроме того, он создается повторением слова, что делает его уязвимым для атак по словарю (которые намного быстрее, чем атаки методом перебора).
В PHP мы можем получить криптографически безопасные случайные байты с random_bytes()
,
$key = random_bytes(32);
и в Python с os.urandom()
key = os.urandom(32)
(Вы можете использовать те же функции для создания IV; вы не должны использовать статический IV, IV должен быть непредсказуемым)
Вы также можете получить ключ из вашего пароля с помощью KDF. В этом случае важно использовать случайную соль и достаточно большое количество итераций. PHP предоставляет алгоритм PBKDF2 с функцией hash_pbkdf2
, а Python с hashlib.pbkdf2_hmac
.