使用openssl_decrypt解密aes-128-gcm加密文件

问题描述 投票:0回答:1

我们正在尝试解密通过 AS4 协议和 SOAP 消息收到的文件。我们可以使用“openssl_private_decrypt”解密密钥。但解密的密钥大小为 256 字节,与“openssl_decrypt”密钥大小所需的大小不匹配:

$privateKey = '*hidden*';
$passPhrase = '*hidden*';
$supplierCypherValue = 'ePsYNDRENhm/PJ1+3UT7V5U94/mP/wiPtILqBea869SnZh9olcVglJcOJZc7qexii4ewb00qopIW0HP8xYn4uQ7MNoh2fDfCQUd0hwGrIxcYQL3IBijccLJHKx0FmPIOLui3z4+sXLUz5sCBzQdzJWt2q3Uz/fkfXceVbqo5tn5jMwuayQ+uzQg86Uf+fhoGI891XFeVGQgemhPc9NigIlx/Z/W9+4B1QxM+Kd5mgOQHmNl6vF/n+q6g4TIvjZSQFuYPH7/Edb0e7eqDsEHrnfRtmTanw4YEDDALu3KECTI692i2W0f0TJRtXptwjMN9k5rA2i6rQWLyFny+6x74rQ==';
$base64DecodedCipherValue = base64_decode($supplierCypherValue);
$privateKey = openssl_pkey_get_private($privateKey, $passPhrase);
$decryptedKey = '';
openssl_private_decrypt($base64DecodedCipherValue,$decryptedKey, $privateKey, OPENSSL_NO_PADDING); // Output = true
// For further testing purposes, $decryptedKey bin output in hex format:
$decryptedKeyHex = '00853d1a77f1e400c602c26bd97aaaaa408c0dbb95d92ce85713d9418cfb51fab5fc956629e769d703330530ae7ce797919abc396846a5faa81e43769bf2dc3e9c19cb548aad34967d934c8d8ddffc1ac97002ca06c9caf32d5c2f5cab4e31c18276c3860c7f7f542fbd331586b227aaae63f4d0dd94bcd0089ffabf230381bc9d107fa8bb93679415b1a2d1c53d1100d1adf966271c6753ae91ccc29a84baa5b63c1e7c4bed07a23a18c366608a55806e9073485aef9c4a500f71ff8d9888dc92bd7b7f02108fda47e9af81bcc7074b46d87efa45c474be187f8ada412359a1630daf11ff9c3d85622715ec19537ed00289f124c334af49f7ef5e8f1f833be5';
$decryptedKey = hex2bin($decryptedKeyHex);
// Continue
$cipher = 'aes-128-gcm';
$binaryData = 'binary data';
$ivlen = openssl_cipher_iv_length($cipher);
$iv = substr($binaryData, 0, $ivlen);
$ciphertext_raw = substr($binaryData, $ivlen, -16);
$tag = substr($binaryData, -16);

$decryptedData = openssl_decrypt(
    $ciphertext_raw,
    $cipher,
    $decryptedKey,
    OPENSSL_RAW_DATA,
    $iv,
    $tag
);

if (empty($decryptedData)) {
    var_dump(openssl_error_string());
    throw new \Exception('Decription failed');
}

输出:

string(89) "error:0607A082:digital envelope routines:EVP_CIPHER_CTX_set_key_length:invalid key length"

Exception : Decription failed

我们尝试了 openssl_decrypt 方法的几种变体。更改IV或数据仍然会出现密钥长度无效的错误。二进制内容应解密为 gzipped xml 文档。

php openssl aes-gcm
1个回答
0
投票

正如评论中已经提到的,由于

OPENSSL_NO_PADDING
选项,在 RSA 解密 AES 密钥期间不会删除填充。您必须指定使用的填充,而不是
OPENSSL_NO_PADDING
。然而,从解密的数据中,无法明确确定应用了哪种填充。也许这些信息可以在元数据中找到(我不熟悉 AS4 协议)。

假设解密成功,由于前导 0x00 字节且不符合 PKCS#1 v1.5 (RSAES-PKCS1-v1_5),数据很可能符合 OAEP (RSAES-OAEP)。然而,OAEP 参数,特别是 OAEP 和 MGF1 摘要,无法从数据中得出。这里只能尝试一下,通常的摘要是SHA256或SHA1。

由于 PHP/OpenSSL 仅支持 SHA1,因此该库不太适合于此。例如,完全支持 OAEP 的 PHP 库是 phpseclib。或者,由于解密已经发生,因此也可以“手动”执行取消填充,如“RFC8017,第 7.1.2 章,步骤 3”中所述,例如如果假设 SHA256 作为摘要: <?php const DIGEST = 'sha256'; const DIGEST_LEN = 32; const KEY_LEN = 256; $key = hex2bin("00853d1a77f1e400c602c26bd97aaaaa408c0dbb95d92ce85713d9418cfb51fab5fc956629e769d703330530ae7ce797919abc396846a5faa81e43769bf2dc3e9c19cb548aad34967d934c8d8ddffc1ac97002ca06c9caf32d5c2f5cab4e31c18276c3860c7f7f542fbd331586b227aaae63f4d0dd94bcd0089ffabf230381bc9d107fa8bb93679415b1a2d1c53d1100d1adf966271c6753ae91ccc29a84baa5b63c1e7c4bed07a23a18c366608a55806e9073485aef9c4a500f71ff8d9888dc92bd7b7f02108fda47e9af81bcc7074b46d87efa45c474be187f8ada412359a1630daf11ff9c3d85622715ec19537ed00289f124c334af49f7ef5e8f1f833be5"); $Y = substr($key, 0, 1); $maskedSeed = substr($key, 1, DIGEST_LEN); $maskedDB = substr($key, 1 + DIGEST_LEN); $seedMask = mgf1($maskedDB, DIGEST_LEN); $seed = _xor($maskedSeed, $seedMask); $dbMask = mgf1($seed, KEY_LEN - DIGEST_LEN - 1); $db = _xor($maskedDB, $dbMask); print(bin2hex($db) . PHP_EOL); // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012df6648fa1770d6a8ef0fd4e15f75141 // from https://en.wikipedia.org/wiki/Mask_generation_function#MGF1 function mgf1($mgfSeed, $maskLen) { $t = ''; $count = ceil($maskLen / DIGEST_LEN); for ($i = 0; $i < $count; $i++) { $c = pack('N', $i); $t .= hash(DIGEST, $mgfSeed . $c, true); } return substr($t, 0, $maskLen); } function _xor($v1, $v2) { $res = ''; for($i = 0; $i < strlen($v1); $i++){ $res .= $v1[$i] ^ $v2[$i]; } return $res; } ?> 这提供了有效的结果,即满足 OAEP 规范的结果(在步骤 3g 中):

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012df6648fa1770d6a8ef0fd4e15f75141

给出以下 16 字节 AES 密钥(十六进制编码):

2df6648fa1770d6a8ef0fd4e15f75141

© www.soinside.com 2019 - 2024. All rights reserved.