Добавить в корзинуПозвонить
Найти в Дзене

О разнице между подписями HMAC и ECDSA

По работе мне довольно часто приходится сталкиваться с различного рода криптографическими штуками. И вот как-то раз возникла необходимость сделать интеграцию с рядом криптобирж. API этих бирж не используют никакие token-аутентификации, как принято делать в вебе. В таких случаях больше подходит HMAC-based аутентификация. Причины ясны - не нужно поддерживать токены на бэкенде, следить за их экспирацией и прочее. Достаточно только один раз выдать API-ключ клиенту, сохранить его у себя и все. В таком сетапе серверу требуется только проверить цифровую подпись сообщения, чтобы убедиться, что запрос совершает авторизованный клиент. Так, стоп, что?! Но ведь нас в школе институте учили, что цифровая подпись это там всякие DSA (ECDSA в случае криптографии на эллиптических кривых, что более распространено в наши дни). Что это за зверь такой - HMAC и почему не привычная всем цифровая подпись? Зачем мудрить и использовать что-то другое? А если мне попадется подобная задача, то какой подход выбрать
Designed by vectorjuice / Freepik
Designed by vectorjuice / Freepik

По работе мне довольно часто приходится сталкиваться с различного рода криптографическими штуками. И вот как-то раз возникла необходимость сделать интеграцию с рядом криптобирж. API этих бирж не используют никакие token-аутентификации, как принято делать в вебе. В таких случаях больше подходит HMAC-based аутентификация. Причины ясны - не нужно поддерживать токены на бэкенде, следить за их экспирацией и прочее. Достаточно только один раз выдать API-ключ клиенту, сохранить его у себя и все.

В таком сетапе серверу требуется только проверить цифровую подпись сообщения, чтобы убедиться, что запрос совершает авторизованный клиент. Так, стоп, что?! Но ведь нас в школе институте учили, что цифровая подпись это там всякие DSA (ECDSA в случае криптографии на эллиптических кривых, что более распространено в наши дни). Что это за зверь такой - HMAC и почему не привычная всем цифровая подпись? Зачем мудрить и использовать что-то другое? А если мне попадется подобная задача, то какой подход выбрать? Вот на эти вопросы я и захотел ответить сам себе, а заодно и поделиться с миром.

Вообще, HMAC (Hash-based MAC) относится к классу алгоритов Message Authentication Code (MAC). Приставку H он приобраел благодаря тому, что его работа основана на использовании заранее выбранной хеш-функции (более подробно можно посмотреть в википедии). Целью этого класса алгоритмов является:

  • Аутентнификация сообщения. Он удостоверяет, что сообщение сформировал держатель секретного ключа.
  • Гарантия целостности сообщения. Никто не изменил оригинальное сообщение по пути.

Но подождите, эти же задачи решает и ECDSA. Так в чем разница? Разбираемся дальше.

Цифровая подпись дает еще одну важную гарантию:

  • Невозможность отказаться (non-repudiation).

Я не нашел устоявшегося термина (статьи в википедии) на русском языке, поэтому буду использовать его так. Другими словами, после того, как подпись была сделана, ее создатель не может утверждать, что он к ней непричастен. Почему этого свойства нет у MAC? Потому что для создания и проверки MAC используется один и тот же ключ, а в случае с ECDSA, напомню, подпись создается секретным ключом, а проверяется - публичным. Поэтому, чисто теоретически, если кто-то хакнул сервер, стащил ключи из базы, то от Вашего имени может посылать запросы. Может по этой причине чаще предпочитают использовать HMAC в таких задачах? Думаю, все же нет, люди сознательно идут на риск использования одинакового ключа на обеих сторонах, значит это не критично.

В чем еще может быть разница? Давайте посмотрим на безопасность. Согласно википедии, безопасность HMAC выше, чем безопасность используемой в ней хеш-функции, хоть и завист от нее. Например, MD5 алгоритм считается устаревшим и ненадежным, а HMAC с использованием этого хеша еще считается безопасным (но все же не стоит его использовать). А вот использование этой же хеш-функции в ECDSA уже считается небезопасным, т.к. ECDSA полагается на более строгие условия безопасности (assumptions их в литературе называют). Значит, HMAC безопасней. Ну что ж, хорошая причина в его пользу.

А есть ли еще какие-то причины? Ну разумеется, самое интересное я приберег напоследок. HMAC оказывается намного быстрее при одинаковой длине ключа. Вот бенчмарк, заботливо подготовленный вашим покорным слугой:

$ go test -bench=. -benchtime=10000x
goos: linux
goarch: amd64
pkg: bench_ecdsa_hmac
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
BenchmarkHMacSha256-8 10000 2067 ns/op
BenchmarkEcdsaP256-8 10000 27174 ns/op
PASS
ok bench_ecdsa_hmac 0.500s

Здесь видно, что одна подпись занимает в среднем 2 микросекунды против 27 у ECDSA. Весомый аргумент для использования на сервере, нагрузка на который может достигать сотен тысяч запросов в секунду.

Выводы

Если Вам придется велосипедить подобную задачу или настраивать уже имеющуюся систему (как, например, JWT, где необходимо указать каким алгоритмом подписываются данные), то следует отталкиваться от условий которые вы имеете (спасибо, Кэп!). Если система нагруженная и Вас не беспокоит тот факт, что для подписывания данных и их проверки используется один и тот же ключ - смело используйте HMAC-SHA256 (иногда сокращают до каких-нибудь неприличных букв вроде HS256). Криптостойкости хеш-функции SHA-256 вполне достаточно. Ну, а если Вы паранойик, который даже Chrome-у не позволяет запоминать свои пароли, то можете и на SHA-512 заморочиться.

Если же использовать один и тот же ключ - непозволительная роскошь (как в криптовалютах), и нет каких-то уж очень специфических требований к задаче, то ECDSA это очевидный выбор. Из кривых, на которых она работает, можно взять что-то из популярных с 32-битным ключом, например, Secp256k1 (используется в Bitcoin).

Спасибо за внимание, надеюсь, изложил не слишком сложно. Успехов!