Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python与PHP上解密AES256_Php_Python_Cryptography_Aes - Fatal编程技术网

在Python与PHP上解密AES256

在Python与PHP上解密AES256,php,python,cryptography,aes,Php,Python,Cryptography,Aes,我发现AES加密有问题,用PHP加密,用Python解密 对于加密,我使用以下PHP函数: function cryptpass($arg1) { $k = '61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6'; $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc')); $cipher = base

我发现AES加密有问题,用PHP加密,用Python解密

对于加密,我使用以下PHP函数:

function cryptpass($arg1) {

    $k = '61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6';
    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
    $cipher = base64_encode(openssl_encrypt($arg1,'aes-256-cbc',$k,OPENSSL_RAW_DATA,$iv));
    return urlencode(base64_encode('{"cipher":"'.$cipher.'","i":"'.base64_encode($iv).'"}'));
}
我用这个Python代码来解密:

def decryptpass(info):
   key = '61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6'
   data = json.loads(base64.b64decode(info))
   iv = base64.b64decode(data.get('i'))
   cipher = AES.new(key,AES.MODE_CBC,iv)
   return cipher.decrypt(data.get('cipher'))
但在运行此代码时,会发生以下错误:

ValueError:AES密钥的长度必须为16、24或32字节


我知道我的密钥有64个字节,但PHP加密是如何使用它的?我尝试从密钥中删除最后32个字符,但这不起作用。

您正在定义一个64个字符的密钥;如果这64个字符是十六进制数字,则
openssl\u encrypt()
不会以任何方式解码十六进制字符,它会逐字使用这些字符

但是,AES-256只接受具有32字节(=256位)的密钥,而不是64位,并且
openssl\u encrypt()
会自动截断密钥。另一方面,PyCrypto
AES.new()
方法显式地告诉您密钥太长,从而提醒您此处的错误,即您可能应该首先将十六进制密钥解码为字节

如果在Python中将密钥减少到32个字符,或者在这两种情况下都将密钥从十六进制转换为字节,则可以成功解密消息:

$k=hex2bin('61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6');
key=bytes.fromhex('61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6')
我强烈建议解码而不是截断;32个十六进制字符的熵要小得多(字节包含的值与32个十六进制字符平方可编码的值的数量一样多,2为256次方,2为128次方)

因为
openssl\u encrypt()
也会对返回值进行base64编码,因此需要在Python端对
cipher
值进行base64解码:

>>> data = json.loads(base64.b64decode(info))
>>> data
{'cipher': 'Iu9VgH8DdxHdQgnq8o23ew==', 'i': 'Vz+wy5VS6toNHx7MEYl+/A=='}
# base64:   ^^^^^^^^^^^^^^^^^^^^^^^^         ^^^^^^^^^^^^^^^^^^^^^^^^
最后,
openssl\u encrypt()
添加到加密消息以使其适合AES块大小(16字节),您需要在Python端再次删除该填充,PyCrypto
AES.decrypt()
方法不适合您:

# Decode from hex to create a key 256 bits (32 bytes) long:
key = bytes.fromhex('61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6')
# or, if you don't use hex2bin in PHP, truncate to 32 characters
# key = b'61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6'[:32]


def decryptpass(info):
    data = json.loads(base64.b64decode(info))
    iv = base64.b64decode(data['i'])
    cipher = AES.new(key, AES.MODE_CBC, iv)
    padded = cipher.decrypt(base64.b64decode(data['cipher']))
    # manual PKCS#7 unpadding
    return padded[:-padded[-1:]].decode()
但是,请注意,PyCrypto项目已经6年没有出现在新版本中了,不应该再相信它是安全的。您确实希望使用此处:

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend

key = bytes.fromhex('61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6')

def decrypt_aes_256(key, iv, encrypted):
    decryptor = Cipher(
        algorithms.AES(key), modes.CBC(iv), default_backend()
    ).decryptor()
    unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
    decrypted = decryptor.update(encrypted) + decryptor.finalize()
    return unpadder.update(decrypted) + unpadder.finalize()

def decryptpass(info):
    data = json.loads(base64.b64decode(info))
    iv = base64.b64decode(data['i'])
    encrypted = base64.b64decode(data['cipher'])
    return decrypt_aes_256(key, iv, encrypted).decode()
演示,首先是PHP:

$ php -a
Interactive shell

php > function cryptpass($arg1) {
php {     $k = hex2bin('61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6');
php {     $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
php {     $cipher = base64_encode(openssl_encrypt($arg1,'aes-256-cbc',$k,OPENSSL_RAW_DATA,$iv));
php {     return urlencode(base64_encode('{"cipher":"'.$cipher.'","i":"'.base64_encode($iv).'"}'));
php { }
php > echo cryptpass("Hello, world!");
eyJjaXBoZXIiOiJJdTlWZ0g4RGR4SGRRZ25xOG8yM2V3PT0iLCJpIjoiVnord3k1VlM2dG9OSHg3TUVZbCsvQT09In0%3D
然后是Python;使用上文定义的
加密
功能:

>>> from urllib.parse import unquote
>>> info = unquote("eyJjaXBoZXIiOiJJdTlWZ0g4RGR4SGRRZ25xOG8yM2V3PT0iLCJpIjoiVnord3k1VlM2dG9OSHg3TUVZbCsvQT09In0%3D")
>>> decryptpass(info)
'Hello, world!'

b64deode
检查此代码的拼写。我们可以获得一个重现此问题的JSON字符串示例吗?我们并非都安装了两种语言。:-)在PHP shell中创建的示例,加密文本
“Hello world!”
,输出
Eyjjaxbozxiioijcsznhb2dpus80sxpouvqrdllwk5npt0ilcjpijoinovfsmuhjterbznvbtxfnlr4beezdz09in0=
(我删除了URL编码,因为您显然正在使用有效的base64数据)。您是否使用?请把你的进口商品包括在内好吗?