Python 中的 PHP openssl AES

问题描述 投票:0回答:2

我正在开发一个使用 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代码以获得预期的输出?

php python encryption aes pycrypto
2个回答
3
投票

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)的思想是为使用相同密钥的加密提供随机化。如果您使用相同的 IV,攻击者可能能够推断出您发送了相同的消息两次。这可以被认为是一个损坏的协议。

IV 不应该是秘密的,因此您只需将其与密文一起发送即可。通常在加密期间将其添加到密文中并在解密之前将其切掉。


0
投票

加密.php

function encrypt($data, $passphrase)
{
    if(is_array($data)) $data = json_encode($data);
    $secret_key = hash('sha256', $passphrase, true);
    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
    $encrypted_64 = openssl_encrypt($data, 'aes-256-cbc', $secret_key, 0, $iv);
    $iv_64 = base64_encode($iv);
    $json = new stdClass();
    $json->iv = $iv_64;
    $json->data = $encrypted_64;
    return base64_encode(json_encode($json));
}

function decrypt($data, $passphrase)
{
    $secret_key = hash('sha256', $passphrase, true);
    $json = json_decode(base64_decode($data));
    $iv = base64_decode($json->{'iv'});
    $encrypted_64 = $json->{'data'};
    $data_encrypted = base64_decode($encrypted_64);
    $decrypted = openssl_decrypt($data_encrypted, 'aes-256-cbc', $secret_key, OPENSSL_RAW_DATA, $iv);
    $decoded = json_decode($decrypted,true) ;
    return is_array($decoded) ? $decoded : $decrypted;
}

python 加密.py

import base64
import hashlib
from Crypto.Cipher import AES
import json


def pad(data):
   block_size = AES.block_size
   padding = block_size - len(data) % block_size
   return data + bytes([padding] * padding)

def encrypt(data, passphrase):
   if isinstance(data, dict):
      data = json.dumps(data)
   secret_key = hashlib.sha256(passphrase.encode()).digest()
   iv = AES.new(secret_key, AES.MODE_CBC).iv
   cipher = AES.new(secret_key, AES.MODE_CBC, iv)
   data = data.encode('utf-8')
   padded_data = pad(data)   
   encrypted_data = cipher.encrypt(padded_data)
   iv_64 = base64.b64encode(iv).decode()
   encrypted_64 = base64.b64encode(encrypted_data).decode()
   son_data = {"iv": iv_64, "data": encrypted_64}
   return base64.b64encode(json.dumps(json_data).encode()).decode()


def decrypt(encrypted_data, passphrase):
   secret_key = hashlib.sha256(passphrase.encode()).digest()
   json_data = json.loads(base64.b64decode(encrypted_data))
   iv = base64.b64decode(json_data['iv'])
   encrypted_data = base64.b64decode(json_data['data'])
   cipher = AES.new(secret_key, AES.MODE_CBC, iv)
   decrypted_data = cipher.decrypt(encrypted_data) 
   decrypted_data = decrypted_data[:-decrypted_data[-1]]
   decrypted_data = decrypted_data.decode('utf-8')
   loaded_data = json.loads(decrypted_data)
   if isinstance(loaded_data, dict):
      return loaded_data
return decrypted_data
© www.soinside.com 2019 - 2024. All rights reserved.