使用有效密钥的 AES 256 ECB 解密 returns strange/characters

AES 256 ECB decyption with valid key returns strange/characters

我正在尝试使用函数 openssl_decrypt 在 PHP 中解密。

问题是返回的字符串部分正确但部分是乱码

`@M{-Y  f{5678","token":null}`

如有任何帮助,我们将不胜感激

首先我认为这是一个编码问题所以我尝试使用此函数更改编码但没有成功

mb_convert_encoding($data,'UTF-8');

这是我正在使用的简单函数

$secret="#oc*Zd'&'&%rez`&;957.u1c:(|'%c81";


$data="SsxrFLoAWTPP7t8AR1/QFXSkZF6Xl2DXGV8Ay90rXk1sgwN46CmSmWsBqTvhbeUT";

$decrypted=openssl_decrypt($data,'aes-256-cbc',$secret);

var_dump($decrypted);

这应该是预期的输出

`{"reg_no":"UP2345678","token":null}

CBC 模式需要 IV。加密的 IV 必须用于解密。在发布的示例中,openssl_decrypt 调用中没有传递 IV(对应于具有 0 值的 IV),因此第一个块(1 个块 = 16 字节)被错误地解密。

原则上,如果已知密钥、明文和密文,则可以重构IV:解密密文的第一块(没有IV),并将结果与​​明文的第一块进行异或。这导致发布示例中数据的以下 IV(十六进制字符串):3B297D2864244336363339332B2D2826。使用此 IV

的输出
$secret = "#oc*Zd'&'&%rez`&;957.u1c:(|'%c81";
$iv = hex2bin('3B297D2864244336363339332B2D2826');
$data = "SsxrFLoAWTPP7t8AR1/QFXSkZF6Xl2DXGV8Ay90rXk1sgwN46CmSmWsBqTvhbeUT";
$decrypted = openssl_decrypt($data, 'aes-256-cbc',$secret, 0, $iv);
print('Decrypted data: '.$decrypted);

对应预期结果:

{"reg_no":"UP2345678","token":null}

编辑:

虽然我认为很清楚,但我想提一下,下面描述的方式当然不是确定解密IV的常规方式(那根本行不通,因为明文不是已知)。通常用于加密的 IV 只是与密文一起发送给接收者。这是可能的,因为 IV 不必保密。 即在发布的示例中,IV 由于某种原因丢失了,尽管它实际上应该存在。

无论如何,IV也可以通过以下方式确定,使用明文,密文和密钥:在CBC模式的描述中可以看出,在加密开始时,第一个明文的块和IV是XOR-ed,然后结果被加密。因此,可以通过首先解密这个第一个加密块然后 XOR-ing 明文的结果来确定 IV。对应的PHP-code为:

// Step 1: Decrypt the first block of the ciphertext (no IV is used which is equivalent to a 0-IV)  
$ciphertext = base64_decode('SsxrFLoAWTPP7t8AR1/QFXSkZF6Xl2DXGV8Ay90rXk1sgwN46CmSmWsBqTvhbeUT');
$ciphertextFirstBlock = substr($ciphertext, 0, 16);                                                                               // First block / 16 Byte of encrypted data
$decryptedFirstBlock = openssl_decrypt($ciphertextFirstBlock, 'aes-256-cbc', $secret,  OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);  // First block / 16 Byte of decrypted data
print('Decrypted first block: '.bin2hex($decryptedFirstBlock)."\n");

// Step 2: XOR the result with the first block of the plaintext
$plaintext = '{"reg_no":"UP2345678","token":null}';
$plaintextFirstBlock = substr($plaintext, 0 , 16);                                                                                // First block / 16 Byte of plaintext
$ivReconstructed = $decryptedFirstBlock ^ $plaintextFirstBlock;
print('Reconstructed IV: '.bin2hex($ivReconstructed)."\n");