внедрение шифрования AES256 в IOS

Это мой java-код. Теперь я хочу реализовать ту же функциональность в Objective-C.

Cipher encryptCipher;
IvParameterSpec iv = new IvParameterSpec(key);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = encryptCipher.doFinal(dataToEncrypt.getBytes());
Log.d("TAG", "encrypted string:"
        + Base64.encodeToString(encrypted, Base64.DEFAULT));
return Base64.encodeToString(encrypted, Base64.DEFAULT).trim();

Это моя реализация iOS

- (NSData *)AES256EncryptWithKey:(NSString*)key
{
    char keyPtr[kCCKeySizeAES256 + 1];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    size_t bufferSize           = dataLength + kCCBlockSizeAES128;
    void* buffer                = malloc(bufferSize);

    size_t numBytesEncrypted    = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                  kCCAlgorithmAES128,
                                  kCCOptionPKCS7Padding,
                                  keyPtr,
                                  kCCKeySizeAES256,
                                  NULL,
                                  [self bytes],
                                  dataLength,
                                  buffer,
                                  bufferSize, 
                                  &numBytesEncrypted);

    if (cryptStatus == kCCSuccess)
    {

        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer);
    return nil;
}

Это моя функция генерации хеш-ключа. эта функция возвращает один и тот же ключ в Android и iOS

int dkLen = 16;
    NSData *keyData = [hash_key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *salt    = [saltKey dataUsingEncoding:NSUTF8StringEncoding];
    uint    rounds  = 1000;
    uint    keySize = kCCKeySizeAES128;

    NSMutableData *derivedKey = [NSMutableData dataWithLength:keySize];





    CCKeyDerivationPBKDF(kCCPBKDF2,               // algorithm
                         keyData.bytes,           // password
                         keyData.length,          // passwordLength
                         salt.bytes,              // salt
                         salt.length,             // saltLen
                         kCCPRFHmacAlgSHA1,       // PRF
                         rounds,                  // rounds
                         derivedKey.mutableBytes, // derivedKey
                         dkLen*8);
 return derivedKey;

Я получаю другой результат. Я делаю что-то не так? Пожалуйста, помогите мне узнать.


person Askarc Ali    schedule 29.10.2015    source источник
comment
Поскольку у вас все еще есть проблема, вы можете улучшить вопрос: (1) Показать ввод и вывод обеих версий (в шестнадцатеричном формате); (2) Предоставьте исполняемые фрагменты кода в вашей любимой онлайн-среде IDE, например ideone.com (она поддерживает Java и Objective-C). ).   -  person Artjom B.    schedule 09.11.2015
comment
не могли бы вы привести мне подобный пример   -  person Askarc Ali    schedule 10.11.2015
comment
@Artjom B, твоя помощь неоценима. см. это gist.github.com/askarali/401e1056c5d2c3ad29d9   -  person Askarc Ali    schedule 11.11.2015


Ответы (2)


Одна проблема заключается в том, что в коде Java использовался режим CBC, а в коде iOS — режим ECB.

Далее, из упомянутого проекта:
//result= yHbhApwTpQ2ZhE97AKF/g==
является недопустимым кодом Base64, он не содержит кратных 4 байтов.

С этими опциями: CBC, заполнение PKCS#7

inputs:  
   data in: "hello" which will be null padded to the block length of 16-bytes  
   key:  
      base64: VQQhu+dUdqXGoE7RZL2JWg==  
      hex: 550421bbe75476a5c6a04ed164bd895a  
   iv:   
      base64: VQQhu+dUdqXGoE7RZL2JWg==  
      hex: 550421bbe75476a5c6a04ed164bd895a  
encrypted output:  
   hex: ff21db840a704e943666113dec0285fe  
   base64: /yHbhApwTpQ2ZhE97AKF/g==  

Это тестовый код:

NSString *base64Key  = @"VQQhu+dUdqXGoE7RZL2JWg==";
NSString *dataString = @"hello";

NSData *key  = [[NSData alloc] initWithBase64EncodedString:base64Key  options:0];
NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];

NSLog(@"key:  %@", key);
NSLog(@"data: %@", data);

NSData *encryptedData = [TestClass crypt:data
                                 iv:key
                                key:key
                            context:kCCEncrypt];

NSLog(@"encryptedData: %@", encryptedData);
NSString *encryptedBase64Data = [encryptedData base64EncodedStringWithOptions:0];
NSLog(@"encryptedBase64Data: %@", encryptedBase64Data);

Это метод шифрования (в классе TestClass):

+ (NSData *)crypt:(NSData *)dataIn
                  iv:(NSData *)iv
                 key:(NSData *)symmetricKey
             context:(CCOperation)encryptOrDecrypt
{
    CCCryptorStatus ccStatus   = kCCSuccess;
    size_t          cryptBytes = 0;    // Number of bytes moved to buffer.
    NSMutableData  *dataOut    = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];

    ccStatus = CCCrypt( encryptOrDecrypt,
                       kCCAlgorithmAES128,
                       kCCOptionPKCS7Padding,
                       symmetricKey.bytes,
                       kCCKeySizeAES128,
                       iv.bytes,
                       dataIn.bytes,
                       dataIn.length,
                       dataOut.mutableBytes,
                       dataOut.length,
                       &cryptBytes);

    if (ccStatus != kCCSuccess) {
        NSLog(@"CCCrypt status: %d", ccStatus);
    }

    dataOut.length = cryptBytes;

    return dataOut;
}

