iPhone — расшифровка сообщения, зашифрованного с помощью AES, с помощью ключа, отличного от того, который использовался для шифрования

Я просто кодирую базовые методы «шифрования» и «дешифрования» для AES на iPhone, используя CCrypt.

Я провел несколько тестов и был действительно поражен, обнаружив, что иногда, если вы пытаетесь расшифровать зашифрованный текст с помощью ключа, отличного от того, который использовался для шифрования обычного текста, CCrypt не возвращает никаких ошибок.

Вот пример:

- (void) testDecryptTextWithTheWrongKey {
    NSData *encryptKey = [Base64 decodeBase64WithString:@"+LtNYThpgIlQs2CaL00R6AuG2C/i6U1Vt1+6wfFeFMk="];
    NSData *decryptKey = [Base64 decodeBase64WithString:@"yg7BvhM8npVGpAFpAESDn3IRWpe6qeQWaa1rwHiTsyU="];

    NSString *plainText = @"The text to be encrypted";
    NSData *plainTextData = [plainText dataUsingEncoding:NSUTF8StringEncoding];

    NSError *error = nil;
    NSData *encrypted = [LocalCrypto encryptText:plainTextData key:encryptKey error:&error];

    assertThat(error, nilValue());
    assertThat(encrypted, notNilValue());

    error = nil;
    NSData *decrypted = [LocalCrypto decryptText:encrypted key:decryptKey error:&error];

    assertThat(error, notNilValue());
    assertThat(decrypted, nilValue());
}

Мои методы шифрования и дешифрования, определенные в LocalCrypto, просто вызывают внутренний метод «executeCryptoOperation», указывающий, что они хотят зашифровать или расшифровать:

+ (NSData *) executeCryptoOperation:(CCOperation)op key:(NSData *) key input:(NSData *) input error:(NSError **)error {
    size_t outLength;
    NSMutableData *output = [NSMutableData dataWithLength:input.length + kCCBlockSizeAES128];

    CCCryptorStatus result = CCCrypt(op,                    // operation
                                     kCCAlgorithmAES128,    // Algorithm
                                     kCCOptionPKCS7Padding | kCCOptionECBMode, // options
                                     key.bytes,             // key
                                     key.length,            // keylength
                                     nil,                   // iv
                                     input.bytes,           // dataIn
                                     input.length,          // dataInLength,
                                     output.mutableBytes,   // dataOut
                                     output.length,         // dataOutAvailable
                                     &outLength);           // dataOutMoved

    if (result == kCCSuccess) {
        output.length = outLength;
    } else {
        *error = [NSError errorWithDomain:kCryptoErrorDomain code:result userInfo:nil];
        return nil;
    }

    return output;
}

Что ж, мой вопрос: нормально ли, что CCrypt возвращает kCCSuccess, когда мы пытаемся расшифровать зашифрованный текст ключом, отличным от того, который использовался во время шифрования? Я что-то упускаю или делаю что-то не так?

Это правда, что даже когда CCrypt возвращает успех для расшифровки, я не могу получить правильную NSString из результирующих данных, но я определенно ожидаю, что CCrypt вернет какую-то ошибку в этой ситуации (как, вероятно, сделал бы Java).

Если это нормальное поведение, как я должен узнать, вернула ли операция дешифрования настоящий простой текст или просто набор байтов, которые не имеют никакого смысла?

Здесь есть аналогичный вопрос, но ответ меня не очень убеждает: Возврат неверного текста расшифровки при использовании недопустимого ключа

Спасибо!


person jsanchez    schedule 13.10.2011    source источник
comment
Ответ в связанном вопросе имеет смысл. Пока ваш ключ соответствует требованиям, он используется для расшифровки зашифрованной строки, и ошибок не возникает. Как и зачем ему знать, как должен выглядеть расшифрованный текст?   -  person jrturton    schedule 13.10.2011
comment
Я вижу вашу точку зрения, и это действительно имеет смысл. Меня смущает то, что если я запускаю один и тот же тест на Java (шифрование с помощью ключа и дешифрование с помощью другого), я получаю исключение во время расшифровки (точнее, BadPaddingException)... любые идеи о том, почему Java обнаруживает, что происходит что-то не так, а iOS нет?   -  person jsanchez    schedule 13.10.2011


Ответы (2)


Существуют алгоритмы шифрования, которые включают заполнение (например, заполнение PKCS#5 в вашей реализации Java), а есть алгоритмы, которые этого не делают.

Если ваш алгоритм шифрования использовал заполнение, соответствующий алгоритм дешифрования ожидает, что в расшифрованном открытом тексте также будет правильно сформированное заполнение. Это служит дешевой частичной проверкой целостности, поскольку с неправильным ключом вывод, скорее всего, не будет иметь правильного заполнения. (Вероятность того, что случайный n-байтовый блок (n=16 для AES) имеет допустимое заполнение PKCS#5, равен 1/256 + 1/(256^2) + ... + 1/(256^n), что лишь немногим больше, чем 1/256.)

Возможно, ваша функция target-C CCCrypt не проверяет правильность заполнения, а только его последний байт (или даже только некоторые биты этого последнего байта), чтобы увидеть, сколько байтов было дополнено (и теперь должно быть отрезано). ).

Если вы хотите убедиться в правильности ключа, зашифруйте некоторую известную часть открытого текста и выдайте ошибку, если ее нет в расшифрованной части. (Но не делайте этого в режиме ECB, см. ниже.)

Если вы также хотите убедиться, что данные не были изменены, также используйте MAC или используйте комбинированный режим аутентификации шифрования для вашего блочного шифра.

Еще одно примечание: не следует использовать режим ECB, вместо этого следует использовать безопасный режим работы (подойдет любой другой режим, указанный в этой статье и поддерживаемый вашей реализацией - стандартом в настоящее время является режим CBC или CTR). Некоторые режимы (такие как CFB, OFB и CTR) вообще не требуют заполнения.

person Paŭlo Ebermann    schedule 13.10.2011

Вы упускаете тот факт, что функция расшифровки понятия не имеет, как должен выглядеть открытый текст (расшифрованные данные).

Что касается функции расшифровки, то она получила от вас ключ и зашифрованный текст, применила процедуру расшифровки к зашифрованному тексту, используя предоставленный вами ключ, и никаких ошибок не возникло. Отсюда и успех.

Ваша работа заключается в том, чтобы убедиться, что открытый текст, который вы получили, был действительно правильным/имеет тот формат, который вы ожидали.

person uvesten    schedule 13.10.2011
comment
Я вижу вашу точку зрения, и это действительно имеет смысл. Меня смущает то, что если я запускаю один и тот же тест на Java (шифрование с помощью ключа и дешифрование с помощью другого), я получаю исключение во время расшифровки (точнее, BadPaddingException)... любые идеи о том, почему Java обнаруживает, что происходит что-то не так, а iOS нет? - person jsanchez; 13.10.2011
comment
Padding имеет очень мало разрешенных форматов. Неправильный ключ вряд ли приведет к правильному заполнению в конце последнего блока. Какое заполнение ожидает ваш метод расшифровки? - person rossum; 13.10.2011
comment
В Java я использую схему заполнения PKCS#5. - person jsanchez; 13.10.2011
comment
Я предполагаю, что это как-то связано с конкретной реализацией в Java. Вы можете обновить свой вопрос, указав точный метод Java, который вы используете, желательно со ссылкой на документацию. - person uvesten; 13.10.2011