2011-11-27 48 views
13

私のアプリは、 256ビット暗号化を使用してNSString(暗号化/復号化するテキスト)を別のNSString(キーワード)で暗号化および復号化する必要があります。私のプロジェクトを実行し、暗号化メソッドを実行すると、何も暗号化されず、テキストフィールドが消えてしまいます。ここで私が持っているコードは次のとおりです。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

私はどんな結果を得るために、私の文字列のベース-64エンコーディングを使用する必要があると言われています。これが正しければ、どうすればいいですか?

私はまた、暗号化がiOS 5で変更され、私のアプリがiOS 5+のみのアプリだと言われました。これが本当であれば、この暗号化をiOS 5で行うためには何が必要か、NSStringで動作する別のAES 256ビット実装をどこから見つけることができますか?

なぜこのコードで結果が得られないのですか?

答えて

11

編集:以下のリンクは、古い実装を示しています。最新のバージョンはRNCryptorです。

あなたのコードでは、iOSの組み込みAES実装は使用されていません。独自のカスタム実装を備えています。 AESEncryptWithPassphrase:も、鍵を誤って生成し、パスフレーズのほとんどのエントロピーを捨てます。

iOSでは、AESにCCCrypt*()関数を使用する必要があります。また、暗号化および復号化ルーチンで何が起きているのかを理解しておく必要があります。 (検査によって出力を読むことができないという点で)正しいように見える暗号化コードを書くのは非常に簡単ですが、非常に安全です。

上記の実装に関する問題の説明と、iOSでAESを正しく使用する方法については、Properly encrypting with AES with CommonCryptoを参照してください。 iOS 5にはCCKeyDerivationPBKDFが追加されました。

暗号化の前に文字列をBase-64でエンコードする必要はありません。 Base-64エンコーディングは、バイナリデータを電子メールや制御文字が問題になる場所で簡単に送信できる形式に変換する必要がある場合に使用します。 8ビットのバイナリデータを7ビットのASCIIデータに変換します。それはここでは必要ないし有用ではない。


EDIT:それはあなたが慎重にこのコードを使用する方法の説明を読むことが重要です。単にセキュリティコードをカット&ペーストしてうまくいかないと危険です。つまり、RNCryptManagerへのフルソースは、iOS 5 Programming Pushing the Limitsの第11章のサンプルコードの一部として利用可能であり、参考になる可能性があります。[編集:これは古いコードです。回答の先頭にリンクされているRNCryptorを今すぐお勧めします]。このコードは、パフォーマンスを向上させ、非常に大きなデータセットを処理する方法を含めて、このコードの使用方法に関するより長い議論を含んでいます。

+0

ありがとうございました!それは非常に便利です! –

+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)で、cryptorがキーとして32 '\ 0'を使用する場合、 "getCString:maxlength:encoding"は何もしないので、キーの長さを確認する必要があります。それは危険です。 – MasterBeta