Рейтинг:1

Как составить (H)KDF, шифрование и (H)MAC

флаг mk

По устаревшим причинам одна из моих систем не имеет возможности использовать режим AEAD, мы ограничены AES в обычном режиме CBC или CTR плюс MAC.

Типичная задача — передать данные с одного узла на другой, гарантируя целостность и конфиденциальность. Я ловлю себя на том, что постоянно указываю следующую композицию:

  • CSPRNG для создания секрета начальной загрузки
  • KDF для получения ключей для шифрования и MAC — я использую HKDF
  • CSPRNG снова получить IV
  • Режим CTR для шифрования данных
  • MAC по секрету начальной загрузки, iv, cipherspec и шифротексту — я использую HMAC

Итак, я делаю «Зашифровать-затем-MAC» и аутентифицирую все входные данные для вычисления зашифрованного текста. Но я как бы беспечно предположил, что эта композиция безопасна. На самом деле я никогда не видел эту полную композицию, включая KDF, описанную как многоразовый примитив.

TLS делает что-то очень похожее, но это не совсем то же самое (например, он по-другому использует HKDF).

Схемы IES, такие как ECIES и DLIES, выглядят концептуально похожими, но различаются в деталях, особенно в способе получения входных данных для KDF.

Итак, мой вопрос: является ли эта проблема недостаточно общей, чтобы гарантировать решение поваренной книги? Или, может быть, что-то уже существует, что я упустил из виду? Иначе как я могу обрести уверенность в решении? (Когда дело доходит до криптографии, я всегда осторожен).

В случае, если детали полезны, поток:

Передающий узел выполняет следующие действия:

  1. Получите 256 секретных битов семя из CSPRNG
  2. Шифровать семя для другого узла, использующего его открытый ключ как зашифрованное_начальное число
  3. Расколоть семя в 128 бит соль и 128 бит key_material
  4. Получите 384 секретных бита, вызвав HKDF-HMAC-SHA-256(length=384b, ikm=key_material, salt=salt, info=<идентификатор исходного узла || идентификатор конечного узла>)
  5. Разделить на 128 бит ключ_шифрования, 256 бит HMAC_ключ

Для каждого отправляемого сообщения:

  1. Получите 128 бит из CSPRNG как шифрование_iv
  2. Зашифруйте открытый текст, используя AES-128-CTR(iv=шифрование_iv, ключ=шифрование_ключ)
  3. Вычислить тег как HMAC-SHA-256 (ключ = ключ_HMAC, данные = зашифрованное_начальное число || шифрование_iv || шифроспецификация = AES-128-CTR || зашифрованный текст)
  4. Отправить на другой узел: зашифрованное_начальное число || шифрование_iv || спецификация шифра || зашифрованный текст || тег

Принимающий узел выполняет следующие действия:

  1. Разобрать полученное сообщение на его компоненты зашифрованное_начальное число и т.д.
  2. расшифровать зашифрованное_начальное число используя закрытый ключ принимающего узла, получая семя
  3. Расколоть семя в 128 бит соль и 128 бит key_material
  4. Получите 384 секретных бита, вызвав HKDF-HMAC-SHA-256(length=384b, ikm=key_material, salt=salt, info=<идентификатор исходного узла || идентификатор конечного узла>)
  5. Разделить на 128 бит ключ_шифрования, 256 бит HMAC_ключ
  6. Вычислить тег как HMAC-SHA-256 (ключ = HMAC_key, данные = <сообщение, полученное от отправляющего узла без тега>)
  7. Назначать tag_valid := правда если тег совпадает с тегом в полученном сообщении, ЛОЖЬ в противном случае
  8. Назначать k := ключ_шифрования если tag_valid, иначе присвоить k := <некоторая случайная константа>
  9. Расшифровать зашифрованный текст как [спецификация шифра](iv=encryption_iv, ключ=k)
  10. Вывести кортеж (tag_valid, открытый текст) - звонящий должен проверить tag_valid перед использованием открытого текста

Так что же может пойти не так? Ну, для одного семя значение используется до проверки тега MAC. Я мог бы подписать его, используя закрытый ключ отправляющего узла, но на самом деле это не связывает семя к тегу MAC. Кроме того, это начинает становиться грязным, отсюда и мое беспокойство.

kelalaka avatar
флаг in
Если у вас есть надежная система с открытым ключом, почему бы вам просто не сгенерировать 512-битный унифицированный материал случайного ключа и использовать 256-битный AES-256 и 256-битный для HMAC и отправить через механизм открытого ключа для упрощения протокола?
eddydee123 avatar
флаг mk
Действительно, я упростил реальную ситуацию - на самом деле ключей для других целей, которые нужно отправить, больше. Вот почему я отправляю начальное число KDF вместо самих ключей. Мой вопрос пытается обобщить общую композицию KDF+Enc+MAC.
kelalaka avatar
флаг in
В этом случае вам может понадобиться DRBG, чтобы компрометация в текущем состоянии не утекала до и после этапов.
eddydee123 avatar
флаг mk
@kelalaka Я запутался - ты имеешь в виду DRBG вместо HKDF? я не следую рассуждениям
kelalaka avatar
флаг in
Не совсем так, в зависимости от вашего варианта использования семени вам может понадобиться вызвать его, чтобы вообще ничего не скомпрометировать, например. $seed_1 = DRGB(seed_0),HKDF(seed_1), seed_2 = DRGB(seed_1),HKDF(seed_2), ...)$

Ответить или комментировать

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