文件末尾缺少RNCryptor字节

时间:2014-03-11 23:15:53

标签: encryption rncryptor

使用RNCryptor加密和解密文件,并且遇到一个我似乎无法获得完整文件的问题。

我的加密如下

- (void) encryptDownloadedFile:(NSString*)filename
{
    NSString *outputTmpFilePath = [downloadCacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mov", filename]];

    int blockSize = 32 * 1024;

    __block NSInputStream *plainTextStream = [NSInputStream inputStreamWithData:[downloadFileStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]];
    __block NSOutputStream *encryptedStream = [NSOutputStream outputStreamToFileAtPath:outputTmpFilePath append:NO];
    __block NSMutableData *downloadedFileData = [NSMutableData data];

    [plainTextStream open];
    [encryptedStream open];

    __block NSMutableData *data = [NSMutableData dataWithLength:blockSize];
    __block RNEncryptor *encryptor = nil;

    dispatch_block_t readStreamBlock = ^{
        [data setLength:blockSize];
        NSInteger bytesRead = [plainTextStream read:[data mutableBytes] maxLength:blockSize];

        if (bytesRead < 0) {
            // Throw an error
        }

        else if (bytesRead == 0) {
            [encryptor finish];

            [downloadedFileData writeToFile:outputTmpFilePath atomically:YES];

            [plainTextStream close];
            [encryptedStream close];
            [downloadFileStream close];
            plainTextStream = nil;
            encryptedStream = nil;
            downloadFileStream = nil;

        }
        else {
            [data setLength:bytesRead];
            [encryptor addData:data];
        }
    };

    encryptor = [[RNEncryptor alloc] initWithSettings:kRNCryptorAES256Settings
                                         password:@"blah"
                                          handler:^(RNCryptor *cryptor, NSData *data)     {

                                                  [downloadedFileData appendBytes:data.bytes length:data.length];

                                                  if (cryptor.isFinished) {

                                                  }
                                                  else {
                                                      readStreamBlock();
                                                  }
                                              }];
    readStreamBlock();
}

RNCryptor git页面上的示例非常标准。输入文件是先前使用

抓取的下载文件
downloadFileStream = [[NSOutputStream alloc] initToMemory];

解密完整性在这里

- (void) decryptDownloadedFile:(NSString*)filename
{
    NSString *inputTmpFilePath = [downloadCacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mov", filename]];
    NSString *outputTmpFilePath = [downloadCacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"decrypted%@.mov", filename]];

    int blockSize = 32 * 1024;

    NSInputStream *cryptedStream = [NSInputStream inputStreamWithFileAtPath:inputTmpFilePath];
    NSOutputStream *decryptedStream = [NSOutputStream outputStreamToFileAtPath:outputTmpFilePath append:NO];

    [cryptedStream open];
    [decryptedStream open];

    __block NSMutableData *data = [NSMutableData dataWithLength:blockSize];
    __block RNDecryptor *decryptor = nil;

    dispatch_block_t readStreamBlock = ^{
        [data setLength:blockSize];
        NSInteger bytesRead = [cryptedStream read:[data mutableBytes] maxLength:blockSize];
        if (bytesRead < 0) {
            // Throw an error
        }
        else if (bytesRead == 0) {
            [decryptor finish];

            [decryptedStream close];
        }
        else {
            [data setLength:bytesRead];
            [decryptor addData:data];
        }
    };

    decryptor = [[RNDecryptor alloc] initWithPassword:@"blah"
                                          handler:^(RNCryptor *cryptor, NSData *data)     {
                                                  [decryptedStream write:data.bytes maxLength:data.length];
                                                  if (cryptor.isFinished) {

                                                  }
                                                  else {
                                                      readStreamBlock();
                                                  }
                                              }];
    readStreamBlock();    
}

再次非常类似于git页面。

但是,当我加密和解密同一个文件时,我的尾部是60字节。在我开始熟练地支持可恢复下载之前,这不是一个大问题。然后丢失的字节很重要,因为它们出现在文件的中心。

我已经检查了进出的内容,如下所示

  • 将字节发送到加密器19,615,005(文件大小)
  • 加密器19,615,026
  • 创建的加密字节
  • 解密收到的字节数或19,615,026
  • 来自解密器19,614,944的解密字节

我试过了

  1. 在RNCryptor.h中更改.options = kCCOptionPKCS7Padding
  2. 尝试填充块大小和自己的16字节边界
  3. 更改了加密器完成和readStreamBlock调用,以确保它不是时间问题
  4. 调查了RNCryptorEngine中的finishWithError,但没有错误
  5. 填充到块大小的工作,然后我可以清理我填充的零,但它不理想。

    我在挠头。以前有人经历过这个循环吗?

    更新

    花了很长时间挠头,意识到我没有能力及时发现问题。然而,我倒退到简单的解决方案,这是有效的,但不适合我,因为这给了我内存问题。

    - (void) simpleEncrypt:(NSString*)filename
    {
        NSLogDebug(@"simpleEncrypt");
    
        NSString *outputTmpFilePath = [downloadCacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mov", filename]];
    
        NSData *data = [downloadFileStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
        NSError *error;
        NSData *encryptedData = [RNEncryptor encryptData:data
                                        withSettings:kRNCryptorAES256Settings
                                            password:@"blah"
                                               error:&error];
    
        [encryptedData writeToFile:outputTmpFilePath options:NSDataWritingAtomic error:&error];
    
        NSLogDebug(@"simpleEncrypt isFinished");
    }
    
    - (void) simpleDecrypt:(NSString*)filename
    {
        NSLogDebug(@"simpleDecrypt");
    
        NSString *inputTmpFilePath = [downloadCacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mov", filename]];
        NSString *outputTmpFilePath = [downloadCacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"decrypted%@.mov", filename]];
    
        NSData *encryptedData = [[NSFileManager defaultManager] contentsAtPath:inputTmpFilePath];
    
        NSError *error;
        NSData *decryptedData = [RNDecryptor decryptData:encryptedData
                                        withPassword:@"blah"
                                               error:&error];
    
        [decryptedData writeToFile:outputTmpFilePath options:NSDataWritingAtomic error:&error];
    
        NSLogDebug(@"simpleDecrypt isFinished");
    }
    

    如果我将它与之前的解决方案混合,我会遇到同样的问题。

1 个答案:

答案 0 :(得分:1)

您将流移动了,这可能是问题所在。在链接的示例中,在readStreamBlock中,有以下代码:

else if (bytesRead == 0) {
 [decryptor finish];
}

然后在解密处理程序中,有这样的代码:

                                        if (cryptor.isFinished) {
                                          [decryptedStream close];
                                          // call my delegate that I'm finished with decrypting
                                        }

您将结束移至readStreamBlock

    else if (bytesRead == 0) {
        [decryptor finish];

        [decryptedStream close];
    }

这意味着在异步解密完成之前关闭流。