如何使用 AES-256-CCM 在 php 中通过 python 解密加密文本
how to decrypt in php an encrypted text by python using AES-256-CCM
我正在尝试使用 python 中的 cryptography.hazmat
解密 PHP 中使用 AES-256-CCM
加密的密文
我在 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,我找不到另一个例子
解密过程没有 return 任何东西
真正让我困惑的是:
- 我们没有使用 IV 在 python 代码中加密,但是 PHP 需要
非NULL IV,如何解决?
$tag
在 PHP 代码中代表什么,$tag_lenght 在 PHP 和
python(密码=AESCCM(密钥,tag_length=8))?
- 如果解密需要
nonce
如何在我的 PHP 代码中使用它?
如何获得这项工作?从 python 加密并在 PHP
中解密相同的密文
注意:我必须使用python进行加密,php进行解密,我必须使用AES-CCM,python 代码已修复,感谢您的理解
谢谢
AES-CCM 的 PHP 实现中似乎有一个错误,随机数长度为 12
字节(由 OP 使用)导致错误 ciphertext/tag .但是,此错误被 OP 的 PHP 代码中的许多缺陷所隐藏。因此,必须首先修复这些缺陷:
- Python 和 PHP 实现的不同之处在于,在 Python 代码中,密文和标签按该顺序连接,而在 PHP 代码中,密文和标签分开处理。
- Python代码中的随机数对应PHP代码中的IV。
- 在 PHP 代码中,如果密文作为原始数据传递而不是 Base64 编码,则必须设置
OPENSSL_RAW_DATA
标志。
- 随机数和密文(+ 标记)的值在两个代码中不同。但是,由于选择的 12 字节随机数与 12 字节随机数的 PHP 错误相结合,更正毫无意义,请参见下文。 IE。成功测试的先决条件是随机数大小不等于 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 代码,可以从 Python 代码 解密数据,只要随机数的长度不等于 12
字节。
Python 和 PHP 实现允许长度为 7
到 13
字节(包括两者)的随机数,s。 here for Python。关于 12
字节随机数的问题,结果如下: 如果在 PHP 代码中,通过删除最后一个 5
字节,same ciphertext/tag 被创建。以下 PHP 代码说明了 8
和 16
字节的标签长度(PHP 版本 7.4.4):
<?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
字节随机数生成不同的 ciphertexts/tags (这就是为什么(更正的)OP PHP 使用 12
字节随机数的代码失败)。使用具有相同参数的 Java/BC 进行检查会为 12
字节的随机数生成 相同的 ciphertexts/tags 作为 Python 代码,它验证了Python 代码的值并再次表明 PHP 实现中的错误。
编辑:我在这里提交了一个问题:https://bugs.php.net/bug.php?id=79601. Note: The issue was set to private by the admins, so that it cannot be opened (at least for now) without the appropriate permissions, s. here。
我正在尝试使用 python 中的 cryptography.hazmat
解密 PHP 中使用 AES-256-CCM
加密的密文
我在 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,我找不到另一个例子
解密过程没有 return 任何东西
真正让我困惑的是:
- 我们没有使用 IV 在 python 代码中加密,但是 PHP 需要 非NULL IV,如何解决?
$tag
在 PHP 代码中代表什么,$tag_lenght 在 PHP 和 python(密码=AESCCM(密钥,tag_length=8))?- 如果解密需要
nonce
如何在我的 PHP 代码中使用它?
如何获得这项工作?从 python 加密并在 PHP
中解密相同的密文注意:我必须使用python进行加密,php进行解密,我必须使用AES-CCM,python 代码已修复,感谢您的理解
谢谢
AES-CCM 的 PHP 实现中似乎有一个错误,随机数长度为 12
字节(由 OP 使用)导致错误 ciphertext/tag .但是,此错误被 OP 的 PHP 代码中的许多缺陷所隐藏。因此,必须首先修复这些缺陷:
- Python 和 PHP 实现的不同之处在于,在 Python 代码中,密文和标签按该顺序连接,而在 PHP 代码中,密文和标签分开处理。
- Python代码中的随机数对应PHP代码中的IV。
- 在 PHP 代码中,如果密文作为原始数据传递而不是 Base64 编码,则必须设置
OPENSSL_RAW_DATA
标志。 - 随机数和密文(+ 标记)的值在两个代码中不同。但是,由于选择的 12 字节随机数与 12 字节随机数的 PHP 错误相结合,更正毫无意义,请参见下文。 IE。成功测试的先决条件是随机数大小不等于 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 代码,可以从 Python 代码 解密数据,只要随机数的长度不等于 12
字节。
Python 和 PHP 实现允许长度为 7
到 13
字节(包括两者)的随机数,s。 here for Python。关于 12
字节随机数的问题,结果如下: 如果在 PHP 代码中,通过删除最后一个 5
字节,same ciphertext/tag 被创建。以下 PHP 代码说明了 8
和 16
字节的标签长度(PHP 版本 7.4.4):
<?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
字节随机数生成不同的 ciphertexts/tags (这就是为什么(更正的)OP PHP 使用 12
字节随机数的代码失败)。使用具有相同参数的 Java/BC 进行检查会为 12
字节的随机数生成 相同的 ciphertexts/tags 作为 Python 代码,它验证了Python 代码的值并再次表明 PHP 实现中的错误。
编辑:我在这里提交了一个问题:https://bugs.php.net/bug.php?id=79601. Note: The issue was set to private by the admins, so that it cannot be opened (at least for now) without the appropriate permissions, s. here。