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");