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


Decrypting output of RNCryptor 1.x using PHP

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

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

这是RNCryptor代码,用于解密来自2。x线:

/**
 * @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;
}

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

我意识到我的问题和我想的有点不同。我实际上是在不知不觉中使用RNCryptor 2.0,但事实证明,潜在的问题仍然存在,PHP实现RNCryptor包括没有解密我的数据。

以下是我今天经过几个小时的研究和测试后得出的结论:RNCryptor不只是自己加密数据。它还添加了自定义标头和HMAC数字签名。不幸的是,自从RNCryptor 1.0发布以来,这种布局报头和HMAC的模式已经改变了几次。

RNCryptor 1.0和1.1使用架构版本0。我的头撞了很长时间比我愿意承认,我只是不能得到AES CTR Little-Endian en/解密工作在PHP。(有人知道吗?)

RNCryptor 2.0使用模式1,RNCryptor 2.1使用模式2。唯一的区别是,在模式1中,HMAC仅从有效负载生成,而不是从报头生成。Schema 2 正确地从有效负载加上报头生成HMAC(因此更安全)。更多信息可以在Rob Napier的博客上找到。

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

干杯!