PHP aes-128-gcm openssl_decrypt仅在使用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,$tag);
$decrypted2 = openssl_decrypt($enc,$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";
?>

输出

普通: 0f00102d280c07e4081f01103b1000ff8880020c09060006190900ff090d323232313230323031323735360904103b1000090507e4081f0106004c48df06000000cb06000089cf06000e61e7060000020a060000000009000900

enc: 09e89c959cd513057787832142e6796e1f6de55cba8e5cec6e16aa635b3b102ddb22d85841923ddc2ee3052027945dfd00d025a0a5d0eb385e0033dd28037d80b47522b3db310b01871474686b609d2da15864785895>

十二月:

dec2: 0f00102d280c07e4081f01103b1000ff8880020c09060006190900ff090d323232313230323031323735360904103b1000090507e4081f0106004c48df06000000cb06000089cf06000e61e7060000020a060000000009000900

解决方法

欢迎使用Stackoverflow。您正在GCM模式下使用AES算法,这意味着密文可以防止通过“身份验证标签”或简称“标签”进行修改。该标签是在使用AES-GCM加密明文时生成的,在解密密文时需要使用。

在您的代码中,为解密功能提供了一个空的$ 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,$tag);
echo "tag: ".bin2hex($tag)."<br>" . PHP_EOL;
$decrypted2 = openssl_decrypt($enc,$tag);

结果:

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

使用解决方案进行编辑

根据@Maarten Bodewes(https://stackoverflow.com/a/49244840/8166854)的回答,有可能对“ aes gcm”进行解密 没有身份验证标签的加密数据,因为

AES GCM = AES CTR + AuthTag

按如下所示更改源代码会按预期在第一次运行时解密密码,我将十六进制数据'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,$tag);
$methodCtr = 'aes-128-ctr';
$ivCtr = hex2bin('534D5367700114E600102D2900000002');
$decryptedCtr = openssl_decrypt($enc,$methodCtr,$ivCtr);
$encrypted = openssl_encrypt($plain,$tag);
echo "tag: ".bin2hex($tag)."<br>" . PHP_EOL;
$decryptedGcm = openssl_decrypt($enc,$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";
?>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...