0

我一直在我的 iOS 应用程序中使用RNCryptor。由于应用程序的一些问题,我需要解密一些运行 PHP 5.4 的数据服务器端。RNCryptor 包包含 PHP 代码,但它仅适用于 RNCryptor 的 2.x 分支。我的数据是用 1.x 分支加密的。不幸的是,RNCryptor 2.x 不向后兼容 1.x。

据我所知,这些分支之间的唯一区别是 1.x 使用 AES CTR 模式来加密文本,而 2.x 现在使用 AES CBC。但我不知道如何调整 PHP 代码以使用 CTR。我也不确定 1.x 和 2.x 之间是否还有其他变化。我发现关于 1.x 的有用信息非常少。

这是用于从 2.x 行解密数据的 RNCryptor 代码:

/**
 * @param string $b64_data Data encrypted by RNCryptor 2.x
 * @return string|false Decrypted plaintext string, or false if decryption fails
 */
function decrypt_data($b64_data) {
    global $gPassword; // the password string that was used to encrypt the data

    // kRNCryptorAES256Settings 
    $algorithm = MCRYPT_RIJNDAEL_128;
    $key_size = 32;
    $mode = MCRYPT_MODE_CBC;
    $pbkdf2_iterations = 10000;
    $pbkdf2_prf = 'sha1';
    $hmac_algorithm = 'sha256';

    // back to binary              
    $bin_data = base64_decode($b64_data);
    // extract salt
    $salt = substr($bin_data, 2, 8);
    // extract HMAC salt
    $hmac_salt = substr($bin_data, 10, 8);
    // extract IV
    $iv = substr($bin_data, 18, 16);
    // extract data
    $data = substr($bin_data, 34, strlen($bin_data) - 34 - 32);
    $dataWithoutHMAC = chr(2).chr(1).$salt.$hmac_salt.$iv.$data;
    // extract HMAC
    $hmac = substr($bin_data, strlen($bin_data) - 32);
    // make HMAC key
    $hmac_key = hash_pbkdf2($pbkdf2_prf, $gPassword, $hmac_salt, $pbkdf2_iterations, $key_size, true);
    // make HMAC hash
    $hmac_hash = hash_hmac($hmac_algorithm, $dataWithoutHMAC , $hmac_key, true);
    // check if HMAC hash matches HMAC  
    if($hmac_hash != $hmac) {
        echo "HMAC mismatch".$nl.$nl.$nl;
        return false;
    }
    // make data key
    $key = hash_pbkdf2($pbkdf2_prf, $gPassword, $salt, $pbkdf2_iterations, $key_size, true);

    // decrypt
    $cypher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
    // initialize encryption handle
    if (mcrypt_generic_init($cypher, $key, $iv) != -1) {
        // decrypt
        $decrypted = mdecrypt_generic($cypher, $data);

        // http://www.php.net/manual/en/function.mdecrypt-generic.php
        // We found that sometimes the resulting padding is not null characters "\0" but rather one of several control characters.
        // If you know your data is not supposed to have any trailing control characters "as we did" you can strip them like so.
        $decrypted = preg_replace( "/\p{Cc}*$/u", "", $decrypted );

        // clean up
        mcrypt_generic_deinit($cypher);
        mcrypt_module_close($cypher);

        return trim($decrypted);
    }
    return false;
}

我真的需要一个像上面这样的函数,它可以处理由 RNCryptor 的 1.x 行加密的数据。除此之外,有人知道我如何自己调整上述功能吗?谢谢!

4

1 回答 1

0

我意识到我的问题与我想的略有不同。我实际上在不知不觉中使用了 RNCryptor 2.0,但事实证明,根本问题仍然存在,即 RNCryptor 包含的 PHP 实现没有解密我的数据。

这是我今天经过数小时的研究和测试后学到的东西:RNCryptor 不只是自己加密数据。它还添加了自定义标头和 HMAC 数字签名。不幸的是,自从 RNCryptor 1.0 发布以来,这种用于布置标头和 HMAC 的架构已经更改了几次。

RNCryptor 1.0 和 1.1 使用架构版本 0。我为此付出的时间比我愿意承认的要长,而且我无法让 AES CTR Little-Endian en/decryption 在 PHP 中工作。(有人知道吗?)

RNCryptor 2.0 使用模式版本 1,而 RNCryptor 2.1 使用模式 2。唯一的区别是在模式 1 中,HMAC 仅从有效负载生成,而不是从标头生成。模式 2正确地从有效负载标头生成 HMAC (因此更安全)。更多关于这方面的信息可以在 Rob Napier 博客上的这篇文章中找到。

我决定彻底检查 RNCryptor 中包含的 PHP 实现,以记录这个问题并防止其他人(你!)遇到问题。我还想使实现现代化并使其面向对象。在 Github 上查看我的分叉 RNCryptor。我也提交了一个拉取请求,所以希望它最终也会出现在rnapier/RNCryptor中。

干杯!

于 2013-05-09T06:16:32.377 回答