title: NSData with CCCrypt in multi-threaded environment
body: <p>I have a file that was encrypted using AES.
  I use the following NSData category:</p>
  
  <pre><code>#import &lt;CommonCrypto/CommonCryptor.h&gt;
  
  @implementation NSData (AES)
  
  - (NSData *)AES256DecryptWithKey:(NSString *)key {
  
      // 'key' should be 32 bytes for AES256, will be null-padded otherwise
      char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
      bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
  
      // fetch key data
      [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
  
      NSUInteger dataLength = [self length];
  
      //See the doc: For block ciphers, the output size will always be less than or 
      //equal to the input size plus the size of one block.
      //That's why we need to add the size of one block here
      size_t bufferSize = dataLength + kCCBlockSizeAES128;
  
      void *buffer = malloc(bufferSize);
  
      size_t numBytesDecrypted = 0;
      CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                            kCCAlgorithmAES128,
                                            kCCOptionPKCS7Padding,
                                            keyPtr,
                                            kCCKeySizeAES256,
                                            NULL /* initialization vector (optional) */,
                                            [self bytes], dataLength, /* input */
                                            buffer,       bufferSize, /* output */
                                            &amp;numBytesDecrypted);
  
      NSLog(@"Bytes decrypted: %d",numBytesDecrypted);
  
      if (cryptStatus == kCCSuccess) {
          //the returned NSData takes ownership of the buffer and will free it on deallocation
          return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
      }
  
      NSLog(@"Decrypt failed with error code %d",cryptStatus);
      free(buffer); //free the buffer;
      return nil;
  }
  
  @end
  </code></pre>
  
  <p>The descrypt process seems to work fine when I load the entire file from filesystem with the following code:</p>
  
  <pre><code>[NSData dataWithContentsOfFile:dataPath];
  </code></pre>
  
  <p>The problem occurs when the file is not read with the previous call but when an external code that chunk the file and init an NSData with only a little chunk of data and try to decrypt this, in particolar the problems occurs when different thread use this code (or at least is what i think):</p>
  
  <pre><code>- (NSData *)readDataOfLength:(NSUInteger)length
  {
      HTTPLogTrace2(@"%@[%p]: readDataOfLength:%lu", THIS_FILE, self, (unsigned long)length);
  
      if (![self openFileIfNeeded])
      {
          // File opening failed,
          // or response has been aborted due to another error.
          return nil;
      }
  
      // Determine how much data we should read.
      // 
      // It is OK if we ask to read more bytes than exist in the file.
      // It is NOT OK to over-allocate the buffer.
  
      UInt64 bytesLeftInFile = fileLength - fileOffset;
  
      NSUInteger bytesToRead = (NSUInteger)MIN(length, bytesLeftInFile);
  
      // Make sure buffer is big enough for read request.
      // Do not over-allocate.
  
      if (buffer == NULL || bufferSize &lt; bytesToRead)
      {
          bufferSize = bytesToRead;
          buffer = reallocf(buffer, (size_t)bufferSize);
  
          if (buffer == NULL)
          {
              HTTPLogError(@"%@[%p]: Unable to allocate buffer", THIS_FILE, self);
  
              [self abort];
              return nil;
          }
      }
  
      // Perform the read
  
      HTTPLogVerbose(@"%@[%p]: Attempting to read %lu bytes from file", THIS_FILE, self, bytesToRead);
  
      ssize_t result = read(fileFD, buffer, bytesToRead);
  
      // Check the results
  
      if (result &lt; 0)
      {
          HTTPLogError(@"%@: Error(%i) reading file(%@)", THIS_FILE, errno, filePath);
  
          [self abort];
          return nil;
      }
      else if (result == 0)
      {
          HTTPLogError(@"%@: Read EOF on file(%@)", THIS_FILE, filePath);
  
          [self abort];
          return nil;
      }
      else // (result &gt; 0)
      {
          HTTPLogVerbose(@"%@[%p]: Read %d bytes from file", THIS_FILE, self, result);
  
          fileOffset += result;
  
          NSData *data = [NSData dataWithBytes:buffer length:result];
          return [data AES256DecryptWithKey:@"abcdefghijklmnopqrstuvwxyz123456"];
          //return data;
      }
  }
  </code></pre>
  
  <p>What happens is that the function CCCrypt in this case fail with error code -4304 AKA "kCCDecodeError - Input data did not decode or decrypt properly."</p>
  
  <p>Moreover if in the CCCrypt call instead of kCCOptionPKCS7Padding i pass 0 -> No padding the method decrypt the first chunk of data but when the thread is switched it fails with -4300 AKA "kCCParamError - Illegal parameter value."</p>
  
  <p>With the following message in console:</p>
  
  <pre><code>[Switching to process 13059 thread 0x0]
  2011-05-25 18:00:03.631 Drm[1843:6e0b] Bytes decrypted: 131072
  2011-05-25 18:00:03.647 Drm[1843:6e0b] Bytes decrypted: 68096
  [Switching to process 11779 thread 0x0]
  2011-05-25 18:00:04.547 Drm[1843:6e0b] Bytes decrypted: 0
  2011-05-25 18:00:04.555 Drm[1843:6e0b] Decrypt failed with error code -4300
  </code></pre>
  
  <p>Someone can help?</p>