PHP aes-128-gcm openssl_decrypt 仅在使用 openssl_encrypt 后有效

PHP aes-128-gcm openssl_decrypt only works after using openssl_encrypt

我必须解密从外部方获得的 aes-128-gcm 加密数据。由于 openssl_decrypt 从未返回任何数据,我尝试自己加密其他地方的解密数据,看看是否有效,实际上我收到了我尝试解密的相同加密数据。因此我知道,我所有的参数都是正确的。所以我玩弄了我的 PHP 代码并得出了一个奇怪的结论,在我加密明文之后解密数据只对我有用?!? 有人知道这里发生了什么吗?

谢谢, 哈利

<?php

$method='aes-128-gcm';

$key = hex2bin('0748BEF58E04D5917ED0B9B558628265');

//echo "iv_length: ". openssl_cipher_iv_length($method)."<br>";
$iv = hex2bin('534D5367700114E600102D29');
$tag = NULL;

$enc = hex2bin('09E89C959CD513057787832142E6796E1F6DE55CBA8E5CEC6E16AA635B3B102DDB22D85841923DDC2EE3052027945DFD00D025A0A5D0EB385E0033DD28037D80B47522B3DB310B01871474686B609D2DA15864785895DF2BE887');
$plain = hex2bin('0F00102D280C07E4081F01103B1000FF8880020C09060006190900FF090D323232313230323031323735360904103B1000090507E4081F0106004C48DF06000000CB06000089CF06000E61E7060000020A060000000009000900');

$decrypted = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
$encrypted = openssl_encrypt($plain, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
$decrypted2 = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);

echo "plain: ".bin2hex($plain)."<br>";
echo "enc: ".bin2hex($encrypted)."<br>";
echo "dec: ".bin2hex($decrypted)."<br>";
echo "dec2: ".bin2hex($decrypted2)."\n";

while ($msg = openssl_error_string())
    echo $msg . "<br>\n";
?>

输出:

普通话: 0F00102D280C07E4081F011103B1000FF8888888888888888888888888888888888888888888888888888881906190619090909090D323232323232323232313233233233237373736090900090009079090907E407E4081FB1700907E4081FIMNE太平洋兰

编码: 09e89c959cd513057787832142e6796e1f6de55cba8e5cec6e16aa635b3b102ddb22d85841923ddc2ee3052027945dfd00d025a0a5d0eb385e0033dd28037d80b47522b3db310b01871474686b609d2da15864785895df2be887

十二月:

十二月 2: 0F00102D280C07E4081F011103B1000FF8888888888888888888888888888888888888888888888888888881906190619090909090D323232323232323232313233233233237373736090900090009079090907E407E4081FB1700907E4081FIMNE太平洋兰

欢迎使用 Whosebug。您正在 GCM 模式下使用 AES 算法,这意味着密文不会被“身份验证标签”或短“标签”修改。此标签在使用 AES-GCM 加密明文时生成,并且在解密密文时需要可用。

在您的代码中,您向 decrypt-function 提供了一个空的 $tag-variable 并且解密失败。使用 openssl_encrypt 生成“新”明文时,您的 $tag-variable 会填充一个标签。现在您再次解密并将此标记提供给 openssl_decrypt-function 并且解密按预期进行。

所以需要从第三方获取$tag的值才能成功解密密文回明文

使用源代码中的这个小改动,程序提供了 $tag:

$decrypted = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
echo "tag: ".bin2hex($tag)."<br>" . PHP_EOL;
$encrypted = openssl_encrypt($plain, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
echo "tag: ".bin2hex($tag)."<br>" . PHP_EOL;
$decrypted2 = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);

结果:

tag: <br>
tag: 9268f3568512fc9f15075096c1b47902<br>

用解决方案编辑

根据@Maarten Bodewes () 的回答,有机会解密“aes gcm” 没有认证标签的加密数据因为

AES GCM = AES CTR + AuthTag

按如下所示更改您的源代码可以在第一个 运行 中按预期解密密码,我手动将 hex-data '00000002' 添加到 iv:

plain:  0f00102d280c07e4081f01103b1000ff8880020c09060006190900ff090d323232313230323031323735360904103b1000090507e4081f0106004c48df06000000cb06000089cf06000e61e7060000020a060000000009000900<br>
enc:    09e89c959cd513057787832142e6796e1f6de55cba8e5cec6e16aa635b3b102ddb22d85841923ddc2ee3052027945dfd00d025a0a5d0eb385e0033dd28037d80b47522b3db310b01871474686b609d2da15864785895df2be887<br>
decCtr: 0f00102d280c07e4081f01103b1000ff8880020c09060006190900ff090d323232313230323031323735360904103b1000090507e4081f0106004c48df06000000cb06000089cf06000e61e7060000020a060000000009000900<br>
decGcm: 0f00102d280c07e4081f01103b1000ff8880020c09060006190900ff090d323232313230323031323735360904103b1000090507e4081f0106004c48df06000000cb06000089cf06000e61e7060000020a060000000009000900

代码:

<?php
$method='aes-128-gcm';
$key = hex2bin('0748BEF58E04D5917ED0B9B558628265');
$iv = hex2bin('534D5367700114E600102D29');
$tag = NULL;
$enc = hex2bin('09E89C959CD513057787832142E6796E1F6DE55CBA8E5CEC6E16AA635B3B102DDB22D85841923DDC2EE3052027945DFD00D025A0A5D0EB385E0033DD28037D80B47522B3DB310B01871474686B609D2DA15864785895DF2BE887');
$plain = hex2bin('0F00102D280C07E4081F01103B1000FF8880020C09060006190900FF090D323232313230323031323735360904103B1000090507E4081F0106004C48DF06000000CB06000089CF06000E61E7060000020A060000000009000900');

//$decrypted = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
$methodCtr = 'aes-128-ctr';
$ivCtr = hex2bin('534D5367700114E600102D2900000002');
$decryptedCtr = openssl_decrypt($enc, $methodCtr, $key, OPENSSL_RAW_DATA, $ivCtr);
$encrypted = openssl_encrypt($plain, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);
echo "tag: ".bin2hex($tag)."<br>" . PHP_EOL;
$decryptedGcm = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);

echo "plain:  ".bin2hex($plain)."<br>" . PHP_EOL;
echo "enc:    ".bin2hex($encrypted)."<br>" . PHP_EOL;
echo "decCtr: ".bin2hex($decryptedCtr)."<br>" . PHP_EOL;
echo "decGcm: ".bin2hex($decryptedGcm)."\n" . PHP_EOL;
while ($msg = openssl_error_string())
    echo $msg . "<br>\n";
?>