iOS Common Crypto Decrypt RC4 Зашифрованный видеофайл Сбой памяти - PullRequest
0 голосов
/ 09 ноября 2018

Я расшифровываю видеофайл, который отлично работает для файлов небольшого размера, но для файлов размером более 300 Мб происходит сбой памяти. Код как ниже: Я проверил значение начального байта, оно идет до 315 МБ, а затем вылетает, мой файл имеет размер 350 МБ.

Он работает для нескольких iPhone и сбоев для немногих. Лучшим решением было бы сделать это порциями, чтобы избежать проблем с памятью, но при этом также происходит сбой.

#define kChunkSizeBytes (1024*1024) // 1 MB

@implementation NSMutableData (Crypto)
   -(BOOL) doCrypto:(NSString *)key operation: (CCOperation) operation
{

    //Keeping it 32 as per our key
    char keyPtr[512 + 1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr));     // fill with zeroes (for padding)

    // Fetch key data

    if (![key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]) {return FALSE;} // Length of 'key' is bigger than keyPtr

    CCCryptorRef cryptor;




    CCCryptorStatus cryptStatus = CCCryptorCreate(operation, kCCAlgorithmRC4, 0,
                                                  keyPtr, key.length,
                                                  NULL, // IV - needed?
                                                  &cryptor);

    if (cryptStatus != kCCSuccess) { // Handle error here
        return FALSE;
    }

    size_t dataOutMoved;
    size_t dataInLength = kChunkSizeBytes; // #define kChunkSizeBytes (16)
    size_t dataOutLength = CCCryptorGetOutputLength(cryptor, dataInLength, FALSE);
    size_t totalLength = 0; // Keeps track of the total length of the output buffer
    size_t filePtr = 0;   // Maintains the file pointer for the output buffer
    NSInteger startByte; // Maintains the file pointer for the input buffer

    char *dataIn = malloc(dataInLength);
    char *dataOut = malloc(dataOutLength);
    NSRange bytesRange = NSMakeRange((NSUInteger) 0, (NSUInteger) 0);

    for (startByte = 0; startByte <= [self length]; startByte += kChunkSizeBytes) {
            if ((startByte + kChunkSizeBytes) > [self length]) {
                dataInLength = [self length] - startByte;
            }
            else {
                dataInLength = kChunkSizeBytes;
            }

            // Get the chunk to be ciphered from the input buffer
            bytesRange = NSMakeRange((NSUInteger) startByte, (NSUInteger) dataInLength);
            [self getBytes:dataIn range:bytesRange];
            cryptStatus = CCCryptorUpdate(cryptor, dataIn, dataInLength, dataOut, dataOutLength, &dataOutMoved);

            if (startByte >= 203728200) {
                NSLog(@"%ld",(long)startByte);
            }
            if (dataOutMoved != dataOutLength) {
                NSLog(@"dataOutMoved (%d) != dataOutLength (%d)", dataOutMoved, dataOutLength);
            }

            if ( cryptStatus != kCCSuccess)
            {
                NSLog(@"Failed CCCryptorUpdate: %d", cryptStatus);
            }

            // Write the ciphered buffer into the output buffer
            bytesRange = NSMakeRange(filePtr, (NSUInteger) dataOutMoved);
            [self replaceBytesInRange:bytesRange withBytes:dataOut];
            totalLength += dataOutMoved;

            filePtr += dataOutMoved;

    }

    // Finalize encryption/decryption.
    cryptStatus = CCCryptorFinal(cryptor, dataOut, dataOutLength, &dataOutMoved);
    totalLength += dataOutMoved;

    if ( cryptStatus != kCCSuccess)
    {
        NSLog(@"Failed CCCryptorFinal: %d", cryptStatus);
    }

    // In the case of encryption, expand the buffer if it required some padding (an encrypted buffer will always be a multiple of 16).
    // In the case of decryption, truncate our buffer in case the encrypted buffer contained some padding
    [self setLength:totalLength];

    // Finalize the buffer with data from the CCCryptorFinal call
    NSRange bytesNewRange = NSMakeRange(filePtr, (NSUInteger) dataOutMoved);
    [self replaceBytesInRange:bytesNewRange withBytes:dataOut];

    CCCryptorRelease(cryptor);

    free(dataIn);
    free(dataOut);

    return 1;
}
@end

1 Ответ

0 голосов
/ 10 ноября 2018

Если replaceBytesInRange:bytesRange вызывает сбой, то мое первое предложение о том, как избежать сбоя, - добавить проверку ошибок для предыдущих вызовов функций, от которых это зависит.

Например, в тех случаях, когда происходит сбой, возможно, bytesRange не является допустимым / полезным значением. Может быть, это dataOut, что недопустимо / пригодно для использования. Ваш код в вашем вопросе устанавливает эти значения из вызовов функций, но не проверяет возвращаемое значение для условий ошибок / индикаторов ошибок / недопустимых значений.

Это может быть связанный вызов зависимой функции. например, cryptStatus устанавливается с помощью вызова CCCryptorUpdate(), который имеет dataOut в качестве входного параметра. Я не знаю Objective-C, и я не знаком с функцией CCCryptorUpdate(), но похоже, что это повлияет на / заполнит dataOut. Если он на самом деле возвращает ошибку, то, вероятно, dataOut, вероятно, не будет в пригодном для использования состоянии к тому времени, когда вы используете его в строке replaceBytesInRange. Проверка возвращаемого значения cryptStatus может помечать условия, когда вы должны не продолжать использовать dataOut в последующих вызовах.

Что подводит меня к другому, что я заметил: вы делаете проверяете пару вещей, но только регистрируете их. Проверки для if (dataOutMoved != dataOutLength) и для (cryptStatus != kCCSuccess) выглядят как вещи, которые должны остановить выполнение, или выйти из цикла, или что-то в этом роде, а не просто регистрировать вхождение.

Еще одна вещь, которую я вижу, это то, что dataOut - это malloc() один раз, не очищается и используется повторно. Это может быть вполне допустимо в некоторых обстоятельствах, но также может вызвать именно ту ошибку, которую вы видите. Что-нибудь в вашем коде предполагает что-либо о содержимом dataOut? Я размышляю в духе строковых операций C, которые предполагают нулевое завершение. Если не соблюдать осторожность, нулевые терминаторы, которые, как предполагается, находятся там (или, возможно, на самом деле находятся там сначала), могут быть перезаписаны, если, скажем, весь буфер заполнен. Опять же, я не очень хорошо знаю Objective-C и эти функции, так что это не конкретное утверждение, а скорее аналогия вида вещей, которые могут происходить.

TL; DR : добавьте проверку ошибок для каждого из ваших вызовов функций и отвечайте соответствующим образом (прерывание, выход, повтор, все что угодно), чтобы последующий вызов функции не пытался использовать значения, которые указывают на ошибки или являются недопустимыми.

Держу пари, что с добавленной проверкой ошибок вы (1) остановите сбои и (2) узнаете что-то конкретное о , почему это то, что файлы, превышающие определенное количество, вызывают эти сбои.

...