【问题标题】:PHP openssl AES in PythonPHP openssl AES 在 Python 中
【发布时间】:2017-02-03 01:30:48
【问题描述】:

我正在开发一个使用 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


    【解决方案1】:

    PHP's 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 不应该是秘密的,因此您可以简单地将其与密文一起发送。通常在加密期间将其添加到密文中,并在解密之前将其切掉。

    【讨论】:

    • 谢谢Artjom。我必须改变的另一件事是在encrypt 方法中双重调用base64.b64encode。之后,我从 Python 获得与 PHP 相同的输出。我不知道为什么在 PHP 中调用 base64_encode 虽然 openssl_encrypt 返回 base64 编码结果。
    • 可能是这样做的,因为最初的开发者不知道他们在做什么。
    猜你喜欢
    • 2018-03-02
    • 1970-01-01
    • 2015-01-29
    • 2018-11-11
    • 2023-02-23
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    相关资源
    最近更新 更多