使用PHP解密RNCryptor 1.x的输出

时间:2013-05-06 17:19:33

标签: php encryption aes rncryptor

我一直在我的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行加密的数据。没错,任何人都知道如何自己调整上述功能?谢谢!

1 个答案:

答案 0 :(得分: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(因此更安全。)有关详细信息,请参阅this post on Rob Napier's blog

我决定彻底检查RNCryptor中包含的PHP实现,以便记录此问题并防止其他人(您!)遇到问题。我还希望实现现代化并使其面向对象。见my forked RNCryptor on Github。我也提交了一个拉取请求,所以希望它也会在rnapier/RNCryptor中结束。

干杯!

相关问题