Objective-c中的AES256解密问题

时间:2012-03-20 20:27:06

标签: objective-c

我正在尝试使用以下代码段来解密使用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

1 个答案:

答案 0 :(得分:5)

此代码存在严重的安全问题。它错误地构造了AES密钥,大大减少了密钥空间并且没有IV,从而为第一个块创建了问题。我强烈建议不要使用此代码。

我通过开发这个常用代码片段的替代品,大部分时间都是如此。见https://github.com/rnapier/RNCryptor。如果它对您不起作用,请告诉我。我试图让它足够容易用于人们将停止使用AES256EncryptWithKey的所有常见情况。

有关此代码问题的详细讨论,请参阅Properly encrypting with AES with CommonCrypto。我喜欢有人将AES加密包装成一个易于使用的类别。我只是希望它没有那么多安全问题。


编辑:回到实际问题,您是否使用AES256EncryptWithKey来加密此数据?如果没有,则具体格式可能完全不同。几乎每个AES加密实现都使用不同的方法来生成其输入参数,然后生成其输出(大多数都不能很好地记录这一点)。您必须匹配参数和格式。例如,您无法使用AES256EncryptWithKey来解密使用openssl enc生成的内容。