Objective c 多线程环境中使用CCCrypt的NSData

Objective c 多线程环境中使用CCCrypt的NSData,objective-c,aes,nsdata,Objective C,Aes,Nsdata,我有一个使用AES加密的文件。 我使用以下NSData类别: #import <CommonCrypto/CommonCryptor.h> @implementation NSData (AES) - (NSData *)AES256DecryptWithKey:(NSString *)key { // 'key' should be 32 bytes for AES256, will be null-padded otherwise char keyPtr[k

我有一个使用AES加密的文件。 我使用以下NSData类别:

#import <CommonCrypto/CommonCryptor.h>

@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 */
                                          &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
当文件未通过上一次调用读取时,但当外部代码将文件分块并使用少量数据初始化NSData并尝试对此进行解密时,就会出现问题,特别是当不同线程使用此代码时(或者至少我认为是这样):


有人可以帮忙吗?

AES是一种分组密码。您必须一次解密一个块。AES块为128位(这与AES256DecryptWithKey中的“256”无关)。因此,必须确保传递的数据是16字节的倍数

我没有尝试过这样使用
CCCrypt()
,这不是它真正的用途
CCCrypt()
是一个方便的函数,当您想进行一次性解密时。当您想执行“随用”解密时,您可以使用
CCCryptorCreate()
,然后多次调用
CCCryptorUpdate()
,最后调用
CCCryptorFinal()
(或者您可以调用
CCCryptorFinal()
,然后调用
CCCryptorReset()
,用相同的密钥解密更多内容)。最后,调用
CCCryptorRelease()
来释放加密程序


EDIT我想了很久,意识到即使将输入分成16字节的块,
CCCrypt()
也不能以这种方式使用。AES加密的每个块修改下一个块的IV,所以不能仅仅在流的中间启动某人。这就是为什么在整个会话中需要一个持久的
CCCryptor
对象。

所以您的建议是拥有一个CCCryptor的共享引用,并在多个CCCryptorUpdate()调用之间使用它?我一定会尝试一下,我会让你知道的!但是kCCOptionPKCS7Padding选项并不用于不关心填充?kCCOptionPKCS7Padding表示它应该将PKCS填充应用于您传递给它的内容。你把它放在小溪中间。你不能仅仅在流的中间应用填充。(你也需要跟踪你的IV,所以你不能只是在流中间开始解密。)我试图实现你建议我的,但是仍然存在问题:调用我的代码的类,因此需要数据块(并且我没有控制)。有时需要的数据块不是16字节的倍数,而通常需要的是2字节,这打破了我的解密过程,您可以加密2字节的数据。将使用您请求的填充算法(示例中为PKCS7)将其填充为16字节并加密。生成的crypttext始终是16字节的倍数。如果你有2个字节的加密文本,它不是AES,或者你扔掉了部分数据包。我的问题不在加密过程中,而是在解密过程中。试图读取我的代码的系统要求我提供2byte块,但我无法解密2byte。
[NSData dataWithContentsOfFile:dataPath];
- (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 < 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 < 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 > 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;
    }
}
[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