2

アプリとサーバー間の通信に問題があります。RNCryptorを使用してメッセージを暗号化し、それをbase64でエンコードして、リクエストでサーバーに転送します。これは、DATAヘッダーと、投稿データとしてのhttp本文の両方で行われます。POSTを介してbase64でエンコードされたメッセージを変換および転送する方法を間違えていると思います。

暗号化されたメッセージをヘッダー経由で受信すると、毎回完全に正常に復号化されます。ただし、POSTデータを介してメッセージを取得すると、さまざまな結果が得られます。ほとんどの場合、失敗します。それ以外の場合は、部分的に復号化され(最初の数文字)、20分の1程度の復号化が成功します。

Objective-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);

よろしくお願いします!

4

3 に答える 3

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));

文字列が適切にエンコードされ、リクエスト中に記号が他のものに置き換えられないようにするため、これが最善の方法だと思います。ここに参照があります:

http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFURLRef/Reference/reference.html#//apple_ref/c/func/CFURLCreateStringByAddingPercentEscapes

http://developer.apple.com/library/ios/#documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/WorkingWithHTTPAndHTTPSRequests/WorkingWithHTTPAndHTTPSRequests.html

于 2013-07-12T23:11:07.487 に答える
2

解決策を見つけました。リクエスト中、「+」記号はサーバーによって空白として解釈され、base64コードを壊します。次の行でこの問題が修正されました。

postMessage       = [postMessage stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
于 2013-02-12T21:30:46.517 に答える
-1

このURLで、エンコード/デコードされた文字列を確認できます

http://meyerweb.com/eric/tools/dencoder/

ご覧のとおり、エンコードボタンを押すと「+」が「%2B」変化します。

于 2014-02-07T17:38:31.933 に答える