PHP openssl AES на Python


Я работаю над проектом, в котором PHP используется для расшифровки сообщений AES-256-CBC

<?php

class CryptService{
    private static $encryptMethod = 'AES-256-CBC';
    private $key;
    private $iv;

    public function __construct(){
        $this->key = hash('sha256', 'c7b35827805788e77e41c50df44441491098be42');
        $this->iv = substr(hash('sha256', 'c09f6a9e157d253d0b2f0bcd81d338298950f246'), 0, 16);
    }

    public function decrypt($string){
        $string = base64_decode($string);
        return openssl_decrypt($string, self::$encryptMethod, $this->key, 0, $this->iv);
    }

    public function encrypt($string){
        $output = openssl_encrypt($string, self::$encryptMethod, $this->key, 0, $this->iv);
        $output = base64_encode($output);
        return $output;
    }
}

$a = new CryptService;
echo $a->encrypt('secret');
echo "\n";
echo $a->decrypt('S1NaeUFaUHdqc20rQWM1L2ZVMDJudz09');
echo "\n";

Вывод

>>> S1NaeUFaUHdqc20rQWM1L2ZVMDJudz09
>>> secret

Теперь мне нужно написать код Python 3 для шифрования данных. Я пытался использовать PyCrypto, но безуспешно. Мой код:

import base64
import hashlib
from Crypto.Cipher import AES

class AESCipher:
    def __init__(self, key, iv):
        self.key = hashlib.sha256(key.encode('utf-8')).digest()
        self.iv = hashlib.sha256(iv.encode('utf-8')).digest()[:16]

    __pad = lambda self,s: s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size)
    __unpad = lambda self,s: s[0:-ord(s[-1])]

    def encrypt( self, raw ):
        raw = self.__pad(raw)
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        return base64.b64encode(cipher.encrypt(raw))

    def decrypt( self, enc ):
        enc = base64.b64decode(enc)
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv )
        return self.__unpad(cipher.decrypt(enc).decode("utf-8"))

cipher = AESCipher('c7b35827805788e77e41c50df44441491098be42', 'c09f6a9e157d253d0b2f0bcd81d338298950f246')

enc_str = cipher.encrypt("secret")
print(enc_str)

Вывод

>>> b'tnF87LsVAkzkvs+gwpCRMg=='

Но мне нужен вывод S1NaeUFaUHdqc20rQWM1L2ZVMDJudz09, который PHP расшифрует в secret. Как изменить код Python, чтобы получить ожидаемый результат?

Author: Horned Owl, 2016-09-25

1 answers

PHP - это hash по умолчанию выводит строку в шестнадцатеричном формате, но Python .digest() возвращает bytes. Вы, вероятно, хотели использовать .hexdigest():

def __init__(self, key, iv):
    self.key = hashlib.sha256(key.encode('utf-8')).hexdigest()[:32].encode("utf-8")
    self.iv = hashlib.sha256(iv.encode('utf-8')).hexdigest()[:16].encode("utf-8")

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

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

 3
Author: Artjom B., 2016-09-25 19:20:49