我正在尝试使用以下代码段来解密使用32字节密钥加密的文件。因此,当我尝试加密文件数据时,一切正常。但是当我尝试解密时,程序甚至不会在CryptoExtensions.m中传递条件if (cryptStatus == kCCSuccess)
。我真的很累,想出一个问题。我试图使用Base64解码,但我的文件以UTF8编码保存,所以当我把它的内容放在NSData的日志中时我没有问题:
NSData *fileData = [[[NSData alloc] initWithContentsOfFile:destPath] autorelease];
NSLog(@"File data:%@",[[NSString alloc] initWithData:fileData encoding:NSUTF8StringEncoding]);
但是当我尝试解密时,我从 CryptoExtensions 方法获取nil
:
NSData *aesResponse = [fileData AES256DecryptWithKey:@"4QXcCZlgRAIchiaqkMVpF3nkpARmdL3z"];
NSLog(@"AES:%@",[[NSString alloc] initWithData:aesResponse encoding:NSUTF8StringEncoding]);
这是crypto代码段的内容:
CryptoExtensions.h
#import <Foundation/Foundation.h>
@interface NSData (CryptoExtensions)
- (NSData*)AES256EncryptWithKey:(NSString*)key;
- (NSData*)AES256DecryptWithKey:(NSString*)key;
@end
CryptoExtensions.m
#import "CryptoExtensions.h"
#import <CommonCrypto/CommonCryptor.h>
@implementation NSData (CryptoExtensions)
- (NSData*)AES256EncryptWithKey:(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 numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess)
{
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
- (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);
if (cryptStatus == kCCSuccess)
{
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;
}
@end
答案 0 :(得分:5)
此代码存在严重的安全问题。它错误地构造了AES密钥,大大减少了密钥空间并且没有IV,从而为第一个块创建了问题。我强烈建议不要使用此代码。
我通过开发这个常用代码片段的替代品,大部分时间都是如此。见https://github.com/rnapier/RNCryptor。如果它对您不起作用,请告诉我。我试图让它足够容易用于人们将停止使用AES256EncryptWithKey
的所有常见情况。
有关此代码问题的详细讨论,请参阅Properly encrypting with AES with CommonCrypto。我喜欢有人将AES加密包装成一个易于使用的类别。我只是希望它没有那么多安全问题。
编辑:回到实际问题,您是否使用AES256EncryptWithKey
来加密此数据?如果没有,则具体格式可能完全不同。几乎每个AES加密实现都使用不同的方法来生成其输入参数,然后生成其输出(大多数都不能很好地记录这一点)。您必须匹配参数和格式。例如,您无法使用AES256EncryptWithKey
来解密使用openssl enc
生成的内容。