web-dev-qa-db-ja.com

iOSでのAES256NSString暗号化

私のアプリは、 aes 256ビット暗号化を使用してNSString(暗号化/復号化するテキスト)を別の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);
}

ヘッダーファイルは、次のリンクをクリックしてダウンロードできます。 AES実装を含むZipファイル

結果を得るには、文字列のBase-64エンコーディングを使用する必要があると言われています。これが本当なら、どうすればいいですか?

また、iOS 5で暗号化が変更されたと言われました。私のアプリはiOS 5以上のアプリです。これが当てはまる場合、iOS 5でこの暗号化を機能させるにはどうすればよいですか、またはNSStringで機能する別のAES256ビット実装をどこで見つけることができますか。

このコードが結果を生成しないのはなぜですか?

14
Sam Spencer

編集:以下のリンクは古い実装を参照しています。最新バージョンは RNCryptorと呼ばれます

コードはiOSの組み込みAES実装を使用しません。独自のカスタム実装があります。 _AESEncryptWithPassphrase:_も誤ってキーを生成し、パスフレーズのエントロピーのほとんどを破棄します。

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

上記の実装の問題の説明、およびiOSでAESを適切に使用する方法については、 CommonCryptoを使用したAESによる適切な暗号化 を参照してください。 iOS5ではCCKeyDerivationPBKDFが利用可能になっていることに注意してください。

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


[〜#〜] edit [〜#〜]:このコードの使用方法の説明を注意深く読むことが重要です。セキュリティコードを単純にカットアンドペーストしてそれが機能することを期待するのは危険です。とはいえ、RNCryptManagerの完全なソースは、第11章のコード例の一部として利用できます iOS 5 Programming Pushing the Limits と役立つかもしれません :これは古いコードです。今すぐRNCryptorをお勧めします。回答の上部にリンクされています]。この本(サイトの内容にかかわらず、来週発売予定)には、このコードの使用方法に関するより長い議論が含まれています。

11
Rob Napier

カテゴリ付きの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];
}
7
Fatih Donmez