Давайте сначала определить множество возможных проблем, а затем попытаться решить. У нас есть некоторые данные (запись) и подпись. Подпись может быть вычислена с помощью разных алгоритмов. Программа может развиваться и изменять свое поведение, libsodium также может (независимо) развиваться и изменять свое поведение. На фронте формирования подписи мы имеем:
crypto_sign()
, который использует алгоритм некоторые по умолчанию для создания подписей (на момент написания только вызывает crypto_sign_ed25519()
)
crypto_sign_ed25519()
, которая производит подписи на основе конкретного ed25519
алгоритма
Я предполагаю, что для одного конкретного алгоритма с учетом тех же входных данных и того же ключа мы всегда получим тот же результат, что и его математика, и любое отклонение от этого правила сделает библиотеку полностью непригодной.
Давайте рассмотрим два основных варианта:
- Использование
crypto_sign_ed25519()
все время, и никогда не меняется в этом. Не так уж плохо, потому что это просто и до тех пор, пока в libsodium существует crypto_sign_ed25519()
, и он стабилен в своем выпуске, вам не о чем беспокоиться со стабильной фиксированной подписью и нулевыми накладными расходами для этого. Конечно, в будущем кто-то может обнаружить какую-то ужасную проблему с этим алгоритмом, и если вы не готовы изменить алгоритм, который может означать ужасную проблему для вас.
- Использование
crypto_sign()
. С этим у нас внезапно возникает много проблем, потому что алгоритм может измениться, поэтому вы должны хранить некоторые метаданные вместе с подписью, которая открывает набор вопросов:
- Что хранить?
- должны ли эти метаданные быть уровня записи или уровня файла?
Что мы имеем в упомянутых функций для второго подхода?
sodium_library_version_major()
- это функция, чтобы сообщить нам версию API-библиотеки. Это напрямую не связано с изменениями в поддерживаемых/дефолтных алгоритмах, поэтому это мало полезно для наших проблем.
crypto_sign_primitive()
- это функция, которая возвращает строку, идентифицирующую алгоритм, используемый в crypto_sign()
. Это идеальное совпадение с тем, что нам нужно, потому что, предположительно, его выход изменится точно в то время, когда алгоритм изменится.
crypto_sign_bytes()
- это функция, которая возвращает размер подписи, созданной crypto_sign()
в байтах. Это полезно для определения объема хранилища, необходимого для подписи, но он может легко оставаться неизменным, если алгоритм изменяется, поэтому метаданные, которые нам нужно хранить явно, не обязательно.
Теперь, когда мы знаем, что хранить, возникает вопрос обработки хранимых данных. Вам нужно получить имя алгоритма и использовать его для вызова соответствующей функции проверки. К сожалению, из того, что я вижу, сам libsodium не предоставляет какой-либо простой способ получить правильную функцию, учитывая имя алгоритма (например, EVP_get_cipherbyname()
или EVP_get_digestbyname()
в openssl), поэтому вам нужно сделать это самостоятельно (что, конечно же, должно быть неудачным для неизвестного имени). И если вам нужно сделать это самостоятельно, возможно, было бы еще проще хранить некоторый числовой идентификатор вместо имени из библиотеки (хотя бы код).
Теперь давайте вернемся к уровню файлового уровня и уровню записи. Чтобы решить, есть еще два вопроса, чтобы задать —, вы можете генерировать новые подписи для старых записей в любой момент времени (это технически возможно, это разрешено политикой), и вам нужно добавить новые записи в старые файлы?
Если вы не можете создавать новые сигнатуры для старых записей или вам необходимо добавить новые записи и не хотите, ухудшая производительность регенерации подписи, то у вас нет выбора, и вам нужно:
- имеет поле динамического размера для вашей подписи
- магазина алгоритм (динамическое поле строки или внутреннее (для приложения) ID) используется для создания подписи вместе с самой подписью
Если вы можете создать новые подписи или especi если вам не нужно добавлять новые записи, тогда вы можете уйти с более простым подходом к файловому уровню, когда вы храните алгоритм, используемый в специальном поле уровня файла, и, если алгоритм подписи изменяется, регенерируйте все подписи при сохранении файл (или использовать старый при добавлении новых записей, это также вопрос политики совместимости).
Другие варианты? Ну, что такого особенного в crypto_sign()
? Дело в том, что его поведение не под вашим контролем, разработчики libsodium выбирают для вас алгоритм (без сомнения, они выбирают хороший), но если у вас есть какая-либо информация о версии в вашей файловой структуре (не подписи, я имею в виду), ничто не мешает вам делая свой собственный выбор и используя один алгоритм с одной версией файла, а другой с другим (с кодом конверсии, когда это необходимо, конечно). Опять же, это также основано на предположении, что вы можете создать новую подпись, и это разрешено политикой.
Это возвращает нас к первоначальным двум вариантам с вопросом о том, стоит ли делать все это по сравнению с использованием только crypto_sign_ed25519()
. В основном это зависит от продолжительности вашей программы, я бы, наверное, сказал (как мнение), что если это менее 5 лет, проще просто использовать один конкретный алгоритм. Если это может быть легко более 10 лет, то нет, вам действительно нужно уметь выжить алгоритм (и, возможно, даже целая крипто библиотека).
Else полностью. Всякий раз, когда вы обновляете свою библиотеку, убедитесь в совместимости или обновите шифрование данных (да, значит, дешифруйте со старым, зашифруйте с новым). Вариант состоит в том, чтобы придерживаться старой версии. Не то чтобы я думал, что libsodium dev's будет несовместимым с алгоритмом без какой-либо головы. – user430051
Я не уверен, что я следую. Когда вы говорите «обновить шифрование данных», вы имеете в виду повторное подписание старых записей с новым алгоритмом? Я боюсь, что это не сработает, поскольку у меня (как у разработчика) нет доступа к секретным ключам пользователей. Эти пользователи и их ключи могут даже долго уйти, когда (если) libsodium изменяет алгоритм в будущем. –