Шифрование AES в Google App Engine (Python) и дешифрование на iOS (Objective-C) - PullRequest
2 голосов
/ 04 января 2012

Я пытаюсь зашифровать некоторые данные из python (Google App Engine), а затем расшифровать их на iOS.

Есть несколько проблем, связанных с этим, из-за того, что с AES Encryption существует очень много вариантови различные форматы, доступные в Python и Objective-C.

Из-за ограниченной доступности библиотек PyCrypto в Google App Engine и кода AES на стороне iOS / Objective-C, требующего PKCS7Padding, я решил использовать slowAES на стороне Python.

Я также использую 16-битный ключ, режим CBC и PKCS7Padding.

Учитывая, что это моя функция шифрования и вспомогательные переменные / функция:

def str2nums(s):
    return map(ord, s)

key = "hjt4mndfy234n5fs"
moo = aes.AESModeOfOperation()
iv = [12, 34, 96, 15] * 4
CBC_mode = moo.modeOfOperation['CBC']
nkey = str2nums(key)


def encrypt(plaintext):
  funcName = inspect.stack()[0][3]
  logging.debug("Enter " + funcName)
  logging.debug("Input string: " + plaintext)
  m, s, encData = moo.encrypt(plaintext, CBC_mode, nkey, len(nkey), iv)
  fmt = len(encData)*'B'
  dataAsStr = ""
  for j in encData:
        dataAsStr = dataAsStr + str(j) + ","
  logging.debug("Output encrypted data:[" + dataAsStr + "]")
  encoded = base64.b64encode(struct.pack(fmt, *encData))
  logging.debug("Output encrypted string: " + encoded)
  decoded = struct.unpack(fmt, base64.b64decode(encoded))
  decrypted = moo.decrypt(decoded, s, CBC_mode, nkey, len(nkey), iv)
  logging.debug("Output decrypted back: " + decrypted)
  return encoded

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

На iOS я использую следующее дополнение AES NSData:

- (NSData *)AES128DecryptWithKey:(NSString *)key {
    // 'key' should be 16 bytes for AES128, will be null-padded otherwise
    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:NSASCIIStringEncoding];

    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 numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES128,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesDecrypted);

    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}

И я использую это, когда я опускаю base64 / упакованные / зашифрованные данные примерно так:

NSMutableString * result = [[NSMutableString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
if (LOG) { NSLog(@"Base64 encoded / Encrypted string: %@", result); }

NSData* encryptedData = [NSData decodeBase64ForString:result]; // base64 decode

if (LOG) { NSLog(@"Encrypted string: %@", encryptedData); }

NSData* decryptedData = [encryptedData AES128DecryptWithKey:@"hjt4mndfy234n5fs"]; // AES Decrypt

Проблема в том, что я не могу показатьсячтобы правильно расшифровать данные на стороне клиента (iOS), даже если они прекрасно дешифруются на сервере (в python).

Во время дешифрования cryptStatus всегда заканчивается: kCCAlignmentError. Что я не совсем понимаю.

Я также перепутал с AES 256, но мне нужен32-битный ключ, я думаю, и это не вариант для slowAES в режиме CBC (по крайней мере, в соответствии с примерами?).

Ведение журнала сервера (Обратите внимание, что фактические незашифрованные данные являются просто пустым набором []. Это представление в JSON-формате для возврата клиенту.

2012-01-04 08:48:13.962
Enter encrypt
D 2012-01-04 08:48:13.962
Input string: []
D 2012-01-04 08:48:13.967
Output encrypted data:[4,254,226,26,101,240,22,113,44,54,209,203,233,64,208,255,]
D 2012-01-04 08:48:13.967
Output encrypted string: BP7iGmXwFnEsNtHL6UDQ/w==
D 2012-01-04 08:48:13.971
Output decrypted back: []

Ведение журнала клиента (iOS):

2012-01-04 12:45:13.891 Base64 encoded / Encrypted string: BP7iGmXwFnEsNtHL6UDQ/w==
2012-01-04 12:45:13.892 Encrypted string: <04fee21a 65f01671 2c36d1cb e940d0ff>
2012-01-04 12:45:29.126 Decrypted string: 

Итак, мои вопросы:

  1. Что означает «ошибка выравнивания»? Или что я делаю неправильно, что не хочетрасшифровывать на клиенте?
  2. Нужно ли вообще беспокоиться о распаковке данных, учитывая, что они выглядят так, как будто они хорошо сочетаются? И если да, то как мне поступить с функцией unpack () в C или Objective?-C?
  3. Есть ли просто лучший способ сделать шифрование AES между Google App Engine и iOS?

РЕДАКТИРОВАТЬ: я должен также отметить, что помимо ответа использовать тот жеВектор инициализации, я обнаружил несоответствие между кодом Python и iOS для заполнения. Шифрование / дешифрование отлично работало для небольших объемов данных, но затем я не смог расшифровать с большими. Я исправил это, изменив iOSсторона, чтобы НЕ использовать PKCS7Padding и поставить вместо этого 0.

1 Ответ

0 голосов
/ 05 января 2012

IV должен совпадать на обоих концах.

IV (вектор инициализации) - это строка байтов, которая отправляется через шифровальщик / расшифровщик, чтобы поместить свою «память» в псевдослучайное состояние до того, как «реальные» данные будут отправлены. Поскольку результаты шифрования зависят от того, что было пройдено ранее, эта инициализация делает невозможным (не зная IV) для злонамеренной третьей стороны, чтобы узнать, мог ли данный открытый текст и ключ создать заданный гипертекст.

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

Наличие IV (даже если оно полу-предсказуемо) значительно увеличивает сложность использования атаки с «известным открытым текстом». Это особенно важно для относительно коротких и частых сообщений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...