Проблема Base64 в сообщении POST NSMutableURLRequest?
У меня проблемы со связью между моим приложением и сервером. Я использую RNCryptor для шифрования сообщения, которое затем кодирую с помощью base64 и передаю на сервер в запросе. Это делается как в заголовке DATA, так и в теле http как данные публикации. Я думаю, что я делаю ошибку в том, как я конвертирую и передаю закодированное в base64 сообщение через POST.
Если я получаю зашифрованное сообщение через заголовок, оно прекрасно расшифровывается каждый раз. Однако, если я получу сообщение через данные POST, я получу разные результаты. Большую часть времени он терпит неудачу, иначе он частично расшифровывает (первые несколько букв), с 1 из 20 или около того успешных расшифровок.
Код объективного c:
- (NSString *)sendEncryptedTestMessage:(NSString *)address{
NSString* messageContent = @"Hello my name is Bob.";
NSError * error = nil;
NSString* responseString2 = nil;
NSData* postData = [RNEncryptor encryptData:[messageContent dataUsingEncoding:NSUTF8StringEncoding]
withSettings:kRNCryptorAES256Settings
password:@"123456"
error:&error];
NSString* messageServer = [NSString base64forData:postData];
NSString* postMessage = [@"message=" stringByAppendingString:messageServer];
postData = [postMessage dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; // problem here I think
NSString* postLength = [NSString stringWithFormat:@"%ld",(unsigned long)[postData length]];
NSURL* URLToRequest = [NSURL URLWithString:address];
NSMutableURLRequest* semisystem = [[[NSMutableURLRequest alloc] initWithURL:URLToRequest] autorelease];
[semisystem setHTTPMethod:@"POST"];
[semisystem setHTTPBody:postData];
[semisystem setValue:postLength forHTTPHeaderField:@"Content-Length"];
[semisystem setValue:self.activationURL forHTTPHeaderField:@"EncryptionKey"];
[semisystem setValue:messageServer forHTTPHeaderField:@"data"];
NSURLResponse* response;
NSData* data = [NSURLConnection sendSynchronousRequest:semisystem
returningResponse:&response
error:&error];
responseString2 = [NSString stringWithFormat:@"%.*s", (int)[data length], [data bytes]];
return responseString2;
}
Код PHP:
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";
$messageBase64 = $_POST['message'];// THIS barely works
$messageBase64 = $_SERVER['HTTP_DATA'];// THIS WORKS
$message = decrypt2($messageBase64,$passkey);
Спасибо заранее!
3 ответа
Я знаю, что это старый вопрос, но долгое время я использовал одно и то же решение, и проблема заключалась в том, что мы не кодируем должным образом URL-адрес перед выполнением запроса к серверу. В документации сказано:
According to RFC 3986, the reserved characters in a URL are:
reserved = gen-delims / sub-delims
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="
А вот как кодировать строку: /
CFStringRef encodedString =
CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(__bridge CFStringRef)(originalString),
NULL,
CFSTR(":/?#[]@!$&'()*+,;="),kCFStringEncodingUTF8);
И снова получить строку:
NSString* stringEncoded = CFBridgingRelease
(CFURLCreateWithString(kCFAllocatorDefault, encodedString, NULL));
Я думаю, что это лучшее, что мы можем сделать, потому что мы гарантируем, что строка будет правильно закодирована, и во время запроса символы не будут заменены другими вещами. вот ссылки:
Я только что нашел решение. Во время запроса символы "+" интерпретируются сервером как пробельные символы, нарушая код base64. Следующая строка исправила эту проблему:
postMessage = [postMessage stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
Вы можете проверить свою закодированную / декодированную строку, в этом URL
http://meyerweb.com/eric/tools/dencoder/
Как вы можете видеть, "+" изменяется на "%2B" при нажатии кнопки кодирования.