在 PHP 中使用 PBEWithMD5AndTripleDES 解密

Decryption using PBEWithMD5AndTripleDES in PHP

我正在努力将 API 集成到我们的网络应用程序中。在初始请求中,API returns 响应使用 PBEWithMD5AndTripleDES 加密,然后进行 base 64 编码。我有一个事先提供给我的加密密码。由于我缺乏经验和 PBEWithMD5AndTripleDES 文档,我很难解密响应。我试过使用 phpseclib 但没有任何运气。

这是我的 phpseclib 代码

        $res = $response->getBody()->getContents();
        $res = base64_decode($res);
        // this is provided by vendor
        $password = self::PASSWORD;
        // I tried this too.
        //$password = md5(utf8_encode($password), true);

        $tripleDes = new TripleDES(TripleDES::MODE_CBC);
        $tripleDes->setKey($password);
        $ddd = $tripleDes->decrypt($res);

        // this is returning false
        var_dump($ddd); die();

能否请您提供一些有关如何在 PHP 中使用 PBEWithMD5AndTripleDES 的示例,或者为我提供一些指导或文档。

PBEWithMD5AndTripleDES 使用基于 MD5 的算法进行密钥/IV 推导,该算法需要密码、盐和迭代计数作为参数。对于采用 24 字节密钥的 CBC 模式 (des-ede3-cbc) 中的加密,应用了 TripleDES。

PBEWithMD5AndTripleDESPKCS#5 (RFC 8018) to support longer keys, here 中定义的 password-based 加密的 Oracle 专有扩展。因为它是专有的,并且由于 MD5 等过时的算法和与 AES 相比相对较慢的 TripleDES,它不应该用于新的实现,而只是为了与旧代码兼容。

我还没有在网上找到任何支持 PBEWithMD5AndTripleDES out-of-the-box 的 PHP 库(仅针对不同的 PBEWithMD5AndDES,例如 here). For a custom implementation you actually only need the derivation of the key / IV. So if you don't find an implementation either, but you have compelling reasons to use this algorithm: Here 是实现推导的 Java 代码。到 PHP 的端口可以是:

function deriveKeyIV($key, $salt, $count){
    
    $result = "";
    for ($var = 0; $var < 4; $var++){
        if($salt[$var] != $salt[$var + 4])
        break;
    }
    if ($var == 4){
        for ($var = 0; $var < 2; $var++){
            $tmp = $salt[$var];
            $salt[$var] = $salt[3 - $var];
            $salt[3 - 1] = $tmp;
        }
    }
    for ($var = 0; $var < 2; $var++){
    
        $toBeHashed = substr($salt, $var * (strlen($salt) / 2), strlen($salt) / 2);
        for ($var2 = 0; $var2 < $count; $var2++){
            $toBeHashed = hash ("MD5", $toBeHashed . $key, TRUE);
        }
        $result = $result . $toBeHashed;
    }
    
    return $result;
}

函数returns32字节,其中前24字节为key,后8字节为IV。使用此密钥和 IV,可以在 CBC 模式下使用 TripleDES 进行加密。

示例:

$keyIv = deriveKeyIV(hex2bin("01026161afaf0102fce2"), hex2bin("0788fe53cc663f55"), 65536);
$key = substr($keyIv, 0, 24);
$iv = substr($keyIv, 24, 8);

print(bin2hex($key) . "\n");
print(bin2hex($iv) . "\n");
print(openssl_encrypt("The quick brown fox jumps over the lazy dog", "des-ede3-cbc", $key, 0, $iv));

输出:

543650085edbbd6c26149c53a57cdd85871fd91c0f6d0be4
d7ffaa69502309ab
m4pye0texirKz1OeKqyKRJ5fSgWcpIPEhSok1SBDzgPthsw9XUuoiqXQBPdsVdUr

作为参考,我使用了 Java 实现,更准确地说是 SunJCE 提供商的 PBEWithMD5AndTripleDES 的实现,它给出了 相同 结果。

请注意,PBEWithMD5AndTripleDES 的原始实现只允许 正好 8 字节大小的盐(尽管推导函数可以处理更大的盐),否则抛出异常(盐必须是 8 字节长)。要添加此约束,可以在 deriveKeyIV 开头添加以下内容:

if (strlen($salt) != 8) {
    throw new Exception('Salt must be 8 bytes long');
}