web-dev-qa-db-ja.com

iPhone上のNSStringのAES暗号化

誰かが文字列を暗号化し、暗号化されたデータで別の文字列を返すことができるように私を正しい方向に向けることができますか? (私はAES256暗号化を試しています。)NSStringインスタンスを2つ取るメソッドを記述したいと思います。1つは暗号化するメッセージで、もう1つはそれを暗号化する「パスコード」です-生成する必要があると思います暗号化されたデータとともにパスコードが提供された場合に元に戻すことができる方法で、パスコード付きの暗号化キー。メソッドは、暗号化されたデータから作成されたNSStringを返す必要があります。

この投稿の最初のコメント で詳細に説明した手法を試しましたが、これまでのところ運がありませんでした。 Appleの CryptoExercise は確かに何かを持っていますが、それを理解することはできません... CCCrypt への多くの参照を見てきましたが、すべてのケースで失敗しましたveはそれを使用しました。

また、暗号化された文字列を復号化できるようにする必要がありますが、それがkCCEncrypt/kCCDecryptと同じくらい簡単であることを願っています。

123
Boz

NSDataとNSStringのカテゴリのコレクションをまとめました。ここでは、Stack OverflowのQuinn Taylorによる Jeff LaMarcheのブログ および いくつかのヒント にあるソリューションを使用しています。

カテゴリを使用してNSDataを拡張してAES256暗号化を提供し、暗号化されたデータを文字列に安全にBASE64エンコードするNSStringの拡張機能も提供します。

文字列の暗号化の使用法を示す例を次に示します。

NSString *plainString = @"This string will be encrypted";
NSString *key = @"YourEncryptionKey"; // should be provided by a user

NSLog( @"Original String: %@", plainString );

NSString *encryptedString = [plainString AES256EncryptWithKey:key];
NSLog( @"Encrypted String: %@", encryptedString );

NSLog( @"Decrypted String: %@", [encryptedString AES256DecryptWithKey:key] );

ここで完全なソースコードを入手してください:

https://Gist.github.com/838614

役に立つヒントをありがとう!

-マイケル

45
Michael Thiel

@owlstead、「与えられた答えの1つの暗号的に安全なバリアント」のリクエストについては、 RNCryptor をご覧ください。それは、あなたが要求していることを正確に行うように設計されました(そして、ここにリストされたコードの問題に対応して構築されました)。

RNCryptorはPBKDF2とソルトを使用し、ランダムIVを提供し、HMAC(独自のソルトを使用してPBKDF2からも生成されます)を接続します。同期および非同期操作をサポートします。

34
Rob Napier

私は@QuinnTaylorで答えを更新するのを少し待っていましたが、彼がそうしなかったので、ここで答えをもう少し明確に、XCode7(そしておそらくそれ以上)にロードする方法で示します。これをCocoaアプリケーションで使用しましたが、iOSアプリケーションでも同様に動作する可能性があります。 ARCエラーはありません。

AppDelegate.mまたはAppDelegate.mmファイルの@implementationセクションの前に貼り付けます。

#import <CommonCrypto/CommonCryptor.h>

@implementation NSData (AES256)

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

希望する@implementationクラスにこれら2つの関数を貼り付けます。私の場合、AppDelegate.mmまたはAppDelegate.mファイルで@implementation AppDelegateを選択しました。

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

- (NSString *) decryptString:(NSString *)ciphertext withKey:(NSString*)key {
    NSData *data = [[NSData alloc] initWithBase64EncodedString:ciphertext options:kNilOptions];
    return [[NSString alloc] initWithData:[data AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding];
}
10
Volomike