Различные результаты в шифровании AES256 в Swift (iOS) и переполнении стека

Я работаю в AES256, чтобы иметь возможность шифровать / дешифровать между iOS и PHP, используя небезопасные каналы.

Я видел много похожих вопросов, которые касаются размера ключа, режима (CBC или ECB), использования случайного iv и т. Д. Но в этом случае я обнаружил странное поведение следующим образом.

Конфигурация в обеих средах:
— Ключ: 32 байта (256 бит)
— Размер блока: 128 бит (стандарт)
— iv: 16 байтов (статический для целей тестирования)
— Режим: CBC

Если я зашифрую 16 или 32-байтовый текст (чтобы соответствовать размеру блока AES), результат в Swift и PHP похожи, но не совсем одинаковы:

key = «12345678901234567890123456789012» plainText = «12345678901234567890123456789012» iv = «1234567890123456»

Swift cipher = e5RnnlJkv4QGnGhkMwfvgMHr80NWUVhbvvfCdPQ5V2KyKJTx4KfWmn4HXi4dG0b8
PHP шифр = e5RnnlJkv4QGnGhkMwfvgMHr80NWUVhbvvfCdPQ5V2I =

Как видите, есть разница в длине шифра и в последних 2 символах строки PHP Base64.

Но если я использую текст, который не является множителем размера блока AES128, скажем «Hello World», бот-среды сообщают о различных (но одинакового размера) шифрах следующим образом

Свифт Шифр ​​= bdwO / 5C8a + pliIoIXtuzfA ==

PHP шифр = oPotHCkxpOwQhIaCz6hNMw ==

В обоих случаях (Swift и PHP) шифр правильно расшифровывается независимо от размера открытого текста. Кроме того, результаты Swift соответствуют версии кода Objective-C

Прикрепленный упрощенный код используется:

PHP

    $key = "12345678901234567890123456789012";
$iv = "1234567890123456";
$plaintext = "Hello World";
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv);
$ciphertext_base64 = base64_encode($ciphertext);
echo  "ciphertext: ".$ciphertext_base64."</br>";

стриж

let keyData: NSData! = (key as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let keyBytes         = UnsafePointer<UInt8>(keyData.bytes)
let keyLength        = size_t(kCCKeySizeAES256)

let plainData = (plainText as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let dataLength    = UInt(plainData.length)
let dataBytes     = UnsafePointer<UInt8>(plainData.bytes)

var bufferData    = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
var bufferPointer = UnsafeMutablePointer<UInt8>(bufferData.mutableBytes)
let bufferLength  = size_t(bufferData.length)

let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options = UInt32(kCCOptionPKCS7Padding)

let ivData: NSData! = (iv as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let ivPointer = UnsafePointer<UInt8>(ivData.bytes)

var numBytesEncrypted: UInt = 0

var cryptStatus = CCCrypt(operation, algoritm, options, keyBytes, keyLength, ivPointer, dataBytes, dataLength, bufferPointer, bufferLength, &numBytesEncrypted)

bufferData.length = Int(numBytesEncrypted)
let base64cryptString = bufferData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
println(base64cryptString)

Почему они разные?

11

Решение

Это связано с различиями в режиме заполнения.

PHP использует «заполнение нулями» если обычный текст не в N раз больше размера блока. Таким образом, PHP дополняет 0..15 байта значением 00 для 128-битных блочных шифров, таких как AES. Для открытого текста, который заканчивается на границе блока, он не будет добавлять байты заполнения.

Большинство других языков используют заполнение PKCS # 7, которое дополняет следующий граница блока, где байт заполнения отражает количество добавленных байтов. Так что это будет 1..16 байт со значением 1..16 (или 01 в 10 в шестнадцатеричном формате). Для открытого текста, который заканчивается на границе блока, он добавит 16 байтов заполнения.

Дополнение PKCS # 7 является детерминированным и не зависит от значения открытого текста (которое может состоять из байтов с любым значением, а не только из текста); другими словами, его всегда можно применять и удалять независимо от содержимого.

Нулевое заполнение имеет проблему, что простой текст, заканчивающийся на 00 байты могут иметь те 00 байты удалены во время распаковки. Обычно это не проблема для ASCII-совместимых строк, так как 00 является управляющим символом, обычно означающим конец файла (EOF).

Пожалуйста, проверьте комментарии на mcrypt_encrypt чтобы увидеть, как вы можете применить PKCS # 7 padding к PHP.

8

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]