Шифровать с помощью openssl и расшифровывать на iPhone с помощью AES 128, режим ecb

Обновление: найдено решение. Я скоро обновлю этот вопрос, указав фактический рабочий код и команду.


Клиент шифрует файл на стороне сервера с помощью C++, и мне нужно расшифровать его в приложении для iPhone.

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

Я хочу вывести некоторые примеры значений, которые мы примем в качестве общей реализации.

Я пытался зашифровать файл с помощью openssl и расшифровать его с помощью какао, но не смог.

Вот что я использую для шифрования:

echo "123456789ABCDEFG" | openssl enc -aes-128-ecb -nosalt -K "41414141414141414141414141414141" -iv 0 > hello.txt.bin

Добавление опции -p к вызову openssl показывает, что используются ожидаемый ключ и iv:

key=41414141414141414141414141414141
iv =00000000000000000000000000000000

И для расшифровки какао (в категории NSData):

- (NSData *)AESDecryptWithKey:(NSString *)key {

    char keyPtr[kCCKeySizeAES128+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;

    char iv[32];
    for (int i = 0; i < 32; i++) {
        iv[i] = 0;
    }

    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionECBMode + kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES128,
                                          iv, //"00000000000000000000000000000000" /* 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;
}

называется так:

- (void)testBinaryFileDecryption {
    NSString *databasePath = [[NSBundle mainBundle] pathForResource:@"hello" ofType:@"txt.bin"];

    NSData *data = [NSData dataWithContentsOfFile:databasePath];
    NSAssert(nil != data, @"Encrypted data, freshly loaded from file should not be nil");

    NSData *plain = [data AESDecryptWithKey:@"AAAAAAAAAAAAAAAA"];
    NSAssert(nil != plain, @"Decrypted plain data should not be nil");

    NSLog(@"Result: '%@'", [[NSString alloc] initWithData:plain encoding:NSASCIIStringEncoding]);
}

Журналы результатов: Result: '4¨µ¢Ä½Pk£N

Какой вариант я забыл? Является ли кодировка NSData возвращенной чем-то другим, кроме NSASCIIStringEncoding ?


person Guillaume    schedule 05.07.2010    source источник
comment
Что случилось с решением, которое вы нашли? Есть ли шанс, что вы его опубликуете?   -  person olivaresF    schedule 14.03.2011


Ответы (2)


Я ничего не знаю о разработке iPhone, но, глядя на этот код, кажется, что вы пытаетесь использовать ascii-of-hex-кодирование фактического ключа для расшифровки пакета. Enc OpenSSL требует шестнадцатеричной кодировки, потому что она преобразует шестнадцатеричные значения в байты. Ваш фактический ключ выглядит примерно так, если преобразовать его непосредственно в ascii.

["\037", " ", "!", "\"", "#", "$", "%", "&", "'", "\036", "\037", " ", "!", "\"", "#", "$"]

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

Попробуйте использовать ключевую спецификацию 41414141414141414141414141414141 для OpenSSL и используйте AAAAAAAAAAAAAAAA в коде своего iPhone.

Кроме того, я настоятельно рекомендую ваши начальные тесты выполнять с данными длиной ровно N*16 байт. OpenSSL enc использует заполнение PKCS#5 (если только вы не используете -nopad), а код вашего iPhone использует заполнение PKCS#7. При беглом взгляде на RFC кажется, что это один и тот же механизм заполнения, но я могу ошибаться.

И я знаю, что вы просто пробуете что-то здесь, но в реальном производственном коде, пожалуйста, не используйте режим ECB.

person sarnold    schedule 05.07.2010
comment
Спасибо за быстрый ответ. С echo "123456789ABCDEFG" | openssl enc -aes-128-ecb -nosalt -K "41414141414141414141414141414141" -iv 0 > hello.txt.bin и `NSData *plain = [data AESDecryptWithKey:@AAAAAAAAAAAAAAAA];` я не получаю полезного результата (Результат: 'ÛÊÐÅp:wíö¹X+3u|Ýç;Q') - person Guillaume; 05.07.2010
comment
@Guillaume, боюсь, вчера вечером я слишком устал, когда писал свой ответ - похоже, то же самое происходит и с IV: OpenSSL enc использует IV из всех нулей, а ваш iPhone использует IV всех ascii-нулей. (Байты выглядят как 0x303030303030..) Вы можете либо передать массив нулей процедуре CCCrypt, либо передать соответствующий IV в OpenSSL enc. - person sarnold; 06.07.2010
comment
Я обновил код и использование команды openssl в вопросе. Тоже не работает :( Спасибо за упорство. Есть другие идеи? - person Guillaume; 06.07.2010
comment
@Guillaume, извините, я в полной растерянности. :( - person sarnold; 06.07.2010
comment
Спасибо, что попробовали. Я надеюсь, что кто-то найдет, что не так. Не может быть, чтобы я первый захотел этого. - person Guillaume; 06.07.2010

Я использую Crypt::OpenSSL::AES для шифрования файлов, которые расшифровываются в моем приложении для iOS, которое расшифровывает с помощью CommonCryptor.

    cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0,
                          keyPtr, kCCKeySizeAES256,
                          IVECTOR /* initialization vector (optional) -- was NULL*/,
                          [self bytes], dataLength, /* input */
                          buffer, bufferSize, /* output */
                          &numBytesDecrypted);

Для инициализации IVECTOR я использую bzero.

bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

Для шифрования под OpenSSL в perl делаю так:

my $cipher = Crypt::CBC->new( -key    => $key,
                              -literal_key => 1,
                              -header => 'none',
                              -iv =>     '0000000000000000',
                              -cipher => 'Crypt::OpenSSL::AES' );

OpenSSL, похоже, принимает IV «0000000000000000» как то же самое, что и символы ASCII 0 (null). В ретроспективе это кажется правдоподобным, но для этого потребовалось много усилий, потому что каждый крипто-сбой выглядит как любой другой крипто-сбой: мусор выброшен.

person Howard Cohen    schedule 04.05.2012