2

使用 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,但没有错误

填充到块大小有点工作,因为我可以清理我填充的零,但它并不理想。

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

更新:

花了很长时间摸不着头脑,意识到我没有能力及时找出问题所在。但是,我退回到简单的解决方案,这很有效,但对我来说不是,因为这会给我带来记忆问题。

- (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");
}

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

4

1 回答 1

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];
    }

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

于 2014-03-29T21:44:09.373 回答