Зашифруйте и расшифруйте случайную строку NSString с помощью CES AES128 в iOS с заданным ключом

Я не уверен, насколько безопасно мое решение.

Rob Napier имеет необычную платформу ( RNCryptor) для шифрования и дешифрования в iOS и других системах.

Насколько я знаю, он использует AES-CBC, что на самом деле является стандартом CommonCryptor.h

Однако мои требования заставили меня использовать AES-CTR. Оба действительно похожи, поэтому в теории это должно было быть что-то легкое. Но не было.

Недостаточно информации вокруг CommonCryptor.h. Это одна из худших объясненных структур за всю историю.

Работая с CBC, вам просто нужно позвонить CCCrypt(), Однако для работы с CTR вам необходимо позвонить: CCCrytorCreate(), CCCryptorUpdate(), CCCryptorFinal() а также CCCryptorRelease()

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

У меня было две большие проблемы в первом подходе: длина ключа и количество байтов, записанных в dataOut.

Я разобрал проблемы с:

1.- NSString ключ из 32 символов

NSString *key = @"1234567890ABCDEFGHIJKLMNOPQRSTUV";

2.- Чтобы вырезать данные с необходимой длины

Наконец, это мой код для шифрования и дешифрования:

#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonKeyDerivation.h>
#import <Security/Security.h>

+ (NSMutableData*) encryptString: (NSString*) stringToEncrypt withKey: (NSString*) keyString
{
//Key to Data
NSData *key = [keyString dataUsingEncoding:NSUTF8StringEncoding];

//String to encrypt to Data
NSData *data = [stringToEncrypt dataUsingEncoding:NSUTF8StringEncoding];

// Init cryptor
CCCryptorRef cryptor = NULL;

// Alloc Data Out
NSMutableData *cipherData = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];

//Empty IV: initialization vector
NSMutableData *iv =  [NSMutableData dataWithLength:kCCBlockSizeAES128];

//Create Cryptor
CCCryptorStatus  create = CCCryptorCreateWithMode(kCCEncrypt,
                                                  kCCModeCTR,
                                                  kCCAlgorithmAES,
                                                  ccPKCS7Padding,
                                                  iv.bytes, // can be NULL, because null is full of zeros
                                                  key.bytes,
                                                  key.length,
                                                  NULL,
                                                  0,
                                                  0,
                                                  kCCModeOptionCTR_BE,
                                                  &cryptor);

if (create == kCCSuccess)
{
    //alloc number of bytes written to data Out
    size_t outLength;

    //Update Cryptor
    CCCryptorStatus  update = CCCryptorUpdate(cryptor,
                                              data.bytes,
                                              data.length,
                                              cipherData.mutableBytes,
                                              cipherData.length,
                                              &outLength);
    if (update == kCCSuccess)
    {
        //Cut Data Out with nedded length
        cipherData.length = outLength;

        //Final Cryptor
        CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
                                               cipherData.mutableBytes, //void *dataOut,
                                               cipherData.length, // size_t dataOutAvailable,
                                               &outLength); // size_t *dataOutMoved)

        if (final == kCCSuccess)
        {
            //Release Cryptor
            //CCCryptorStatus release =
            CCCryptorRelease(cryptor ); //CCCryptorRef cryptorRef
        }
        return cipherData;

    }



}
else
{
    //error

}

return nil;
}



