Tink использует наборы ключей (Keysets) для обеспечения ротации ключей. Формально, набор ключей — это непустой список 1 ключей, в котором один ключ назначен основным (ключ, который используется, например, для подписи и шифрования новых открытых текстов). Кроме того, ключи в наборе ключей получают уникальный идентификатор 2 и статус ключа, который позволяет отключать ключи, не удаляя их из набора ключей.
Ключевые наборы — это основной способ доступа пользователей к ключам (через класс KeysetHandle ). Это гарантирует, что у каждого пользователя есть код для одновременной обработки нескольких ключей. Для большинства пользователей криптографии обработка нескольких ключей является необходимостью : должна быть возможность менять ключи (например, старые ключи могут быть раскрыты), и практически никогда не существует атомарного «переключения на следующий ключ», которое можно было бы применить ко всем машинам, на которых работает код, и ко всем зашифрованным текстам глобально и мгновенно. Следовательно, пользователю необходимо написать код, который работает при переходе от одного ключа к другому.
Пример: AEAD
Рассмотрим набор ключей AEAD, содержащий несколько ключей для примитива AEAD. Как объяснялось ранее, каждый ключ однозначно определяет две функции: \(\mathrm{Enc}\) и \(\mathrm{Dec}\)В набор клавиш теперь также задаются две новые функции: \(\mathrm{Enc}\) и \(\mathrm{Dec}\) - \(\mathrm{Enc}\) просто равна функции \(\mathrm{Enc}\) основного ключа набора ключей, в то время как функция \(\mathrm{Dec}\) пытается расшифровать данные со всеми ключами, проходясь по ним в определенном порядке (см. ниже , как Tink повышает производительность этого процесса).
Интересно отметить, что наборы ключей представляют собой полные ключи : они дают полное описание функций. \(\mathrm{Enc}\) и\(\mathrm{Dec}\) используется. Это означает, что пользователи могут написать класс, который принимает на вход KeysetHandle , выражая идею о том, что классу необходимо полное описание объектов. \(\mathrm{Enc}\) и \(\mathrm{Dec}\) для корректной работы . Это позволяет пользователю писать API, которые сообщают: чтобы использовать этот класс, вам необходимо предоставить мне описание криптографического примитива.
Вращение ключа
Рассмотрим пользователя Tink, пишущего программу, которая сначала получает набор ключей из KMS, затем создает объект AEAD на основе этого набора ключей и, наконец, использует этот объект для шифрования и дешифрования зашифрованных данных.
Такой пользователь автоматически подготовлен к смене ключа и переключению алгоритмов в случае, если текущий выбор больше не соответствует стандартам.
Однако при реализации такой ротации ключей следует проявлять некоторую осторожность: сначала KMS должен добавить новый ключ в набор ключей (но пока не устанавливать его в качестве основного). Затем новый набор ключей необходимо распространить на все исполняемые файлы, чтобы каждый исполняемый файл, использующий этот набор ключей, имел самый новый ключ в наборе. Только после этого новый ключ следует сделать основным, и полученный набор ключей снова распространить на все исполняемые файлы, использующие этот набор ключей.
Ключевые идентификаторы в зашифрованных текстах
Рассмотрим еще раз пример набора ключей AEAD. При наивном подходе расшифровка зашифрованного текста потребует от Tink попытки расшифровки с использованием всех ключей из набора, поскольку невозможно узнать, какой ключ использовался для шифрования. Это может привести к значительным накладным расходам на производительность.
Поэтому Tink позволяет добавлять к зашифрованным текстам префикс в виде 5-байтовой строки, полученной из идентификатора. Следуя философии «полных ключей», описанной выше, этот префикс является частью ключа , и все зашифрованные тексты, когда-либо полученные с помощью этого ключа, должны иметь этот префикс. При создании ключей пользователи могут выбрать, должен ли ключ использовать такой префикс или же следует использовать формат зашифрованного текста без него.
Когда ключ находится в наборе ключей, Tink вычисляет этот тег на основе идентификатора ключа в наборе ключей. Тот факт, что идентификаторы уникальны в пределах набора ключей, подразумевает уникальность и тегов . Следовательно, если используются только ключи с тегами, потери производительности по сравнению с расшифровкой с помощью одного ключа отсутствуют: Tink нужно будет попробовать только один из ключей при расшифровке.
Однако, поскольку тег является частью ключа, это также означает, что ключ может находиться в наборе ключей только в том случае, если он имеет один конкретный идентификатор. Это имеет определенные последствия при описании реализации объектов ключей в разных языках.
Ключи, требующие указания идентификатора, но без префикса вывода.
Некоторые ключи должны иметь определенный идентификатор, но не добавляют префикс к своему выводу. Например, ключи подписи с вариантом NO_PREFIX_WITH_PREHASH_ID (хранящиеся с типом префикса вывода WITH_ID_REQUIREMENT ) создают подписи без префикса. При использовании такого ключа с примитивом Prehash , Tink записывает идентификатор ключа в значение prehash , чтобы удаленный подписывающий знал, каким из своих ключей подписывать.
Как и в случае с ключами, использующими префикс, такой ключ может находиться в наборе ключей только под этим одним идентификатором. Идентификатор ключа в значении прехеша представляет собой обычные метаданные, как и выходной префикс: подпись его не связывает, и проверяющие его никогда не видят. Описание структуры на уровне байтов см. в разделе «Формат передачи Tink» .
В некоторых частях Tink наборы ключей по-прежнему рассматриваются как единое целое. Однако это следует изменить. Причина в том, что порядок, как правило, важен: например, рассмотрим типичный жизненный цикл ротации ключей с Aead. Сначала в набор ключей добавляется новый ключ. Этот ключ еще не становится основным, но активен. Этот новый набор ключей распространяется на все бинарные файлы. Как только все бинарные файлы узнают о новом ключе, ключ становится основным (только на этом этапе использование этого ключа безопасно). На этом втором этапе ротации ключей необходимо знать последний добавленный ключ. ↩
Для обеспечения совместимости с внутренней библиотекой Google, Tink позволяет использовать наборы ключей, в которых идентификаторы повторяются. Эта поддержка будет удалена в будущем. ↩