Comments 16
Большое спасибо. Отличная статья! Сам в свое время занимался подобными разработками, правда спускаться до пространства пользователя не было необходимости. И так же, как и Вы, изучал это Crypto API по исходникам ядра))
+2
А как бы вы посоветовали реализовать операцию диверсификации ключа?
Регистрировать новый алгоритм для этого?
Или есть возможность реализовать свой шаблон?
Регистрировать новый алгоритм для этого?
Или есть возможность реализовать свой шаблон?
+1
Хороший вопрос. В своё время у нас тоже появлялась необходимость в такой операции, но, в итоге, мы решили реализовать и применять её во «фронтенде». То есть Crypto API лишь обрабатывает данные на некотором, установленном ранее, ключе. А вот та часть, что непосредственно этот ключ устанавливает — проводит диверсификацию, не обращаясь для этого к Crypto API.
Насчёт регистрации нового алгоритма не уверен, поскольку в Crypto API нет подходящего для диверсификации типа преобразования. И да, я забыл написать об это в статье, но возможность реализовать свой шаблон похоже есть.
Насчёт регистрации нового алгоритма не уверен, поскольку в Crypto API нет подходящего для диверсификации типа преобразования. И да, я забыл написать об это в статье, но возможность реализовать свой шаблон похоже есть.
0
Спасибо огромное! Сейчас как раз есть необходимость погрузиться в эту тему и тут ваша статья.
0
Здравствуйте, статья актуальна, но к сожалению, на первых строчках есть ошибки к примеру:
При компиляции с помощью GCC при оптимизации -O2 memset будет вырезан и таким образом Ваше «затирание» памяти не произойдёт. Такого рода вещи очень важны при разработке крипто-модулей.
Вот подтверждение (результаты дизассемблирования), компиляция с помощью GCC 7.3 -O2:
Могу порекомендовать вот этот сайт для подобных экспериментов.
Небольшая неточность, Вы забыли преобразование типов (это мелочь), calloc возвращает void*.
void xor_cipher_free(xor_cipher_ctx *ctx)
{
memset(ctx->key, 0xFF, XOR_CIPHER_KEY_SIZE);
free(ctx);
}
При компиляции с помощью GCC при оптимизации -O2 memset будет вырезан и таким образом Ваше «затирание» памяти не произойдёт. Такого рода вещи очень важны при разработке крипто-модулей.
Вот подтверждение (результаты дизассемблирования), компиляция с помощью GCC 7.3 -O2:
xor_cipher_allocate():
mov esi, 16
mov edi, 1
jmp calloc
xor_cipher_free(xor_cipher_ctx*):
jmp free
main:
xor eax, eax
ret
Могу порекомендовать вот этот сайт для подобных экспериментов.
Небольшая неточность, Вы забыли преобразование типов (это мелочь), calloc возвращает void*.
xor_cipher_ctx *cipher = calloc(1, sizeof(xor_cipher_ctx));
+1
Спасибо за комментарий.
Да, я знаю о том, что gcc может обрезать такие вызовы и чем это черевато. Здесь, по хорошему, стоило занулить массив в простом цикле for, но я не стал этого делать, что бы не усложнять (пришлось бы объяснять почему gcc вырезает memset). Но упомянуть об этом безусловно стоило. В ближайшее время я постараюсь это исправить (или, вы можете предложить свою редакцию на github)
Насчёт второго — нет, я не забыл. Это преобразование избыточно, поскольку, в этом случае, void* автоматически и безопасно приводится к нужному типу. Литература по системному программированию в Linux также рекомендует (и обосновывает это) избегать явного приведения типов в таких случаях.
Да, я знаю о том, что gcc может обрезать такие вызовы и чем это черевато. Здесь, по хорошему, стоило занулить массив в простом цикле for, но я не стал этого делать, что бы не усложнять (пришлось бы объяснять почему gcc вырезает memset). Но упомянуть об этом безусловно стоило. В ближайшее время я постараюсь это исправить (или, вы можете предложить свою редакцию на github)
Насчёт второго — нет, я не забыл. Это преобразование избыточно, поскольку, в этом случае, void* автоматически и безопасно приводится к нужному типу. Литература по системному программированию в Linux также рекомендует (и обосновывает это) избегать явного приведения типов в таких случаях.
0
Цикл for точно так же может быть вырезан.
0
Проверил, при компиляции с -O3 "for" действительно вырезается.
Для Linux нашёл такой вариант надёжного мемсета:
void memset_s(void *v, int c, size_t n)
{
volatile unsigned char *p = (unsigned char*)v;
while(n--)
{
*p++ = c;
}
}
Этот не вырезается даже на O3.
0
Всё ещё проще, volatile в сигнатуре функции (именно на память):
Работает на GCC 7.3 -O2 и -O3.
void xor_cipher_free(xor_cipher_ctx* volatile ctx)
{
memset(ctx->key, 0xFF, XOR_CIPHER_KEY_SIZE);
free(ctx);
}
Работает на GCC 7.3 -O2 и -O3.
+1
Можно сделать чуть эффективнее:
А вообще в C11 функция memset_s предусмотрена стандартом, но, кажется, ни один компилятор ее так и не реализовал.
void *(*volatile memset_s)(void *, int, size_t) = memset;
А вообще в C11 функция memset_s предусмотрена стандартом, но, кажется, ни один компилятор ее так и не реализовал.
0
А разве использование Crypto API из userspace не будет заведомо медленнее собственной реализации (да даже того же OpenSSL)? Ведь нужно копирование блоков в kernel-space и обратно.
0
Поэтому к Crypto API из юзерспейса можно обратиться через системные вызовы splice/vmsplice, это помогает избежать такого копирования. Подробнее смотрите здесь.
А вообще, возможно, вы подбросили мне идею для ещё одной статьи)
А вообще, возможно, вы подбросили мне идею для ещё одной статьи)
0
Sign up to leave a comment.
Расширение и использование Linux Crypto API