2011-11-27 171 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