Структура секретного соглашения Windows CNG ECDH
Я потратил несколько дней на поиск структуры секретного соглашения ECDH, но безуспешно. В MSDN я обнаружил, что функция NCryptSecretAgreement устанавливает указатель на переменную NCRYPT_SECRET_HANDLE, которая получает дескриптор, представляющий значение секретного соглашения. Я вообще не знаком с WinAPI, поэтому просто ничего не могу сделать, кроме чтения документов.
Мне нужно обменяться ключами между настольным приложением на базе Windows и веб-приложением. Что мне нужно знать, так это то, как именно KDF CNG использует (в моем случае хэши) значение секретного соглашения. Я использую алгоритм SHA-256 в качестве KDF и пытаюсь хэшировать X и Y секретного соглашения, но результат не совпадает с тем, который вычисляет CNG. Есть идеи?
Спасибо.
1 ответ
Я не могу поручиться за то, что Microsoft сочла нужным для реализации, но есть стандарт на ECDH под названием X9.63. В этом стандарте ECDH работает так:
Вы запускаете вещь DH, получая общую точку кривой (X, Y) (это точка, которую вы получили от пира, умноженная на ваше секретное значение DH).
Вы конвертируете X (и только X; Y отбрасывается) в последовательность байтов, которую мы будем называть Z. Преобразование является беззнаковым байтом с прямым порядком байтов и использует размер поля: если X живет в поле Fq, то преобразование дает точно ceil (ceil (log q) / 8). Например, если вы используете кривую NIST P-521, вы работаете по модулю простого числа q, которое таково, что 2520
521
, поэтому ceil(log q) = 521 и результирующая последовательность байтов состоит ровно из 66 байтов, независимо от того, значение X Для наиболее часто используемой эллиптической кривой (известной как "P-256") это составляет 32 байта.Чтобы вывести Z в ключ, с хеш-функцией H, которая имеет выходную длину n байтов (например, n = 32 с SHA-256), вы вычисляете потенциально бесконечную строку H1|| H2|| H3||... где "||" обозначает конкатенацию, а Hi = H (Z || i), где "i" представляется в виде четырех байтов с использованием соглашения с прямым порядком байтов. Проще говоря, вы хэшируете Z вместе с 32-битным счетчиком и повторяете это снова и снова, пока у вас не будет достаточно байтов для требуемой длины ключа.