У меня есть зашифрованная переменная NSData, которая была закодирована Base64 в Objective-C и передается через POST в сценарий PHP. Я пытаюсь расшифровать эту строку, но продолжаю получать ошибку несоответствия HMAC. Вот мой код PHP:

// back to binary
$bin_data = mb_convert_encoding($username_encrypted, "UTF-8", "BASE64");
// 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);
// extract HMAC
$hmac = substr($bin_data, strlen($bin_data) - 32);

// make HMAC key
$hmac_key = pbkdf2('SHA1', $password, $hmac_salt, 10000, 32, true);
// make HMAC hash
$hmac_hash = hash_hmac('sha256', $data, $hmac_key, true);
// check if HMAC hash matches HMAC
if($hmac_hash != $hmac)
    exit("Error HMAC mismatch");

// make data key
$key = pbkdf2('SHA1', $password, $salt, 10000, 32, true);
// decrypt
$ret = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
echo trim(preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\xFF]/u', '', $ret));

function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        die('PBKDF2 ERROR: Invalid hash algorithm.');
    if($count <= 0 || $key_length <= 0)
        die('PBKDF2 ERROR: Invalid parameters.');

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}

А это мой код для iOS:

NSData *plain_data = [plain_string dataUsingEncoding:NSUTF8StringEncoding];
NSError *error_encryption = nil;
NSData *encrypted_data = [RNOpenSSLEncryptor encryptData:plain_data
                                            withSettings:kRNCryptorAES256Settings
                                                password:key
                                                   error:&error_encryption];

NSString *test_variable = [encrypted_data base64Encoding];

Есть идеи, что не так?

2
Wes Cossick 13 Мар 2013 в 08:42

1 ответ

Лучший ответ

Проблема была устранена следующим сообщением: Проблема с Base64 в сообщении POST NSMutableURLRequest?

По сути, PHP преобразовывал + в пробелы. Кроме того, я использовал функцию PHP decrypt2(), найденную в его примере, а не в моем. (Я включил приведенный ниже код для справки.)

function decrypt2($b64_data,$password)
{
            // back to binary
            //$bin_data = mb_convert_encoding($b64_data, "UTF-8", "BASE64");
            $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 = pbkdf2('SHA1', $password, $hmac_salt, 10000, 32, true);
            // make HMAC hash
            $hmac_hash = hash_hmac('sha256', $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 = pbkdf2('SHA1', $password, $salt, 10000, 32, true);
            // decrypt
            $ret = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);      
            return $ret;
}
$passkey = "123456";
1
Community 23 Май 2017 в 14:50
Вы уверены, что решили проблему несоответствия HMAC? В decrypt2() часть return false; закомментирована. Поэтому, если он не совпадает, он напечатает «Несоответствие HMAC» вместе с некоторыми ошибками E_NOTICE из-за отсутствия переменной $nl, после чего строка все равно будет расшифрована.
 – 
curtisdf
9 Май 2013 в 03:50
Я копался в своей собственной проблеме несоответствия HMAC и обнаружил, что данные RNCryptor, зашифрованные с помощью файла версии 1, вычисляют $ dataWithoutHMAC с только зашифрованным текстом, а не заголовками или IV. Для версии 1 во второй строке под extract data должно быть написано $dataWithoutHMAC = $data;.
 – 
curtisdf
9 Май 2013 в 04:45
К вашему сведению (так как это мой код), $ nl - это просто «
», так как я тестировал это в своем браузере. return false был заменен на echo "HMAC mismatch", чтобы упростить отладку. Если обнаружено несоответствие HMAC, проблема в другом месте, а не в этой строке.
 – 
Tiago
10 Фев 2014 в 14:18