0

我正在尝试使用函数 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}
4

1 回答 1

1

CBC模式需要 IV 。加密的IV必须用于解密。在发布的示例中,-call 中没有传递 IV openssl_decrypt(对应于具有 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,然后对结果进行加密。因此,IV 可以通过首先解密这个第一个加密块,然后将结果与明文进行异或来确定。相应的 PHP 代码是:

// 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");
于 2019-05-25T14:40:49.700 回答