Шифрование AES-256 на iOS не дает такого же результата, как openssl

Я смотрел и смотрел на это в течение нескольких часов. Я отчаянно пытаюсь заставить iOS зашифровать короткий фрагмент текста с помощью шифрования AES-256, который затем может быть расшифрован с помощью openssl.

Простой? Неа.

Код, который я нашел для iOS, несовместим с ключами и IV для openssl, поэтому мне пришлось его адаптировать, но он явно не работает.

Итак, вот код для шифрования, который я использую... передача строки для шифрования (dataString) строкового ключа (key) и вектора инициализации строки (iv)...

- (NSData *)AES256Encrypt:(NSString *)dataString WithKey:(NSString *)key iv:(NSString *)iv {

    // '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];

    //NSLog(@"keyPtr: '%s'", keyPtr);

    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"keyPtr: '%s'", keyData.bytes);
    NSData *dataToEncrypt = [dataString dataUsingEncoding:NSUTF8StringEncoding];
    NSData *ivData = [iv dataUsingEncoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [dataToEncrypt 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,
                                          keyData.bytes, kCCKeySizeAES256,
                                          ivData.bytes, // initialisation vector
                                          dataToEncrypt.bytes, 
                                          dataToEncrypt.length, /* 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;
}

Для той же строки для кодирования это не дает того же значения, что и при использовании openssl с тем же ключом и iv... например. эта командная строка:

openssl enc -aes-256-cbc -e -in secrets.txt -a -iv 0000 -K 0000 -p

secrets.txt — это просто текстовый файл, содержащий строку, которую нужно зашифровать.

Это выводит что-то вроде этого:

salt=3C66000000000000
key=0000000000000000000000000000000000000000000000000000000000000000
iv =00000000000000000000000000000000
qTMfgtAxbF8Yyh27ZDrcIQ==

А для расшифровки выполните обратную операцию (при условии, что зашифрованная последняя строка данных выше находится в test.secrets.out)

openssl enc -aes-256-cbc -d -in test.secrets.out -a -iv 0000 -K 0000 -p 
salt=3C66000000000000
key=0000000000000000000000000000000000000000000000000000000000000000
iv =00000000000000000000000000000000
< text of the secrets.txt file >

Теперь, если я использую ключ и iv из 4 символов, это неправильно кодируется в iOS. Если я использую ключ полной длины и iv, это также не будет правильно кодироваться.

По сути, это проверка, чтобы убедиться, что если я отправлю часть зашифрованных данных, это будет правильная часть данных.

Что мне не хватает?

Некоторый код, который я просмотрел, чтобы попытаться найти ответ...

http://robnapier.net/blog/aes-commoncrypto-564

https://github.com/rnapier/RNCryptor

http://pastie.org/426530

Здесь тоже много искал и не нашел ответа.

Любая помощь приветствуется.


person padajo    schedule 05.06.2012    source источник
comment
Посмотрите, сможете ли вы заставить IOS расшифровать то, что она зашифровала.   -  person Hot Licks    schedule 05.06.2012
comment
Согласитесь с Hot Licks, однако, если он пытается зашифровать локально, используя ускоренные подпрограммы iOS для подключения через SSL к чему-то еще, то..... Я заметил, что SSL использует режим CBC AES. Вы уверены, что настроили iOS в режиме CBC. AES обрабатывает блоки 128-битными фрагментами, возможно, стоит провести исследование, чтобы выяснить, интерпретирует ли iOS входные данные с прямым порядком байтов или с большим. Это касается и ключа, и IV.   -  person trumpetlicks    schedule 05.06.2012
comment
Еще одно замечание: вам также может понадобиться посмотреть, как данные дополняются для последнего 128-битного блока (если данные НЕ выровнены по 128-битной границе).   -  person trumpetlicks    schedule 05.06.2012
comment
Hot Licks: Да, проверил, расшифровывает то, что я шифрую. Похоже, это не проблема... хотя расшифровка данных здесь не требуется.   -  person padajo    schedule 06.06.2012
comment
trumpetlicks: просмотрел padding и little/big endian... хотя я не уверен, что знаю достаточно о том, как подробно посмотреть на этот фрагмент. Код предназначен исключительно для предоставления зашифрованного пакета вместе с операцией HTTP POST с общим закрытым ключом. Таким образом, другой конец может проверить, были ли данные подделаны или нет. Так что нет необходимости в расшифровке или что-то в этом роде.   -  person padajo    schedule 06.06.2012
comment
API удалил шифрование AES, поскольку просто неясно, какой ключ он использует для шифрования, поэтому мы не можем гарантировать, что дешифрование или шифрование где-либо еще будет таким же. вздох   -  person padajo    schedule 14.06.2012


Ответы (1)


В OpenSSL есть уникальный (читай «не близкий ни к одному стандарту, а также не особо безопасный») метод преобразования паролей в IV и ключ. Если вы посмотрите на RNOpenSSLCryptor, вы увидите используемый алгоритм :

// For aes-128:
//
// key = MD5(password + salt)
// IV = MD5(Key + password + salt)

//
// For aes-256:
//
// Hash0 = ''
// Hash1 = MD5(Hash0 + Password + Salt)
// Hash2 = MD5(Hash1 + Password + Salt)
// Hash3 = MD5(Hash2 + Password + Salt)
// Hash4 = MD5(Hash3 + Password + Salt)
//
// Key = Hash1 + Hash2
// IV = Hash3 + Hash4
//

// File Format:
//
// |Salted___|<salt>|<ciphertext>|
//

Использование RNOpenSSLCryptor позволяет RNCryptor поддерживать формат OpenSSL. В настоящее время я переделываю этот код в ветке async для поддержки асинхронных операций, и эта ветвь еще не поддерживает OpenSSL, но я планирую переработать ее в ближайшее время (к середине июля 2012 г.).

Если вам нужен код, который реализует это для вашего собственного использования, посмотрите на keyForPassword:salt: и IVForKey:password:salt:.

Обратите внимание, что формат файла OpenSSL имеет несколько проблем с безопасностью, и я не рекомендую его, если вы можете этого избежать. Он не использует очень хороший KDF для генерации своего ключа, не имеет столь случайного IV, как должен, и не предоставляет HMAC для аутентификации. Именно из-за этих проблем с безопасностью я разработал другой формат файла, как бы мне не нравилось создавать «еще один несовместимый контейнер».

person Rob Napier    schedule 22.06.2012