我有一個使用AES加密的文件。 我用下面的NSData類別:在多線程環境中使用CCCrypt的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
的descrypt過程似乎正常工作當我加載從文件系統的整個文件用下面的代碼:
[NSData dataWithContentsOfFile:dataPath];
文件的時候就沒有出現該問題使用前面的調用進行讀取,但是當外部代碼將文件分塊並初始化一個只有一小塊數據的NSData並嘗試解密時,特別是當不同線程使用此代碼時會出現問題(或者至少是我認爲的):
- (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;
}
}
會發生什麼情況是函數CCCrypt在這種情況下失敗,錯誤代碼爲-4304 AKA「kCCDecodeError - 輸入數據沒有正確解碼或解密。」
此外,如果在CCCrypt調用,而不是kCCOptionPKCS7Padding,我傳遞0 - >沒有填充方法解密第一塊數據,但當線程切換失敗,-4300 AKA「kCCParamError - 非法參數值。
隨着控制檯以下消息:
[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
有人能幫忙嗎?
所以你的建議是有一個CCCryptor的共享引用,並在多個CCCryptorUpdate()調用之間使用它?我一定會試一試,我會讓你知道的! 但kCCOptionPKCS7Padding選項不用於不關心填充? – 2011-05-25 17:41:51
kCCOptionPKCS7Padding表示它應該將PKCS填充應用於您所遞交的內容。你把它交給流的中間。您不能只在流的中間應用填充。 (你還需要跟蹤你的IV,所以你不能只是在流的中間開始解密。) – 2011-05-25 17:45:45
我試圖實現你的建議我,但仍然存在問題:調用我的代碼的類因此需要大量的數據(並且我沒有控制權)有時需要的數據塊不是16個字節的倍數,而通常需要的是2個字節,這會中斷我的解密過程 – 2011-05-30 14:25:17