如何在php中使用AES-256-CCM解密一个加密的文本?

问题描述 投票:0回答:1

我试图在PHP中解密一个用以下方法加密的芯片文本。AES-256-CCM 使用 cryptography.hazmat 在python中,我在我的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 , nonceciphertext 到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#enfunction.openssl-encrypt.html。 我找不到另一个例子,解密过程中没有返回任何东西,真正让我困惑的是。

  1. 我们在python代码中没有使用IV来加密,但PHP需要非NULL的IV,如何解决这个问题?
  2. 怎么解决?$tag 在PHP代码中表示,$tag_lenght在PHP和python(cipher = AESCCM(key, tag_length=8)) ?
  3. 如果需要解密 nonce 如何在我的PHP代码中使用它?

如何让这个工作? 从python中加密,并在PHP中解密相同的芯片文本。

说明:我必须使用python进行加密,php进行解密,我必须使用AES-CCM,python的代码是固定的,谢谢你的理解。

谢谢

python php cryptography aes
1个回答
1
投票

在PHP实现中,似乎有一个错误,对于非ce长为 12 字节(OP使用的),导致密码文本标签错误。然而,这个错误被OP的PHP代码中的一些缺陷所隐藏。因此,必须先修复这些缺陷。

  • Python和PHP实现的不同之处在于,在Python代码中,密文和tag是按顺序连接的,而在PHP代码中,密文和tag是分开处理的。
  • Python代码中的nonce对应于PHP代码中的IV。
  • 在 PHP 代码中 OPENSSL_RAW_DATA 如果密文是作为原始数据而非 Base64 编码传递的,则必须设置该标志。
  • 在两个代码中,nonce和密文(+标签)的值是不同的。但是,由于选择了12字节的nonce,再加上12字节nonce的PHP bug,修正是没有意义的,见下文。也就是说,测试成功的前提条件是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代码,我们可以从Python代码中解密数据 只要nonce的长度不等于 12 字节数.

Python和PHP的实现允许一个长度为 713 字节 (都包括在内), s. 此处为Python. 关于这个问题 12 字节的nonce,结果如下。如果在PHP代码中 12 字节的 nonce 被截断为 7 通过删除最后一个 5 字节数, 一样 ciphertexttag被创建。下面的PHP代码说明了以下标签长度的情况 816 字节(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 实现中的一个错误。

与此相反,Python代码会对不同的 12 与PHP代码相比,字节数为nonce(这就是为什么(修正后的)OP的PHP代码使用了一个 12 字节nonce失败)。) 用相同参数的JavaBC检查会产生以下结果 一样 的密文标记 12 bytes nonce作为Python代码,验证了Python代码的值,再次说明PHP实现中的一个bug。

EDIT:我已经在这里提交了一个问题。https:/bugs.php.netbug.php?id=79601. : 该问题已确定为: 私人 由管理员管理,所以如果没有相应的权限就无法打开(至少目前是这样),s。这里的.

© www.soinside.com 2019 - 2024. All rights reserved.