1

NSDataiOS の Common Crypto を使用してオブジェクトを暗号化および復号化するコードを作成しました。暗号化キーは AES128 で、iOS キーチェーンに保存されます。データを正常に暗号化および復号化できるので、コードの一部が機能していることがわかります。ただし、サニティ チェックとして、2 つ目のAES128 キーも生成し、最初の暗号化キーで暗号化されたデータの復号化を試みました。CCCryptorStatus値が 以外であると予想していましたkCCSuccessが、そうではありませんでした。オブジェクトを受け取りましたが、NSDataエラーはありませんでした。私の暗号化/復号化コードは次のようになります...

-(NSData *)dataDecryptedUsingAlgorithm:(CCAlgorithm)algorithm
                                  data:(NSData *)data
                                   key:(id)key
                  initializationVector:(id)iv
                               options:(CCOptions)options
                                 error:(CCCryptorStatus *)error {
    CCCryptorRef cryptor = NULL;
    CCCryptorStatus status = kCCSuccess;

    NSParameterAssert([key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]);
    NSParameterAssert(iv == nil || [iv isKindOfClass: [NSData class]] || [iv isKindOfClass: [NSString class]]);

    NSMutableData * keyData, * ivData;
    if ( [key isKindOfClass: [NSData class]] )
        keyData = (NSMutableData *) [key mutableCopy];
    else
        keyData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];

    if ( [iv isKindOfClass: [NSString class]] )
        ivData = [[iv dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
    else
        ivData = (NSMutableData *) [iv mutableCopy];    // data or nil

    //    [keyData autorelease];
    //    [ivData autorelease];

    // ensure correct lengths for key and iv data, based on algorithms
    FixKeyLengths( algorithm, keyData, ivData );

    status = CCCryptorCreate( kCCDecrypt, algorithm, options,
                             [keyData bytes], [keyData length], [ivData bytes],
                             &cryptor );

    if ( status != kCCSuccess )
    {
        if ( error != NULL )
            *error = status;
        return ( nil );
    }

    NSData *result = [self runCryptor:cryptor onData:data result:&status];
    if ( (result == nil) && (error != NULL) )
        *error = status;

    CCCryptorRelease(cryptor);

    return ( result );
}

-(NSData *)dataEncryptedUsingAlgorithm:(CCAlgorithm) algorithm
                                  data:(NSData *)data
                                   key:(id)key
                  initializationVector:(id)iv
                               options:(CCOptions)options
                                 error:(CCCryptorStatus *)error {
    CCCryptorRef cryptor = NULL;
    CCCryptorStatus status = kCCSuccess;

    NSParameterAssert([key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]);
    NSParameterAssert(iv == nil || [iv isKindOfClass: [NSData class]] || [iv isKindOfClass: [NSString class]]);

    NSMutableData * keyData, * ivData;
    if ( [key isKindOfClass: [NSData class]] )
        keyData = (NSMutableData *) [key mutableCopy];
    else
        keyData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];

    if ( [iv isKindOfClass: [NSString class]] )
        ivData = [[iv dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
    else
        ivData = (NSMutableData *) [iv mutableCopy];    // data or nil

    //    [keyData autorelease];
    //    [ivData autorelease];

    // ensure correct lengths for key and iv data, based on algorithms
    FixKeyLengths( algorithm, keyData, ivData );

    status = CCCryptorCreate( kCCEncrypt, algorithm, options,
                             [keyData bytes], [keyData length], [ivData bytes],
                             &cryptor );

    if ( status != kCCSuccess )
    {
        if ( error != NULL )
            *error = status;
        return ( nil );
    }

    NSData *result = [self runCryptor:cryptor onData:data result:&status];
    if ( (result == nil) && (error != NULL) )
        *error = status;

    CCCryptorRelease( cryptor );

    return ( result );
}

-(NSData *)runCryptor:(CCCryptorRef)cryptor onData:(NSData *)data result:(CCCryptorStatus *)status {
    size_t bufsize = CCCryptorGetOutputLength( cryptor, (size_t)[data length], true );
    void * buf = malloc( bufsize );
    size_t bufused = 0;
    size_t bytesTotal = 0;
    *status = CCCryptorUpdate( cryptor, [data bytes], (size_t)[data length],
                              buf, bufsize, &bufused );
    if ( *status != kCCSuccess )
    {
        free( buf );
        return ( nil );
    }

    bytesTotal += bufused;

    // From Brent Royal-Gordon (Twitter: architechies):
    //  Need to update buf ptr past used bytes when calling CCCryptorFinal()
    *status = CCCryptorFinal( cryptor, buf + bufused, bufsize - bufused, &bufused );
    if ( *status != kCCSuccess )
    {
        free( buf );
        return ( nil );
    }

    bytesTotal += bufused;

    return ( [NSData dataWithBytesNoCopy: buf length: bytesTotal] );
}

暗号化メソッドと復号化メソッドを呼び出すとkCCAlgorithmAES128、アルゴリズムとkCCOptionPKCS7Paddingオプションとして渡されます。適切なエラーを返すことができるように、復号化に不正なキーが使用された場合にキャッチする方法はありますか?

4

3 に答える 3

2

不正なキーと破損したデータを区別する唯一の信頼できる方法は、Zaph が指摘するように、ある種のクリブ (つまり、用語の最も広い意味で使用されます。つまり、暗号化について知っているもの) です。これに対するアプローチに興味がある場合は、RNCryptor v4 仕様を参照してください。これはまだ実装されていません。これは単なる仕様ですが、パスワードが正しいかどうかを判断するために使用できるバリデータ フィールドが含まれています。これは、初期のキーイング マテリアルの一部を検証トークンに変換する HKDF-Expand ステップを使用します。


注意として、あなたの方法のこの部分は非常に重要です:

if ( [iv isKindOfClass: [NSString class]] )
    ivData = [[iv dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
 else
    ivData = (NSMutableData *) [iv mutableCopy];    // data or nil

文字列が渡された場合、キースペースは予想よりも大幅に小さくなります。完全にランダムな 16 バイトの文字列であっても、正規の UTF8 文字列は、同等の 16 バイトのランダム データよりもはるかに小さいスペースを表します。

于 2014-09-03T21:55:40.583 に答える
1

いいえ、GCM や EAX モードの操作など、認証を追加する暗号モードを使用しない限り、できません。そうしないと、復号化後にパディングが正しい可能性があるため、復号化が成功を返す可能性が常にあります。つまり、 を使用して、CCCryptorStatus正しくないキーや破損した暗号文を (確実に) 検出することはできません。Zaph がApple フォーラムでの議論を指摘して指摘したように、Oracle 攻撃のパディングの可能性があるため、新しいバージョンの iOS (6 および 7) にCCCryptorStatusは が設定されない可能性があります。kCCDecodeError

認証を追加する暗号を使用する代わりに、暗号文に対して HMAC 値を計算するなどして、独自の認証タグを追加することもできます。HMAC に 2 番目のキーを使用し、認証済みデータに IV を含めることをお勧めします。プレーンテキストを使用する前、または最後のブロックを復号化する前に、認証タグを確認する必要があることに注意してください(CBC モード暗号化の場合)。そうしないと、パディング オラクル攻撃に対して脆弱になります。

不正なキーと暗号文の破損を完全に区別することはできないことに注意してください。

于 2014-09-03T21:47:00.163 に答える
0

基本的に、メッセージが正しく復号化されているか正しく復号化されているかを知る方法はありません。AES (およびほとんどの暗号化) に関する限り、それは単なるビット インとビット アウトです。これが特徴です。

エラーCCCryptorStatusは総エラーのみを処理します。これは、不正なパディングに対して kCCDecodeError を設定しません。これは、Apple Developer Forums で詳細に議論されています。

復号化が正しいかどうかを判断することは、第二次世界大戦の復号化に関する主要な問題でした。基本的に、復号化をテストするために知られているメッセージの一部である「Crib」が必要でした。ウィキペディアから: 「ベビーベッド」という用語は、第二次世界大戦中の英国の解読作業であるブレッチリー パークで生まれました。

必要に応じて、通信に使用しているプロトコルにそれを追加する必要があります。

于 2014-09-03T21:47:52.150 に答える