【发布时间】:2011-06-29 21:56:47
【问题描述】:
我的目标是能够在获得文件/文件夹和密码的情况下使用 Objective-C 在 AES 中对其进行加密和解密。我不是加密书呆子或任何东西,但我选择了 AES,因为我发现它非常标准且非常安全。我正在使用一个 NSMutableData 类别,它具有加密和解密其数据的方法。这里是:
- (NSInteger)AES256EncryptionWithKey: (NSString*)key {
// The 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
if (![key getCString: keyPtr maxLength: sizeof(keyPtr) encoding: NSUTF8StringEncoding])
{ return 2; } // Length of 'key' is bigger than keyPtr
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 numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL , // initialization vector (optional)
[self bytes], dataLength, // input bytes and it's length
buffer, bufferSize, // output buffer and it's length
&numBytesEncrypted); // ??
if (cryptStatus == kCCSuccess) {
// The returned NSData takes ownership of the buffer and will free it on deallocation
[self setData: [NSData dataWithBytesNoCopy: buffer length: numBytesEncrypted]];
return 0;
}
free(buffer); // Free the buffer;
return 1;
}
- (NSInteger)AES256DecryptionWithKey: (NSString*)key {
// The 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
if (![key getCString: keyPtr maxLength: sizeof(keyPtr) encoding: NSUTF8StringEncoding])
{ return 2; } // Length of 'key' is bigger than keyPtr
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);
if (cryptStatus == kCCSuccess) {
// The returned NSData takes ownership of the buffer and will free it on deallocation
[self setData: [NSData dataWithBytesNoCopy: buffer length: numBytesDecrypted]];
return 0;
}
free(buffer); // Free the buffer;
return 1;
}
这段代码的问题在于它使用了 about !! 5!!内存中用户选择的文件(使用 NSMutableData 打开)大小的倍数。从用户的角度来看,这是完全不能接受的(想象加密内存中 2Gb - 10Gb 的文件??),但我真的很茫然。
您能建议任何可以解决此问题的修改吗?可能一次加密一个块(这样只有一两个块同时在内存中,而不是整个文件 * 5)。最大的问题是我不知道该怎么做。有什么想法吗?
谢谢
PS:当我使用这个类别时,我是这样做的:
NSMutableData* data = [NSMutableData dataWithContentsOfFile: @"filepath"];
[data AES256EncryptionWithKey: @"password"];
[data writeToFile: @"newname" atomically: NO];
仅这 3 行就造成了如此大的内存问题。
哦,顺便说一句:我需要一个初始化向量吗?我认为它更安全,或者什么,但我不知道。如果真的有需要,能告诉我怎么做吗?
编辑
这就是我现在正在做的事情:
NSMutableData* data = [NSMutableData dataWithContentsOfMappedFile: @"filepath"];
[data SafeAES256EncryptionWithKey: @"password"];
[data writeToFile: @"newname" atomically: NO];
以及类别中的新方法:
- (void)SafeAES256EncryptionWithKey: (NSString*)key {
// The 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
if (![key getCString: keyPtr maxLength: sizeof(keyPtr) encoding: NSUTF8StringEncoding])
{ return 2; } // Length of 'key' is bigger than keyPtr
CCCryptorRef cryptor;
CCCryptorStatus cryptStatus = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL, // IV - needed?
&cryptor);
if (cryptStatus != kCCSuccess) {
; // Handle error here
}
NSInteger startByte;
size_t dataOutMoved;
size_t dataInLength = kChunkSizeBytes; // #define kChunkSizeBytes (16)
size_t dataOutLength = CCCryptorGetOutputLength(cryptor, dataInLength, FALSE);
const void* dataIn = malloc(dataInLength);
void* dataOut = malloc(dataOutLength);
for (startByte = 0; startByte <= [self length]; startByte += kChunkSizeBytes) {
if ((startByte + kChunkSizeBytes) > [self length]) { dataInLength = [self length] - startByte; }
else { dataInLength = kChunkSizeBytes; }
NSRange bytesRange = NSMakeRange(startByte, (int)dataInLength);
[self getBytes: dataIn range: bytesRange];
CCCryptorUpdate(cryptor, dataIn, dataInLength, dataOut, dataOutLength, &dataOutMoved);
if (dataOutMoved != dataOutLength) {
NSLog(@"dataOutMoved != dataOutLength");
}
[self replaceBytesInRange: bytesRange withBytes: dataOut];
}
CCCryptorFinal(cryptor, dataOut, dataOutLength, &dataOutMoved);
[self appendBytes: dataOut length: dataOutMoved];
CCCryptorRelease(cryptor);
我不明白为什么这有时有效而有时却无效。我在这里真的很茫然。有人可以检查此代码吗?
为了不一次将所有文件加载到内存中,我使用-dataWithContentsOfMappedFile,然后调用-getBytes:range:,因为我看到here那样它不会将所有文件加载到实际内存中一次,仅指定范围。
编辑 2
请看我的回答,了解我现在在做什么。
【问题讨论】:
-
见:stackoverflow.com/questions/6127318/… 你不应该将整个文件加载到内存中,你应该只对小数据使用
CCCrypt()。 -
@Bavarious 所以,我现在有两个问题。首先,我如何只加载文件的一小部分数据(我无法加载所有文件,但需要一个 16 字节 - 或多个字节 - 文件块)。其次,我如何使用 CCCreate、Update 和 Finish。我记得在那儿看到过一个例子,但我再也找不到了。我真的无法理解您必须赋予这些功能的所有类型。当代码脱离 Objective-C 和 Cocoa 领域时,我会迷路。请帮忙!
-
@Bavarious 我已经用我现在正在做的事情更新了我的问题,但仍然无法正常工作。请检查一下。
-
我今天晚些时候再看看。
-
@Bavarious 我已经用我现在正在做的事情回答了这个问题,这似乎完美无缺。不过我不确定。
标签: objective-c security macos memory-management aes