NSCharacterSet URLHostAllowedCharacterSet не заменяет знак "+"?

Я пытаюсь передать длинные зашифрованные строки по сети и заставить их правильно выходить на сервер. Например, у меня есть эта зашифрованная строка на клиенте:

wcWSERZCh8Xm1hpbNo1kSD1LvFmpuUr4wmq9hQUWeK0vYcLeFPGwFR/sBTES1A4rPV6eyp9nzEEU9uKkiFSTdP + SPOSqUf6evjf3WRHrXMRe81lIrHuRyk0iRwoNe5uIk + VlpR41kETmznXa4 + gELmf53r7oayRkkffnIPDmpO + WbgE0VL3PQeOsXB01tWJyDiBIsz5WJiiEIm3ZoJW/SW ==

Как вы можете видеть, у него есть несколько символов, которые не будут передаваться по сети без какой-либо кодировки URL (+ и /, наиболее заметно). Я не совсем уверен, могут ли быть другие персонажи, которые могут возникнуть в других ситуациях, поэтому я хочу убедиться, что мое решение "универсально" правильно. Я использую эту строку:

NSString *escapedString = [cipherString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];

который я нашел в высоко оцененном ответе .

Однако у меня все еще есть проблемы с расшифровкой этого на стороне сервера, поэтому я распечатывал результаты на клиенте непосредственно перед отправкой, и я вижу это:

wcWSERZCh8Xm1hpbNo1kSD1LvFmpuUr4wmq9hQUWeK0vYcLeFPGwFR% 2FsBTES1A4rPV6eyp9nzEEU9uKkiFSTdP + SPOSqUf6evjf3WRHrXMRe81lIrHuRyk0iRwoNe5uIk + VlpR41kETmznXa4 + gELmf53r7oayRkkffnIPDmpO + WbgE0VL3PQeOsXB01tWJyDiBIsz5WJiiEIm3ZoJW% 2Fsw ==

Почему знаки "+" все еще существуют? Использую ли я неправильный набор символов? Какой набор символов я должен использовать, чтобы гарантировать, что я правильно избавимся от всех проблемных символов?

Если это помогает, вот код, который я использую для шифрования строки обычного текста. Когда это будет сделано, я base64 кодирую результаты перед отправкой по сети:

- (NSData *)phpEncryptCleartext : (NSData *)cleartext
{
    NSData *cleartextPadded = [self phpPadData:cleartext];

    CCCryptorStatus ccStatus        = kCCSuccess;
    size_t          cryptBytes      = 0;    // Number of bytes moved to buffer.
    NSMutableData  *cipherTextData  = [NSMutableData dataWithLength:cleartextPadded.length];

    ccStatus = CCCrypt(kCCEncrypt,
                       kCCAlgorithmAES128,
                       0,
                       _sessionKey.bytes,
                       kCCKeySizeAES128,
                       _iv.bytes,
                       cleartextPadded.bytes,
                       cleartextPadded.length,
                       cipherTextData.mutableBytes,
                       cipherTextData.length,
                       &cryptBytes);

    if (ccStatus == kCCSuccess) {
        cipherTextData.length = cryptBytes;
    }
    else {
        NSLog(@"kEncryptionError code: %d", ccStatus); // Add error handling
        cipherTextData = nil;
    }

    return cipherTextData;
}

Спасибо за любой совет!

Ответ 1

Быстрая версия здесь.

Чтобы избежать использования символа stringByAddingPercentEncodingWithAllowedCharacters:

NSString *URLEscapedString =
[string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

Ниже приведены полезные наборы символов, на самом деле символы, не входящие в набор:

URLFragmentAllowedCharacterSet  "#%<>[\]^`{|}
URLHostAllowedCharacterSet      "#%/<>[email protected]\^`{|}
URLPasswordAllowedCharacterSet  "#%/:<>[email protected][\]^`{|}
URLPathAllowedCharacterSet      "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet     "#%<>[\]^`{|}
URLUserAllowedCharacterSet      "#%/:<>[email protected][\]^`

Или создайте свой собственный набор символов только с теми символами, которые вам нужно выполнить.

NSCharacterSet *customCharacterset = [[NSCharacterSet characterSetWithCharactersInString:@"your characters"] invertedSet];

Создание набора символов, объединяющего все вышесказанное:

NSCharacterSet *URLFullCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@" \"#%/:<>[email protected][\\]^`{|}"] invertedSet];

Создание Base64

В случае набора символов Base64:

NSCharacterSet *URLBase64CharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"/+=\n"] invertedSet];

Примечание: stringByAddingPercentEncodingWithAllowedCharacters также кодирует символы UTF-8, требующие кодирования.

Пример проверки символов в наборе:

void characterInSet(NSCharacterSet *set) {
    NSMutableString *characters = [NSMutableString new];
    NSCharacterSet *invertedSet = set.invertedSet;
    for (int i=32; i<127; i++) {
        if ([invertedSet characterIsMember:(unichar)i]) {
            NSString *c = [[NSString alloc] initWithBytes:&i length:1 encoding:NSUTF8StringEncoding];
            [characters appendString:c];
        }
    }
    printf("characters not in set: '%s'\n", [characters UTF8String]);
}