Туториалы
11 января 2022
Туториалы
11 января 2022
Использование функции формирования ключа на основе кодов аутентификации HMAC для создания кодов аутентификации сообщений в Swift

Сегодня мы поговорим о функции формирования ключа (Key Derivation Function, KDF) с использованием библиотеки CryptoKit. Эти возможности удобно использовать, когда вам необходимо организовать совместное использование секретных данных двумя получателями. Мы будем формировать симметричный ключ из некоторой информации (при этом она может быть случайной и доступной для каждого), а затем мы просто создадим некий код аутентификации (проверки подлинности) к сообщению, чтобы каждый мог удостовериться, что сообщения/данные являются надежными, заслуживающими доверия. 

Давайте приступим к написанию кода, но сначала... 

Живопись 

Картина, которую я выбрал сегодня – «Мужчина, пишущий письмо» (1662 – 1665) работы Габриэля Метсю. Габриэль Метсю, родившийся в 1629 и умерший в 1667 году – голландский художник, писавший картины на исторические темы, натюрморты, портреты и жанровые работы. Он был «очень эклектичным художником, который не придерживался определенного стиля, техники или какого-либо одного типа сюжета в течение длительного времени». Только 14 из его 133 работ имеют дату создания. 

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

Постановка задачи 

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

Давайте сначала выясним, что такое функция формирования ключа на основе HMAC. Это просто некоторая форма KDF (Key Derivation Function – функция формирования ключа). Кратко говоря, это просто функция, которую вы используете для ввода в нее некоторых данных, а она вам выдает на своем выходе некий псевдослучайный симметричный ключ. Как об этом написано в Википедии: 

Функция формирования ключа (англ. Key Derivation Function, KDF) — функция, формирующая один или несколько секретных ключей на основе некоторого секретного значения (такого, как главный ключ, пароль или парольная фраза) с помощью псевдослучайной функции. Функция формирования ключа может использоваться для создания ключей необходимой длины или заданного формата. Примером этого может служить преобразование элемента группы, полученного как результат протокола обмена ключами Диффи — Хеллмана, в симметричный ключ для использования с алгоритмом AES. Криптографические хеш-функции с ключом являются популярными примерами псевдослучайных функций, используемых для формирования ключа.

Последовательность наших действий будет такой: 

1 – Каждая заинтересованная сторона должна знать материал для формирования входного ключа и функцию генерирования ключа, в данном случае это HKDF (HMAC- based Key Derivation Function – функция формирования ключа на основе HMAC). 

2 – Генерируем ключ, используя материал входного ключа и HKDF. 

3 – Используем этот ключ в HMAC (Hash-based Message Authentication Code – код аутентификации сообщений, использующий хеш-функции) с любой хеш- функцией, какую вы хотите (в нашем случае это алгоритм SHA256, как для формирования ключа, так и для создания кода аутентификации), чтобы создать код аутентификации. 

4 – Отправляем этот код вместе с кодом аутентификации любому, кто желает удостовериться, что сообщение не было подвергнуто модификации. 

Давайте начнем с создания симметричного ключа на основе некоторых входных данных. 

Во-первых, нам необходим входной материал (строка). Он должен быть доступен для совместного использования обеими сторонами. Эта строка может и должна быть публично открытой, поскольку если этого не будет, то впоследствии никто не сможет верифицировать код аутентификации. Причина в том, что мы не предоставляем симметричный ключ никому. Это будет сделано только путем совместного использования материала входной строки.

let secretPassword = "inputMaterialString".data(using: .utf8)! // Mark 1

let hkdfResultKey = HKDF.deriveKey(inputKeyMaterial: SymmetricKey(data: secretPassword), outputByteCount: 151) // Mark 2

В вышеприведенном коде, отмеченном комментарием Mark 1, мы просто создаем данные из некоторой строки. Эта строка является в точности тем, о чем мы говорили при планировании последовательности наших действий, называя это «материалом входного ключа». Таким образом, когда мы говорим о совместном использовании материала входного ключа, это и есть именно то, о чем мы говорим. В строке с комментарием Mark 2 мы используем структуру HKDF библиотеки CryptoKit для вызова статической функции deriveKey, чтобы сгенерировать симметричный ключ длиной 151 байт, который мы можем использовать для выполнения других криптографических операций, таких как создание кода аутентификации для любых данных. В строке с комментарием Mark 2 при вызове функции ей передаются два входных аргумента: первый – это данные, которые вы используете в качестве входного материала для вашего ключа, а второй – размер ключа, который вы хотите сгенерировать, в байтах. 

Чтобы проверить, правильно ли сгенерирован размер ключа, просто распечатаем полученное значение, разделив его на 8:

print("The generated key size (in bytes): ",hkdfResultKey.bitCount/8)

Результат:

The generated key size (in bytes): 151

Итак, наиболее трудная часть пройдена, и теперь вы можете использовать ваш симметричный ключ, как вам хочется. Сегодня мы будем использовать его для создания кода аутентификации, при помощи которого вы сможете убедиться, что сообщение не было изменено. 

Давайте создадим сообщение, которое нам будет необходимо верифицировать, и код аутентификации: 

let trustfulMessage = "The message that would be verified by the authentication code".data(using: .utf8)!

let authenticationCode = HMAC.authenticationCode(for: trustfulMessage, using: hkdfResultKey) // Mark 2

print("\(authenticationCode.description)")

В результате получим:

Код, приведенный в строке с комментарием Mark 2, демонстрирует, как можно генерировать код аутентификации, для чего вам нужно всего лишь ввести входную структуру данных и ключ, который мы сгенерировали выше. 

Теперь, если кто-нибудь захочет проверить, не подвергалось ли данное сообщение модификациям, он может использовать входной материал, чтобы сгенерировать ключ, как это сделали мы, и сгенерировать код аутентификации. Поскольку никто другой не будет знать, как сформировать ключ, МЫ В БЕЗОПАСНОСТИ! И... у нас все готово! 

 Очень круто, не так ли? 

Ниже приведен полностью программный код, который вы можете проверять и тестировать его работу в ваших плейграундах: 

import CryptoKit

let secretPassword = "inputMaterialString".data(using: .utf8)!

let hkdfResultKey = HKDF.deriveKey(inputKeyMaterial: SymmetricKey(data: secretPassword), outputByteCount: 151)

print("The generated key size (in bytes): ",hkdfResultKey.bitCount/8)

let trustfulMessage = "The message that would be verified by the authentication code".data(using: .utf8)!

let authenticationCode = HMAC.authenticationCode(for: trustfulMessage, using: hkdfResultKey)

print("\(authenticationCode.description)")

Заключение 

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

Оригинал статьи

  


Оцените статью
0
0
0
0
0

Чтобы добавить комментарий, авторизуйтесь
Войти
Акулов Иван Борисович
Пишет и переводит статьи для SwiftBook