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