Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/meteor/3.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
用PHP加密文本,用Python解密_Php_Python_Encryption_Pycrypto_Php Openssl - Fatal编程技术网

用PHP加密文本,用Python解密

用PHP加密文本,用Python解密,php,python,encryption,pycrypto,php-openssl,Php,Python,Encryption,Pycrypto,Php Openssl,我正在使用以下代码片段加密PHP7中的文本: $plaintext = "message to be encrypted"; $cipher = "aes-256-cbc"; $ivlen = openssl_cipher_iv_length($cipher); $iv = "0123456789012345"; $key = "akshayakshayaksh"; $ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options

我正在使用以下代码片段加密
PHP7
中的文本:

$plaintext = "message to be encrypted";
$cipher = "aes-256-cbc";
$ivlen = openssl_cipher_iv_length($cipher);
$iv = "0123456789012345";
$key = "akshayakshayaksh";
$ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv);
print $ciphertext;
输出:cUXDhOEGz19QEo9XDvMzXkGFmg/yqunxekvpfytugo=

现在,当我尝试在
Python3
中解密时,它给出了错误:

from Crypto.Cipher import AES
obj2 = AES.new('akshayakshayaksh', AES.MODE_CBC, '0123456789012345')
ciphertext = "cUXDhOEGz19QEo9XDvMzXkGFmg/YQUnXEqKVpfYtUGo="
obj2.decrypt(ciphertext)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件 “/anaconda3/lib/python3.6/site packages/Crypto/Cipher/blockalgo.py”, 第295行,在“解密”中 返回self.\u cipher.decrypt(密文)value错误:输入字符串的长度必须是16的倍数


我知道AES是一种分组密码算法。但是,我应该如何修复我的PHP代码,以便它生成“填充”密码,有什么线索吗?

这里的主要问题是您使用的密钥大小不同。PHP的
openssl\u encrypt
根据加密算法字符串确定密钥大小(本例中为“aes-256-cbc”),因此它需要256位密钥。如果密钥较短,则用零字节填充,因此
openssl\u encrypt
使用的实际密钥为:

"akshayakshayaksh\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
Pycryptodome根据密钥的实际大小确定密钥大小,因此Python代码使用AES-128-CBC。此外,正如kelalaka在文章中提到的,密文是base64编码的(
openssl\u encrypt
base64默认情况下对密文进行编码-如果我们在
$options
中使用
openssl\u原始数据
),我们可以获得原始字节。Pycryptodome不解码密文,因此我们必须使用
b64decode()

key = b'akshayakshayaksh\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
obj2 = AES.new(key, AES.MODE_CBC, b'0123456789012345')
ciphertext = b"cUXDhOEGz19QEo9XDvMzXkGFmg/YQUnXEqKVpfYtUGo="
print(obj2.decrypt(b64decode(ciphertext)))
#b'message to be encrypted\t\t\t\t\t\t\t\t\t'
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from base64 import b64decode

key = b'akshayakshayaksh\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
obj2 = AES.new(key, AES.MODE_CBC, b'0123456789012345')
ciphertext = b"cUXDhOEGz19QEo9XDvMzXkGFmg/YQUnXEqKVpfYtUGo="
plaintext = obj2.decrypt(b64decode(ciphertext))
plaintext = unpad(plaintext, AES.block_size)
结尾额外的
\t
字符是填充-CBC需要填充。Pycryptodome不会自动删除填充,但它在
Crypto.Util.padding
中提供了填充函数

key = b'akshayakshayaksh\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
obj2 = AES.new(key, AES.MODE_CBC, b'0123456789012345')
ciphertext = b"cUXDhOEGz19QEo9XDvMzXkGFmg/YQUnXEqKVpfYtUGo="
print(obj2.decrypt(b64decode(ciphertext)))
#b'message to be encrypted\t\t\t\t\t\t\t\t\t'
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from base64 import b64decode

key = b'akshayakshayaksh\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
obj2 = AES.new(key, AES.MODE_CBC, b'0123456789012345')
ciphertext = b"cUXDhOEGz19QEo9XDvMzXkGFmg/YQUnXEqKVpfYtUGo="
plaintext = obj2.decrypt(b64decode(ciphertext))
plaintext = unpad(plaintext, AES.block_size)

尽管PHP的openssl接受任意大小的密钥,但最好使用算法字符串中指定的密钥大小,以至少防止混淆。此外,密钥字节应尽可能随机

正如Maarten Bodewes在文章中指出的,该键使用有限的字节范围,因此非常弱。此外,它是通过重复一个单词创建的,这使得它容易受到字典攻击(比暴力攻击快得多)

在PHP中,我们可以使用

在Python中使用

(可以使用相同的函数创建IV;不应使用静态IV,IV必须是不可预测的)


您还可以使用KDF从密码中派生密钥。在这种情况下,重要的是使用随机salt和足够高的迭代次数。PHP提供了带函数的PBKDF2算法,Python提供了函数。

今天,当一位朋友向我指出Fernet库时,我正在努力解决这个问题。它有一个python和php版本,这使它非常简单和健壮

PHP版本:


你在传输之前转换了吗?不,目前我没有,我必须转换吗?目前我没有“传输”这个密码文本。我可以复制粘贴解密。所以我认为Base64现在没有必要。如果我错了,请改正!似乎,由于
=
,密文已经以64为基数。然后通过
b64解码
对其进行解码。密码需要字节。现在我明白你的意思了!但当像这样尝试时:obj2.decrypt(b64decode(ciphertext)),得到的输出是:b'\xaa\x7f\xa0\xd5\x07\xf3\xcf1X\x15\xd6\x1e\x16\xdd\x0eC\xebk\xf3\xa3eP]T\xd0Y\xc2\xc5\xae\x8b\xd7\xd9'。我不能把这个十六进制字符串转换成普通的ASCII/英语!谢谢在python中,有没有一种方法可以从我原来的256位键中获得零填充的键?是的,有(
key+=b'\0'*(32-len(key))
),但我认为填充键不是一个好主意。相反,在Python和PHP中都使用32字节的密钥。哇,这是一个很好的答案!当然,键不应该是字符串。如果只使用小写字符,则可获得与之相当的强度
log_2(26^len(“akshayaksh”))
或。就在这时,字母是完全随机选择的——它们可能不是。@t.m.adam:“可能是印度名字,通过谷歌快速搜索”-->这是PO的名字。;-)顺便说一句,谢谢你们三位提出的问题和详尽的答案。
<?php
require 'vendor/autoload.php';

use Fernet\Fernet;

$key = '[Base64url encoded fernet key]';
$fernet = new Fernet($key);

$token = $fernet->encode('string message');

$message = $fernet->decode('fernet token');
if ($message === null) {
    echo 'Token is not valid';
}

?>
from cryptography.fernet import Fernet
# Put this somewhere safe!
key = Fernet.generate_key()
f = Fernet(key)
token = f.encrypt(b"A really secret message. Not for prying eyes.")
f.decrypt(token)
print(token)