具有有效密钥的AES 256 ECB解密返回奇数/字符

时间:2019-05-25 11:07:30

标签: php aes cbc-mode ecb

我正在尝试使用功能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}

2 个答案:

答案 0 :(得分:1)

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运算,然后对结果进行加密。因此,可以通过首先解密此第一个加密块,然后将结果与纯文本进行异或运算来确定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");

答案 1 :(得分:0)

@Topaco

非常感谢!

我想我需要开始学习密码学...:-)