2011-11-27 174 views
13

我的应用程序使用 256位加密,使用另一个NSString(关键字)加密和解密(或应该)NSString(要加密/解密的文本)。当我运行我的项目并运行加密方法时,没有任何东西被加密,文本字段只是自行清除。下面是我的代码有:AES256 iOS中的NSString加密

-(void)EncryptText { 
    //Declare Keyword and Text 
    NSString *plainText = DataBox.text; 
    NSString *keyword = Keyword.text; 

    //Convert NSString to NSData 
    NSData *plainData = [plainText dataUsingEncoding:NSUTF8StringEncoding]; 

    //Encrypt the Data 
    NSData *encryptedData = [plainData AESEncryptWithPassphrase:keyword]; 

    //Convert the NSData back to NSString 
    NSString* cypherText = [[NSString alloc] initWithData:encryptedData encoding:NSUTF8StringEncoding]; 

    //Place the encrypted sting inside the Data Box 
    NSLog(@"Cipher Text: %@", cypherText); 
} 

头文件可以通过点击此链接下载:ZIP File containing AES Implementation

有人告诉我,我需要用我的字符串的BASE-64编码得到任何结果。如果这是真的,那我该怎么做呢?

我也被告知,在iOS 5中改变了加密和我的应用程序是一款iOS 5+唯一的应用程序。如果这是真的,那么我需要做些什么才能使这种加密在iOS 5上工作,或者我可以在哪里找到另一个可以在NSString上工作的AES 256位实现。

这段代码为什么不产生结果?

回答

11

编辑:下面的链接指的是旧的实现。最新版本被称为RNCryptor

你的代码不使用内置的AES实现iOS版的。它有自己的自定义实现。 AESEncryptWithPassphrase:也错误地生成密钥,丢掉密码中的大部分熵。

在iOS上,你应该使用CCCrypt*()功能AES。您还应该确保您了解加密和解密例程中发生的情况。编写看起来正确的加密代码非常容易(因为您无法通过检查来读取输出),但是非常不安全。

为上述实施,以及如何在iOS正确使用AES问题的说明,请参见Properly encrypting with AES with CommonCrypto。请注意,iOS 5现在有CCKeyDerivationPBKDF可用。

没有要求BASE-64您的字符串加密之前编码。在需要将二进制数据转换为可以通过电子邮件或控制字符成为问题的其他地方轻松发送的表单的情况下,使用Base-64编码。它以7位ASCII数据转换8位二进制数据。这在这里没有必要或有用。


编辑:这是非常重要的,你仔细阅读如何使用此代码的解释。简单地剪切和粘贴安全代码并希望它能正常工作是很危险的。也就是说,RNCryptManager的完整源代码可作为iOS 5 Programming Pushing the Limits的第11章示例代码的一部分,并且可能有帮助[编辑:这是旧代码;我现在推荐RNCryptor,链接在答案的顶部]。这本书(尽管网站上说了什么,应该在下周发布)包含了关于如何使用此代码的更长时间的讨论,包括如何提高性能并处理非常大的数据集。

+0

谢谢你Rob!这非常有帮助! –

+0

代码显示在:http://robnapier.net/blog/aes-commoncrypto-564去哪里?它不会进入它自己的类,因为没有什么东西不会成为头文件和实现,所以它会进入我的方法所在的.m文件中。 –

+0

我通常把它放在一个名为'RNCryptManager'的类中,但是你可以把它放在任何地方。代码也可以简单地转换为函数而不是类方法。 –

6

NSData的类别为就好了AES加密,我没有检查zip文件,但是这应该为你工作;

#import <CommonCrypto/CommonCryptor.h> 
@implementation NSData (AESAdditions) 
- (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 

使用它的包装函数,如;

- (NSData*) encryptString:(NSString*)plaintext withKey:(NSString*)key { 
     return [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key]; 
} 

- (NSString*) decryptData:(NSData*)ciphertext withKey:(NSString*)key { 
     return [[[NSString alloc] initWithData:[ciphertext AES256DecryptWithKey:key] 
             encoding:NSUTF8StringEncoding] autorelease]; 
} 
+1

请注意,此实现是非常不安全的,因为它抛弃了大部分的密钥空间,没有IV,也没有盐或密钥伸缩。请参阅http://robnapier.net/blog/aes-commoncrypto-564了解为什么要避免这种通常复制的代码段的讨论。 –

+0

@tylerdurden您应该检查密钥的长度,因为如果key.length>(kCCKeySizeAES256 + 1)和密码将使用32'\ 0'作为密钥,“getCString:maxlength:encoding”将不会执行任何操作。有危险。 – MasterBeta