2011-11-27 10 views
13

Mã hóa và giải mã ứng dụng của tôi (hoặc phải là) một NSString (văn bản được mã hóa/giải mã) với một NSString khác (từ khóa) sử dụng Mã hóa 2562 Bit256-Bit. Khi tôi chạy dự án của mình và chạy phương thức mã hóa, không có gì được mã hóa vào trường văn bản chỉ cần xóa chính nó. Dưới đây là đoạn code tôi có:Mã hóa NSString AES256 trong iOS

-(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); 
} 

Các tập tin tiêu đề có thể được tải về bằng cách nhấn vào liên kết này: ZIP File containing AES Implementation

Tôi đã nói rằng tôi cần phải sử dụng Base-64 mã hóa chuỗi của tôi để có được bất kỳ kết quả . Nếu điều này là đúng, thì làm thế nào để làm điều đó?

Tôi cũng được thông báo rằng mã hóa đã thay đổi trong iOS 5 và ứng dụng của tôi là ứng dụng CHỈ dành cho iOS 5+. Nếu điều này là đúng, thì tôi phải làm gì để làm cho mã hóa này hoạt động trên iOS 5 hoặc nơi tôi có thể tìm thấy một triển khai AES 256-bit khác sẽ hoạt động trên NSString.

Tại sao mã này không tạo ra kết quả?

Trả lời

11

CHỈNH SỬA: Các liên kết bên dưới tham chiếu đến triển khai cũ hơn. Phiên bản mới nhất được gọi là RNCryptor.

Mã của bạn không sử dụng cài đặt AES được tích hợp sẵn của iOS. Nó có triển khai tùy chỉnh riêng. AESEncryptWithPassphrase: cũng tạo khóa không chính xác, loại bỏ hầu hết entropy trong cụm mật khẩu.

Trên iOS, bạn nên sử dụng các chức năng CCCrypt*() cho AES. Bạn cũng nên chắc chắn rằng bạn hiểu những gì đang xảy ra trong các thói quen mã hóa và giải mã của bạn. Nó rất dễ dàng để viết mã mã hóa có vẻ chính xác (trong đó bạn không thể đọc đầu ra bằng cách kiểm tra), nhưng là cực kỳ không an toàn.

Xem Properly encrypting with AES with CommonCrypto để được giải thích về các vấn đề với việc triển khai ở trên và cách sử dụng AES đúng cách trên iOS. Lưu ý rằng iOS 5 hiện có sẵn CCKeyDerivationPBKDF.

Không yêu cầu Base-64 mã hóa chuỗi của bạn trước khi mã hóa. Mã hóa Base-64 được sử dụng trong trường hợp bạn cần chuyển đổi dữ liệu nhị phân thành một biểu mẫu có thể dễ dàng được gửi qua email hoặc các nơi khác, nơi các ký tự điều khiển sẽ là một vấn đề. Nó chuyển đổi dữ liệu nhị phân 8 bit trong dữ liệu ASCII 7 bit. Điều đó không cần thiết hoặc hữu ích ở đây.


EDIT: Điều quan trọng là bạn đọc kỹ những lời giải thích về cách sử dụng mã này. Thật nguy hiểm khi chỉ cần cắt và dán mã bảo mật và hy vọng nó hoạt động. Điều đó nói rằng, nguồn đầy đủ để RNCryptManager có sẵn như là một phần của mã ví dụ Chương 11 cho iOS 5 Programming Pushing the Limits và có thể hữu ích [EDIT: Đây là mã cũ; Tôi khuyên bạn nên sử dụng RNCryptor ngay bây giờ, được liên kết ở đầu câu trả lời]. Cuốn sách (sẽ có sẵn vào tuần tới bất chấp những gì trang web nói) bao gồm một cuộc thảo luận dài hơn về cách sử dụng mã này, bao gồm cách cải thiện hiệu suất và xử lý các tập dữ liệu rất lớn.

+0

Cảm ơn Rob! Điều đó rất hữu ích! –

+0

Mã sẽ hiển thị ở đâu: http://robnapier.net/blog/aes-commoncrypto-564? Nó sẽ không đi trong lớp riêng của nó bởi vì không có gì để đi vào không có gì một tiêu đề và thực hiện, do đó, nó sẽ đi vào cùng một tập tin mm mà phương pháp của tôi là trong? –

+0

Tôi thường đặt nó trong một lớp được gọi là 'RNCryptManager', nhưng bạn có thể đặt nó ở bất cứ đâu. Mã này cũng có thể được chuyển đổi một cách trivially thành các hàm thay vì các phương thức lớp. –

6

NSData với danh mục tốt cho mã hóa AES, tôi không kiểm tra tệp nén nhưng điều này sẽ phù hợp với bạn;

#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 

Sử dụng các hàm bao bọc như;

- (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

Lưu ý rằng việc triển khai này rất không an toàn vì nó sẽ loại bỏ hầu hết không gian phím, không có IV và không có muối hoặc khóa kéo dài. Xem http://robnapier.net/blog/aes-commoncrypto-564 để thảo luận về lý do tại sao tránh đoạn mã được sao chép thường xuyên này. –

+0

@tylerdurden Bạn nên kiểm tra độ dài của khóa, bởi vì "getCString: maxlength: encoding" sẽ không làm gì nếu key.length> (kCCKeySizeAES256 + 1) và mật mã sẽ sử dụng 32 '\ 0' làm khóa của nó. Nó nguy hiểm. – MasterBeta