PHP openssl AES in Python
Question: I am working on a project where PHP is used for decrypt AES-256-CBC messages

    
    
    <?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";
    

ouutput

    
    
    >>> S1NaeUFaUHdqc20rQWM1L2ZVMDJudz09
    >>> secret
    

Now I have to write Python 3 code for encrypting data. I've tried use PyCrypto
but without success. My code:

    
    
    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)
    

output

    
    
    >>> b'tnF87LsVAkzkvs+gwpCRMg=='
    

But I need output `S1NaeUFaUHdqc20rQWM1L2ZVMDJudz09` which will PHP decrypt to
`secret`. How to modify Python code to get expected output?


Answer: [PHP's `hash`](http://php.net/manual/en/function.hash.php) outputs a Hex-
encoded string by default, but Python's `.digest()` returns `bytes`. You
probably wanted to use `.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")
    

The idea of the initialization vector (IV) is to provide randomization for the
encryption with the same key. If you use the same IV, an attacker may be able
to deduce that you send the same message twice. This can be considered as a
broken protocol.

The IV is not supposed to be secret, so you can simply send it along with the
ciphertext. It is common to prepend it to the ciphertext during encryption and
slice it off before decryption.

