python - 如何使用AES-256-CCM通过python在php中解密加密文本
问题描述
我试图在 PHP 中解密一个AES-256-CCM
用python 加密的芯片文本,cryptography.hazmat
我在 python 代码中所做的是:
from cryptography.hazmat.primitives.ciphers.aead import AESCCM
from os import urandom
import base64
#Text To Encrypt
plaintext = bytes("message from python", encoding='utf-8')
#AES 256 Key Genrator
key = AESCCM.generate_key(256)
#Genrate Nonce
nonce= urandom(12)
#chipher
cipher = AESCCM(key, tag_length=8)
#Encryption
ciphertext = cipher.encrypt(nonce, plaintext, None)
然后我将key
,nonce
和转换ciphertext
为 base64
key_b64 = base64.standard_b64encode(key)
ciphertext_b64 = base64.standard_b64encode(ciphertext)
nonce_b64 = base64.standard_b64encode(nonce)
在我的例子中,我得到了这个结果
key = b'\xcb\x14\x96{,0(\x15\x86 \xda\xf8\x1b"i|M\xbd\xc5d\xe7\xa6I\xdf\x7f\xe11\xae\xe8\x8a\xb3j'
key_b64 = b'yxSWeywwKBWGINr4GyJpfE29xWTnpknff+ExruiKs2o='
nonce = b'\xc7f\xdc\xe3\xe4\x03>M\x9by\x92\x9d
nonce_b64 = b'x2bc4+QDPk2beZKd'
ciphertext = b'R\x9f\xe6D\\_\xdexC\x82\xf8\x8e\x9b;\x91\xc7OLo\xc2\t/\x8fV>G='
ciphertext_b64 = b'Up/mRFxf3nhDgviOmzuRx09Mb8IJL49WPkc9'
我在我的 PHP 代码中使用 base64 结果
<?php
$key_from_python = base64_decode('yxSWeywwKBWGINr4GyJpfE29xWTnpknff+ExruiKs2o=');
$ciphertext_from_python = base64_decode('ooGUzo0YiwKPs9+2wXySYEpdBNfSpyLUHm1M');
$nonce_from_python = base64_decode('Up/x2bc4+QDPk2beZKd');
$cipher = "aes-256-ccm";
if (in_array($cipher, openssl_get_cipher_methods())){
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$decrypted_mesage_from_pythom =
openssl_decrypt($encrypted_from_python_,$cipher,$key_from_python,$options=0 , $iv, $tag);
echo $decrypted_mesage_from_pythom;
}
它基于我在这里找到的一个例子http://php.babo.ist/#/en/function.openssl-encrypt.html我找不到另一个例子解密过程不返回任何东西
,真正让我困惑的是:
- 我们没有在 python 代码中使用 IV 加密,但 PHP 需要非 NULL IV,如何解决?
- PHP 代码和 $ tag_lenght
$tag
在 PHP 和 python(cipher = AESCCM(key, tag_length=8)) 中代表什么? - 如果解密需要
nonce
如何在我的 PHP 代码中使用它?
如何得到这份工作?从 python 加密并在 PHP 中解密相同的密文
注意:我必须使用python加密和php解密,我必须使用AES-CCM,python代码是固定的,谢谢你的理解
谢谢你
解决方案
AES-CCM 的 PHP 实现中似乎存在一个错误,该错误导致随机数12
字节长度(由 OP 使用)导致错误的密文/标签。然而,这个错误被 OP 的 PHP 代码中的许多缺陷所隐藏。因此,必须首先修复这些缺陷:
- Python 和 PHP 实现的不同之处在于,在 Python 代码中,密文和标签按顺序连接,而在 PHP 代码中,密文和标签是分开处理的。
- Python 代码中的 nonce 对应于 PHP 代码中的 IV。
- 在 PHP 代码中,
OPENSSL_RAW_DATA
如果密文作为原始数据而不是 Base64 编码传递,则必须设置该标志。 - 随机数和密文(+ 标记)的值在两种代码中不同。但是,由于选择的 12 字节 nonce 以及针对 12 字节 nonce 的 PHP 错误,更正是没有意义的,见下文。即成功测试的先决条件是nonce 大小不等于12 字节。
考虑到这些点的 PHP 实现是例如
<?php
// Data from Python code
$key_from_python = base64_decode('<Base64 encoded key from Python>');
$ciphertext_from_python = base64_decode('<Base64 encoded (ciphertext + tag) from Python>');
$nonce_from_python = base64_decode('<Base64 encoded nonce from Python>');
$cipher = 'aes-256-ccm';
// Separate ciphertext and tag
$tagLength = 8;
$ciphertext = substr($ciphertext_from_python, 0, -$tagLength);
$tag = substr($ciphertext_from_python, -$tagLength);
// Decrypt
if (in_array($cipher, openssl_get_cipher_methods())){
$decrypted_mesage_from_pythom = openssl_decrypt($ciphertext, $cipher, $key_from_python, OPENSSL_RAW_DATA, $nonce_from_python, $tag);
echo $decrypted_mesage_from_pythom;
}
?>
使用这个 PHP 代码,只要 nonce 的长度不等于12
bytes ,就可以从 Python 代码中解密数据。
Python 和 PHP 实现允许一个长度为7
to13
字节(包括两个字节)、s 的随机数。这里是 Python。关于12
字节随机数的问题,结果如下:如果在 PHP 代码中通过删除最后一个字节将12
字节随机数截断为字节,则创建相同的密文/标签。以下 PHP 代码说明了标签长度和字节(PHP 版本 7.4.4)的这一点:7
5
8
16
<?php
function printCiphertextTag($plaintext, $key, $iv, $taglength){
$encrypted = openssl_encrypt($plaintext, "aes-256-ccm", $key, OPENSSL_RAW_DATA, $iv, $tag, NULL, $taglength);
echo sprintf("tag size: %2s, IV size: %2s, IV (hex): %-' 24s, ciphertext (hex): %s, tag (hex): %s\n", $taglength, strlen($iv), bin2hex($iv), bin2hex($encrypted), bin2hex($tag));
}
$plaintext = 'message from python';
$key = '01234567890123456789012345678901';
$nonce12 = openssl_random_pseudo_bytes(12);
$nonce7 = substr($nonce12, 0, 7);
printCiphertextTag($plaintext, $key, $iv = $nonce12, $taglength = 8);
printCiphertextTag($plaintext, $key, $iv = $nonce7, $taglength = 8);
printCiphertextTag($plaintext, $key, $iv = $nonce12, $taglength = 16);
printCiphertextTag($plaintext, $key, $iv = $nonce7, $taglength = 16);
?>
此结果表明 PHP 实现中存在错误。
相比之下,与 PHP 代码相比,Python 代码为12
字节随机数生成不同的密文/标签(这就是使用12
字节随机数的(更正的)OP 的 PHP 代码失败的原因)。使用相同参数对 Java/BC 进行检查会为字节随机数生成与 Python 代码相同的密文/标签12
,这会验证 Python 代码的值并再次指示 PHP 实现中的错误。
编辑:我在这里提出了一个问题:https ://bugs.php.net/bug.php?id=79601 。注意:该问题由管理员设置为私有,因此如果没有适当的权限(至少目前)无法打开它,s。在这里。
推荐阅读
- python - Python:如何将在执行 A 期间创建的变量从脚本 A 导入到脚本 B?
- java - 在 JFrame 中显示 java 程序中生成的 pdf 文档的内容,无需创建 pdf 文件
- validation - Oracle ADF 页面生命周期以及如何执行验证检查
- unit-testing - 如何告诉 Makemaker 并行运行测试?
- stanford-nlp - 为什么 ConceptNet Numberbatch 词嵌入对类比查询的结果很差?
- python - 仅遍历列表列表中的第一个列表
- python - 仅遍历列表列表中的第一个列表
- python - Too Many Indices 错误,使用循环神经网络进行自然语言生成
- python - discord.py 的问题“如果 channel.id ==”
- xamarin.forms - 在 Android 中关闭 CustomTabs(xamarin 表单)时卡在空白屏幕上