首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >iOS常用加密解密RC4加密视频文件内存崩溃

iOS常用加密解密RC4加密视频文件内存崩溃
EN

Stack Overflow用户
提问于 2018-11-09 22:33:35
回答 1查看 122关注 0票数 0

我正在解密一个视频文件,这对小尺寸的文件很好,但对于300mb以上的文件,有内存崩溃。代码如下:我检查了开始字节值,它一直到315mb,然后崩溃,我的文件大小是350mb。

它在很少的iphones上工作,对少数人崩溃,最好的解决方案是分块进行,以避免内存问题,但它也会崩溃。

代码语言:javascript
复制
#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
EN

回答 1

Stack Overflow用户

发布于 2018-11-11 03:52:03

如果replaceBytesInRange:bytesRange导致了崩溃,那么我关于如何避免崩溃的第一个建议是为它所依赖的前面的函数调用添加错误检查。

例如,在它崩溃的情况下,bytesRange可能不是一个有效/可用的值。也许它的dataOut是无效/可用的。问题中的代码从函数调用中设置这些值,但不检查错误条件/错误指示器/无效值的返回值。

它可能是一个相关的依赖函数调用。例如,通过调用CCCryptorUpdate()来设置cryptStatus,它将dataOut作为输入参数。我不知道Objective-C,也不熟悉函数CCCryptorUpdate(),但它看起来会影响/填充dataOut。如果它实际上返回了一个错误,那么当您在replaceBytesInRange行上使用它时,dataOut可能还没有处于可用状态。检查cryptStatus的返回值可能会标记不应在以后的调用中继续使用dataOut的情况。

这就引出了我注意到的另一件事:您确实检查了一些东西,但只记录了它们。对if (dataOutMoved != dataOutLength)(cryptStatus != kCCSuccess)的检查看起来应该停止执行,或者中断循环,或者类似的事情,而不仅仅是记录发生的事情。

我看到的另一件事是dataOut只被malloc()'d一次,而不是被清除,并且被重复使用。这在某些情况下是完全有效的,但它也可能导致您所看到的那种错误。您的代码中是否有任何关于dataOut内容的假设?我在考虑采用空值终止的C字符串操作。如果不小心,假设在那里(或者可能实际上一开始就在那里)的空终止符可能会被覆盖,比如说,如果整个缓冲区被填满了。再说一次,我不太了解Objective-C和这些函数,所以这不是一个特定的声明,而是对可能发生的事情的一种类比。

TL;DR:向每个函数调用添加错误检查,并做出相应的响应(中断、退出、重试等),这样以后的函数调用就不会尝试使用指示错误或其他无效的值。

我敢打赌,通过添加错误检查,您将(1)停止崩溃,(2)了解为什么大于一定数量的文件会导致这些崩溃。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53227711

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档