+ (NSString*) decryptData: (NSData*) data withKey: (NSString*) keyString
{
//Key to Data
NSData *key = [keyString dataUsingEncoding:NSUTF8StringEncoding];

// Init cryptor
CCCryptorRef cryptor = NULL;

//Empty IV: initialization vector
NSMutableData *iv =  [NSMutableData dataWithLength:kCCBlockSizeAES128];

// Create Cryptor
CCCryptorStatus createDecrypt = CCCryptorCreateWithMode(kCCDecrypt, // operation
                                                        kCCModeCTR, // mode CTR
                                                        kCCAlgorithmAES, // Algorithm
                                                        ccPKCS7Padding, // padding
                                                        iv.bytes, // can be NULL, because null is full of zeros
                                                        key.bytes, // key
                                                        key.length, // keylength
                                                        NULL, //const void *tweak
                                                        0, //size_t tweakLength,
                                                        0, //int numRounds,
                                                        kCCModeOptionCTR_BE, //CCModeOptions options,
                                                        &cryptor); //CCCryptorRef *cryptorRef


if (createDecrypt == kCCSuccess)
{
    // Alloc Data Out
    NSMutableData *cipherDataDecrypt = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];

    //alloc number of bytes written to data Out
    size_t outLengthDecrypt;

    //Update Cryptor
    CCCryptorStatus updateDecrypt = CCCryptorUpdate(cryptor,
                                                    data.bytes, //const void *dataIn,
                                                    data.length,  //size_t dataInLength,
                                                    cipherDataDecrypt.mutableBytes, //void *dataOut,
                                                    cipherDataDecrypt.length, // size_t dataOutAvailable,
                                                    &outLengthDecrypt); // size_t *dataOutMoved)

    if (updateDecrypt == kCCSuccess)
    {
        //Cut Data Out with nedded length
        cipherDataDecrypt.length = outLengthDecrypt;

        // Data to String
        NSString* cipherFinalDecrypt = [[NSString alloc] initWithData:cipherDataDecrypt encoding:NSUTF8StringEncoding];

        //Final Cryptor
        CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
                                               cipherDataDecrypt.mutableBytes, //void *dataOut,
                                               cipherDataDecrypt.length, // size_t dataOutAvailable,
                                               &outLengthDecrypt); // size_t *dataOutMoved)

        if (final == kCCSuccess)
        {
            //Release Cryptor
            //CCCryptorStatus release =
            CCCryptorRelease(cryptor); //CCCryptorRef cryptorRef
        }

        return cipherFinalDecrypt;
    }
}
    else
{
    //error

}

return nil;
}

Чтобы назвать это:

NSString *key = @"1234567890ABCDEFGHIJKLMNOPQRSTUV";
NSString *stringToEncrypt = @"Gabriel.Massana";

NSData* encrypted = [GM_AES128_CTR encryptString:stringToEncrypt withKey:key];

NSString *decrypted = [GM_AES128_CTR decryptData:encrypted withKey:key];

Я публикую свое решение, потому что для AES CTR не так много вопросов в Stackru. Кроме того, если кто-то хочет проверить это и сказать мне, если что-то не так, будет очень признателен.

Мой пример в GitHub

Насколько безопасно это решение? Легко взломать систему? Каковы мои возможности для повышения безопасности AES-CTR?

1 ответ

Решение

Я перечисляю это как отдельный ответ, но я только усиливаю то, что уже сказал Заф:

Это полностью сломанное шифрование.

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

CTR никогда не может повторять один и тот же ключ nonce+, и вы каждый раз повторно используете nonce. Это очень отличается от CBC. В CBC, если вы повторно используете IV, то злоумышленнику будет несколько проще взломать ваше шифрование. В CTR, если вы повторно используете ключ nonce+, довольно легко расшифровать сообщение, если у вас есть несколько зашифрованных текстов. Некоторое хорошее обсуждение можно найти в RFC3686.

При правильном использовании AES-CTR обеспечивает высокий уровень конфиденциальности. К сожалению, AES-CTR легко использовать неправильно. Будучи потоковым шифром, любое повторное использование значения для пакета, называемого IV, с тем же одноразовым номером и ключом является катастрофическим. Столкновение IV немедленно пропускает информацию о незашифрованном тексте в обоих пакетах. По этой причине нецелесообразно использовать этот режим работы со статическими ключами. Необходимы чрезвычайные меры для предотвращения повторного использования значения IV со статическим ключом в циклах питания. Для безопасности реализации ДОЛЖНЫ использовать свежие ключи с AES-CTR. Протокол Internet Key Exchange (IKE) [IKE] может использоваться для установки свежих ключей. IKE также может предоставить значение nonce.

Обратите внимание, что RNCryptor изначально использовал CTR. Я вернулся в CBC по рекомендации Apple, после того, как поговорил с ними о том, как тяжело испортить CTR. Если вы можете избежать CTR, вы обязательно должны. Это чрезвычайно полезно для определенных проблем, но для общего шифрования файлов это редко подходит.

Тем не менее, я понимаю, у вас есть проблема в чипе. Как ваш чип получит свой ключ? Кажется странным использовать симметричное шифрование с чипом таким способом. В любом случае RNCryptor v1 может удовлетворить ваши потребности. Вы, вероятно, должны использовать encryptFromStream:toStream:encryptionKey:HMACKey:error: так как я предполагаю, что чип не может обрабатывать PBKDF2.

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

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

NSString * key = @ "1234567890ABCDEFGHIJKLMNOPQRSTUV";

Это не ключ. Это пароль, который значительно сокращает доступное пространство ключей. Ключи, как правило, будут NSData поскольку их нужно выбирать среди всех возможных значений, а не только в ASCII.

Другие вопросы по тегам