Расшифровка AES 128 с зашифрованным текстом короче ключа

Мы разрабатываем приложение, которое должно работать с данными, зашифрованными LoraWan (https://www.lora-alliance.org)

Мы уже нашли документацию о том, как они шифруют свои данные, и читали ее последние несколько дней (https://www.lora-alliance.org/sites/default/files/2018-04/lorawantm_specification_-v1.1.pdf ), но в настоящее время все еще не может решить нашу проблему.

Мы должны использовать 128-битную расшифровку AES ECB с заполнением нулями для расшифровки сообщений, но проблема в том, что она не работает, потому что зашифрованные сообщения, которые мы получаем, недостаточно длинны для AES 128, поэтому алгоритм возвращает «Данные не являются полный блок» в последней строке.

Пример ключа, который мы получаем, выглядит следующим образом: D6740C0B8417FF1295D878B130784BC5 (ненастоящий ключ). Он имеет длину 32 символа, то есть 32 байта, но если рассматривать его как шестнадцатеричный, то он становится длиной 16 байтов, что необходимо для 128-битного AES. Это код, который мы используем для преобразования Hex из String:

public static string HextoString(string InputText)
{byte[] hex= Enumerable.Range(0, InputText.Length)
                 .Where(x => x % 2 == 0)
                 .Select(x => Convert.ToByte(InputText.Substring(x, 2), 16))
                 .ToArray();
return System.Text.Encoding.ASCII.GetString(hex);}

(Небольшая вещь, которую следует отметить для приведенного выше кода, заключается в том, что мы не уверены, какую кодировку использовать, поскольку мы не смогли найти ее в документации Lora, и они нам не сказали, но в зависимости от этой небольшой настройки мы могли испортить нашу расшифровка (хотя мы перепробовали все возможные комбинации, ascii, utf8, utf7 и т.д))

Пример сообщения, которое мы получаем: d3 73 4c, которое, как мы предполагаем, также в шестнадцатеричном формате. Это всего 6 байтов и 3 байта, если мы преобразуем его из шестнадцатеричного в обычный, по сравнению с 16 байтами, которые нам потребуются как минимум для соответствия длине ключа.

Это код для расшифровки Aes 128, который мы используем:

private static string Aes128Decrypt(string cipherText, string key){

string decrypted = null;

var cipherPlainTextBytes = HexStringToByteArray(cipherText);
//var cipherPlainTextBytes = ForcedZeroPadding(HexStringToByteArray(cipherText));
var keyBytes = HexStringToByteArray(key);

using (var aes = new AesCryptoServiceProvider())
{
    aes.KeySize = 128;
    aes.Key = keyBytes;
    aes.Mode = CipherMode.ECB; 
    aes.Padding = PaddingMode.Zeros; 

    ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
    using (MemoryStream ms = new MemoryStream(cipherPlainTextBytes, 0, cipherPlainTextBytes.Length))
    {
        using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
        {
            using (StreamReader sr = new StreamReader(cs))
            {
                decrypted = sr.ReadToEnd();
            }
        }
    }
}
return decrypted;}

Таким образом, очевидно, что в sr.ReadToEnd() будет возвращено «Данные являются неполным блоком».

Как вы можете видеть из примера, в этой закомментированной строке мы также попытались «дополнить» текст до нужного размера полным нулевым массивом байтов правильной длины (16 — cipherText), и в этом случае алгоритм работает хорошо, но он возвращает полную тарабарщину, а не исходный текст.

Мы уже перепробовали все режимы работы и возились с режимами заполнения. Они не предоставляют нам ничего, кроме шифротекста и ключа для этого текста. Также нет вектора инициализации, поэтому мы предполагаем, что должны генерировать его каждый раз (но для ECB он даже не нужен iirc)

Более того, они могут отлично шифровать и расшифровывать свои сообщения. Что больше всего удивляет в этом, так это то, что я гуглю это уже несколько дней и не могу найти НИ ОДНОГО примера в Google, где ШИФРОТЕКСТ короче, чем ключ во время дешифрования.

Очевидно, я нашел примеры, когда сообщение, которое они Шифруют, короче, чем нужно, но это то, для чего заполнение на стороне ШИФРОВАНИЯ (правильно?). Таким образом, когда вы затем получите дополненное сообщение, вы можете сообщить алгоритму, какой режим заполнения использовался для придания ему правильной длины, чтобы затем он мог отделить дополнение от сообщения. Но во всех этих случаях полученное сообщение при расшифровке имеет правильную длину.

Так вот вопрос - что мы делаем не так? есть ли способ расшифровать зашифрованные тексты, которые короче ключа? Или они где-то ошибаются, создавая слишком короткие шифры?

Спасибо за любую помощь.


person user1966576    schedule 21.07.2018    source источник
comment
Укажите место в документе, которое относится к шифрованию, с которым вы работаете.   -  person zaph    schedule 21.07.2018
comment
Страница 25, Шифрование полезной нагрузки кадра MAC (FRMPayload). Это полезная нагрузка, которую они шифруют, которую мы должны расшифровать.   -  person user1966576    schedule 21.07.2018


Ответы (1)


В AES-ECB единственный допустимый зашифрованный текст короче 16 байт — пустой. Это 16-байтовое ограничение — это размер блока (а не ключа) AES, который соответствует размеру ключа для AES-128.

Поэтому вопрос

Пример сообщения, которое мы получаем: d3 73 4c

не показывает зашифрованное сообщение ECB (поскольку комментарий сообщает, что это из JSON, это не могут быть байты, показать как шестнадцатеричный). И это слишком мало, чтобы быть FRMPayload (согласно этому comment) для Join-Accept, поскольку spec говорит о позже:

1625 Сообщение имеет длину 16 или 32 байта.

Может ли быть так, что то, что содержит это сообщение JSON, является не полной FRMPayload, а фрагментом пакета, закодированным как шестнадцатеричная пара с разделителем-пробелом? Пока не понятно, как построить FRMPayload, нет смысла его расшифровывать.

Обновление: если загадочное сообщение всегда имеет размер 3 байта и если оно всегда одинаково для данного ключа (или доступно один раз для каждого ключа), то в соответствии с comment это может быть значение проверки ключа. KCV часто представляет собой первые 3 байта шифрования нулевого значения с ключом для необработанного блочного шифра (эквивалентно: для каждого ECB). Javascript AES Герберта Ханевинкеля может работать полностью в автономном режиме (что необходимо, чтобы не раскрыть ключ) и использоваться для ручной проверки гипотезы. В нем говорится, что для 16-байтового ключа, указанного в вопросе, KCV будет равен cd15e1 (или c076fc согласно варианту в следующем разделе).


Также: он используется CreateDecryptor для создания штуковины, отвечающей за расшифровку ECB. Вероятно, это неверно в контексте расшифровки полезной нагрузки LoraWan, для которой требуется шифрование ECB для расшифровки некоторых полей:

1626 Примечание. Операция дешифрования AES в режиме ECB используется для шифрования сообщения о принятии присоединения, чтобы конечное устройство могло использовать операцию шифрования AES для расшифровки сообщения. Таким образом, конечное устройство должно реализовать только шифрование AES, но не дешифрование AES.


В контексте расшифровки пакетов LoraWan вы хотите взаимодействовать с механизмом AES, используя массивы байтов, а не строки. Строки имеют кодировку, а шифротекст LoraWan и соответствующий открытый текст — нет. Другим, похоже, удалось заставить хороший универсальный криптографический API .NET выполнить низкоуровневую работу. .


В коде HextoString я смутно понимаю, что намерение и, возможно, результат заключаются в том, что hex становится исходным шестнадцатеричным вводом в виде массива байтов (полностью избавленным от шестнадцатеричной и другой кодировки sin; в этом случае переменная hex должна быть переименована во что-то на мелодии из pure_bytes). Но тогда я в недоумении по поводу System.Text.Encoding.ASCII.GetString(hex). Я был бы удивлен, если бы он просто создал строку байтов из массива байтов или вернул ключ обратно в шестнадцатеричный формат для последующей передачи в HexStringToByteArray в Aes128Decrypt. Кроме того, это заставляет меня опасаться, что любой байт в [0x80..0xFF] может превратиться в 0x3F, что не очень хорошо для ключа, зашифрованного текста и соответствующей полезной нагрузки LoraWan. Они не имеют кодировки символов при расшифровке.

Мой вывод состоит в том, что если HexStringToByteArray делает то, что предполагает его название, и учитывая текущий интерфейс Aes128Decrypt, HextoString должен просто удалять пробелы (или не нужен, если HexStringToByteArray удаляет пробелы на лету). Но я рекомендую изменить интерфейс, чтобы использовать массивы байтов, а не строки (см. предыдущий раздел).


В качестве отступления: создание объекта ICryptoTransform из его ключа должно выполняться один раз для многократного использования объекта.

person fgrieu    schedule 21.07.2018
comment
Спасибо за ответ. Уверяю вас, что сообщения, которые мы получили до сих пор, не являются ни 16, ни 32. Я привел пример, который равен 6, их много, но мы также получили 28 длинных сообщений, которые при деконвертировании из шестнадцатеричного кода имеют длину 14 байтов, что опять же, просто не достаточно долго. Что касается остального, я на самом деле не уверен на 100%, что мы должны использовать ECB, но это либо ECB, либо CBC. Они не уточняли, мы просто собрали ECB, потому что CBC даже не упоминается в спецификации, плюс они не предоставляют вектора инициализации - person user1966576; 21.07.2018
comment
@user1966576 user1966576: Вполне может быть, что то, что вы считаете полученными пакетами, на самом деле не так. Как именно вы помещаете их во вселенную .net и делаете вывод, что они меньше 16 байт? Пакеты оживают как массивы байтов, а не строки. Что бы ни делало их струнами, это очень подозрительно. - person fgrieu; 21.07.2018
comment
@user1966576 user1966576: Еще одна ловушка состоит в том, чтобы сделать вывод, что пакет был получен, когда было получено только начало. Некоторые протоколы имеют специальный сигнал или небайтовую комбинацию битов (конец кадра), позволяющую определить конец. Другие указывают длину в начале (повреждение, вызывающее интересные проблемы с восстановлением). Третьи ничего не имеют, и получатель обычно в конечном итоге предполагает, что байт больше не придет, если байт не поступал в течение некоторого времени (причем это время способствует задержке и эффективно определяет конец этого времени). Я не сразу вижу, что указано в связанной спецификации. - person fgrieu; 21.07.2018
comment
Ну хм... В .NET есть библиотека для вебсокетов. Мы используем эту библиотеку, мы подключаемся к нашему источнику через веб-сокет, они отправляют сообщения JSON через это, мы десериализуем эти JSON, одним из таких свойств JSON являются зашифрованные данные, один из примеров которых я привел. У нас нет контроля над той частью, которая превращает их в строку. - person user1966576; 21.07.2018
comment
@ user1966576: Каким бы ни был этот источник, вы показываете, что он отправил вам не полный блок зашифрованного текста AES-ECB. Возможно, у этого источника есть спецификация, говорящая о том, что он решает отправить? - person fgrieu; 21.07.2018
comment
@user1966576 user1966576 Вам нужно пойти глубже, получить сетевой сниффер, такой как прокси Charles, и посмотреть, что на самом деле возвращается с сервера. - person zaph; 21.07.2018
comment
@zaph и все такое, может быть, это KCV. Это нулевой блок, зашифрованный с использованием режима ECB (или, скорее, просто блочное шифрование), и обычно используются только самые левые 3 байта. - person Maarten Bodewes; 22.07.2018