Примечание. Я разделяю шифрование и преобразование данных. Объединение их только усложняет тестирование.

Если вы используете реализацию онлайн-шифрования, заполнение, вероятно, не будет PKCS # 7, потому что mcrypt не поддерживает его, вместо этого он выполняет нестандартное заполнение нулями. Поскольку байты заполнения — это просто количество байтов заполнения, заполнение может быть смоделировано на входе. Вот пример использования AES — Симметричные шифры в Интернете.

Обратите внимание, что "hello" PKCS#7, дополненный до размера блока 16 байт, добавляет 11 байтов значения uint8 11 или 0x0B: 68656c6c6f0B0B0B0B0B0B0B0B0B0B0B.

Наконец, остается вопрос, почему код Java не дает такого результата?

person zaph    schedule 16.11.2015
comment
спасибо заф. у меня есть работающая реализация на java и c#, она работает нормально. - person Askarc Ali; 17.11.2015
comment
Для совместимости все, что необходимо, — это просто получить одинаковые входные данные. Проблема с библиотеками, которые объединяют множество операций, заключается в том, что они обычно не документируют внутренности, что затрудняет взаимодействие. Происходит что-то дополнительное. Возможно, строки не UTF-8? Вот почему я сохраняю фактическое шифрование простым, только байты данных, а затем добавляю преобразования данных вне шифрования. Используя шестнадцатеричные дампы, я могу точно видеть, что это за данные. - person zaph; 17.11.2015
comment
Одним из отличий является размер ключа, в коде iOS ключ явно указан как 256-битный (32-байтовый), но код Java выбирает размер ключа на основе предоставленных данных ключа, который составляет 128-битный (16-байтовый). Другая возможность состоит в том, что данные (hello) состоят из unichar (16 бит). - person zaph; 17.11.2015
comment
этот метод мы используем во всем моем проекте, поэтому в настоящее время я не могу внести улучшения - person Askarc Ali; 18.11.2015
comment
расшифровка zaph дает другой результат - person Askarc Ali; 18.11.2015
comment
I am getting success url response like ‹==› google.com/... Как расшифровать, чтобы узнать ответ? - person Reddy; 01.04.2017
comment
Я люблю тебя @zaph. Пытался получить последовательное шифрование + реализацию base64 в течение 2 дней подряд! Получил правильный зашифрованный код, наконец, благодаря вашей простоте. - person esh; 20.05.2021

Хорошо, а какой у тебя ключ? kCCAlgorithmAES128 и kCCKeySizeAES256 предполагают разные размеры ключей. Я предполагаю, что вы используете 16-байтовый ключ, потому что в противном случае ваш Java-код вызовет исключение. Если вы используете 128-битный ключ, вам следует использовать kCCKeySizeAES128.

Кроме того, вы не передаете какой-либо IV, поэтому предполагается, что IV заполнен байтами 0x00, но в Java вы используете ключ как IV.

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

Да, заполнение PKCS#5 и заполнение PKCS#7 — это одно и то же.

person Artjom B.    schedule 29.10.2015
comment
Итак, это 128-битный ключ (при условии кодировки base64). Если вы хотите использовать AES-256, вам нужен ключ большего размера, и тогда вы не сможете использовать ключ в качестве IV непосредственно в Java. - person Artjom B.; 29.10.2015
comment
я проверил оба ключа, которые получают от Android и ios, они одинаковы - person Askarc Ali; 29.10.2015
comment
Я никогда не говорил, что ваши ключи неверны. Я сказал, что вы используете разные IV в Java и Obj-C. - person Artjom B.; 29.10.2015
comment
не могли бы вы предоставить пример кода, потому что я новичок в iOS - person Askarc Ali; 29.10.2015
comment
@ Артём Б, не могу исправить - person Askarc Ali; 31.10.2015
comment
Это не дает ответа на вопрос. Чтобы подвергнуть критике или запросить разъяснения у автора, оставьте комментарий под его публикацией. - person grebulon; 09.11.2015
comment
@grebulon Вы были отменены. Я хотел бы понять ваши рассуждения. Примечание: Ваш ответ находится в другом замке: когда ответ не является ответом? - person Artjom B.; 09.11.2015
comment
@askarcali Вот пример того, что я имею в виду в своем ответе. Если это не решит вашу проблему, то, вероятно, вы передаете ключ именно так. Результатом вывода ключа является NSMutableData, но вы передаете его как строку, а затем накладываете на нее кодировку UTF-8, которая неверно, потому что это может нарушить байтовое представление ключа во время преобразования. Строка [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; и предыдущие - проблема. Боюсь, я недостаточно знаю об Obj-C, чтобы помочь. - person Artjom B.; 10.11.2015
comment
@Artjom B, можешь открыть чат? и не могли бы вы поделиться тем, что знаете - person Askarc Ali; 10.11.2015
comment
почему / идет сначала - person Askarc Ali; 18.11.2015