2014-05-14 2 views
0

CommonCrypto를 사용하여 NSMutableData 객체를 암호화 (복제하지 않고 결과 바이트를 복사)하려고합니다. 이전에는 CCCrypt() "one-shot"방법을 사용했습니다. 주로 단순 해 보였기 때문입니다. 내 데이터 객체가 메모리에 중복되어있는 것으로 나타났습니다. 이 문제를 방지하기 위해 2048 바이트의 버퍼 크기를 가진 NSInputStream 개체를 사용하려고했습니다. NSMutableData 객체를 읽고 CCCryptorUpdate()를 호출하여 암호화를 처리합니다. 문제는 여전히 복제 된 것으로 보인다는 것입니다. 나는 확실히 여기에 분명 뭔가, 암호화 누락, 심지어 사용하고NSInputStream을 사용하여 NSMutableData 암호화를 구현했습니다.

- (BOOL)encryptWithKey:(NSString *)key 
{ 
    // Key creation - not relevant to the dercribed problem 
    char * keyPtr = calloc(1, kCCKeySizeAES256+1); 
    [key getCString: keyPtr maxLength: sizeof(keyPtr) encoding: NSUTF8StringEncoding]; 

    // Create cryptographic context for encryption 
    CCCryptorRef cryptor; 
    CCCryptorStatus status = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode, keyPtr, kCCKeySizeAES256, NULL, &cryptor); 
    if (status != kCCSuccess) 
    { 
     MCLog(@"Failed to create a cryptographic context (%d CCCryptorStatus status).", status); 
    } 

    // Initialize the input stream 
    NSInputStream *inStream = [[NSInputStream alloc] initWithData:self]; 
    [inStream open]; 
    NSInteger result; 
    // BUFFER_LEN is a define 2048 
    uint8_t buffer[BUFFER_LEN]; 
    size_t bytesWritten; 

    while ([inStream hasBytesAvailable]) 
    { 
     result = [inStream read:buffer maxLength:BUFFER_LEN]; 
     if (result > 0) 
     { 
      // Encryption goes here 
      status = CCCryptorUpdate(
            cryptor,    // Previously created cryptographic context 
            &result,    // Input data 
            BUFFER_LEN,   // Length of the input data 
            [self mutableBytes], // Result is written here 
            [self length],   // Size of result 
            &bytesWritten   // Number of bytes written 
            ); 

      if (status != kCCSuccess) 
      { 
       MCLog(@"Error during data encryption (%d CCCryptorStatus status)", status); 
      } 
     } 
     else 
     { 
      // Error 
     } 
    } 

    // Cleanup 
    [inStream close]; 
    CCCryptorRelease(cryptor); 
    free(keyPtr); 
    return (status == kCCSuccess); 
} 

: 여기에 내 현재 코드입니다 (- - 때문에 주로 역사적인 이유 때문에 "자기"참조가 NSMutableData에 카테고리의주의하시기 바랍니다) 입력 스트림은 .. 저 비트 새로운 라인에

+0

입력 및 출력 버퍼로 인해 발생하는 문제는 무엇입니까? – zaph

+0

문제는 암호화해야 할 큰 문서가 있으며 메모리에 복제 할 필요가 없다는 것입니다. –

+0

그래서 실제로는 일시적인 메모리 사용 문제는 없습니다. 음, 그것이 바로 기억이 사용되는 것입니다. 이를 사전 성숙 최적화 라하며 문제가 있는지를 결정하기 전에 최적화합니다. 거의 항상 그것은 잘못 보낸 시간입니다. – zaph

답변

0

:

result = [inStream read:buffer maxLength:BUFFER_LEN]; 

데이터는 buffer로 판독되고 result의 실행의 결과로 설정된다. 라인 :

status = CCCryptorUpdate(cryptor, &result, ... 

당신은 간단한 오류를 제거 도움이 더 나은 이름을 사용하지 상태, 입력 데이터에 대한

status = CCCryptorUpdate(cryptor, buffer, ... 

buffer를 사용한다. result 대신 변수 이름이 readStatus 인 경우 오류가 발생하지 않을 가능성이 높습니다. 마찬가지로 데이터 변수 buffer의 이름을 지정하는 대신 streamData이라는 것이 더 명확 해졌습니다. 잘못된 이름 지정은 실제로 오류를 유발할 수 있습니다.

+0

당신은 분명히 그 중 하나에 맞습니다, 그러나 그것은 복제의 원인이 아니 었습니다. –

+0

나는 Rob을'CCUpdate()'에 대해 이해하고 보았다. – zaph

2

CCUpdate() 한 번만 호출하면 스트림을 사용하지 않고 읽은 동일한 버퍼로 암호화 할 수 있습니다. 예를 들어 RNCryptManager.m을 참조하십시오. 연구 applyOperation:fromStream:toStream:password:error:. 여기에서는 스트림을 사용했지만, 이미 NSData 인 경우에는 스트림을 수행 할 필요가 없습니다.

그러나 CCUpdate()은 한 번만 호출해야합니다. 여러 번 호출하면 자체 버퍼가 손상됩니다. 이것은 CommonCryptor (radar://9930555)의 열린 버그입니다.

키 생성은 극도로 안전하지 않으며 이러한 유형의 데이터에 ECB 모드를 사용하면 암호화가 거의되지 않습니다. 데이터를 암호 해독하는 데 사용할 수있는 암호문에 패턴을 남깁니다 (in some cases just by looking at it). 실제로이 데이터를 보안하려는 경우이 방법을 사용하지 않는 것이 좋습니다. 이러한 도구를 잘 사용하는 방법을 배우려면 Properly Encrypting With AES With CommonCrypto을 참조하십시오. 미리 패키지 된 솔루션을 원하면 RNCryptor을 참조하십시오. 그러나 현재 RNCryptor에는 내부 암호화에 편리한 방법이 없습니다.

+0

문제는 문서가 큽니다. 가능하다면 메모리에 데이터를 적게 갖고 싶습니다. 그래서 내가 스트림을 사용할 것이라고 생각했습니다. (링크를 가져 주셔서 감사합니다, 나는 그들을 확실히 연구 할 것입니다). –

+0

내부 변환은 확실히 유효한 유스 케이스이지만 데이터를 전송할 때 단순히 해독하거나 암호화하는 것이 더 편리합니다. 예를 들어 RNCryptor의 비동기 인터페이스를 살펴보십시오. 예를 들어, NSURLConnection을 통해 다운로드되는 데이터를 쉽게 해독 할 수 있습니다. 약간의 여분의 코드를 사용하면 스트림을 읽거나 암호화하는 동안 암호를 해독하여 메모리에 암호화 된 버전이 필요하지 않게 할 수 있습니다. –

+0

이것은 완벽하게 유효한 관찰입니다. 불행히도 기존의 (심지어 빈약 한) 솔루션을 바꿀 수있는 위치에 있지 않아 장소 암호화가 유일한 옵션입니다. 또한 CCCreate() 및 CCCUpdate()를 사용하여 원샷 CCCrypt() 또는 "일반적인"프로세스를 사용하여 버퍼를 해결하지 못했습니다. –