用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)