[gnupg-ru] На пути к полноценной поддержке ГОСТ в GnuPG
Paul Wolneykien
manowar на altlinux.org
Ср Июл 25 12:18:48 CEST 2018
25.06.2018 19:53, Paul Wolneykien пишет:
> 23.06.2018 16:07, Dmitrii Tcvetkov пишет:
>>> Здравствуйте, уважаемые подписчики. Представляю вашему вниманию
>>> небольшой шаг в сторону поддержки цифровой подписи ГОСТ в GnuPG.
Здравствуйте. В новой итерации, в дополнение к поддержке цифровой
подписи по ГОСТ, я добавил поддержку ГОСТового шифрования
(enсrypt/decrypt) данных. Это потребовало:
1. Прежде всего, реализации алгоритмов VKO GOST (RFC 4357) внутри
Libgcrypt. Реализацию сделал прозрачную — в том смысле, что данные
операции доступны снаружи через стандартные gcry_pk_encrypt() /
gcry_pk_decrypt(). Единственное, о чём нужно помнить, что таким способом
шифруются (расшифровываются) не данные, а симметричный ключ, который
затем используется для собственно шифрования (расшифрования) данных.
Обновлённый патч доступен по адресу:
http://git.altlinux.org/people/manowar/packages/?p=libgcrypt.git;a=blob;f=libgcrypt-1.8.2-gost.patch;h=2cf069617f12efab3ef8289384eb9c91ec7ef9ed;hb=5b3d051a59d95628943f3597068e393a8f6eb1df
.
2. Добавить в GnuPG отдельную (от Libgcrypt) реализацию
размаскирования ключа (key unwrap). Это вызвано тем обстоятельством, что
данная реализация в целом рассчитана, пока что, на использование
совместно с аппаратными токенами. Операция же выработки общего ключа с
помощью токена включает в себя и его так называемую диверсификацию. По
этой причине, алгоритм размаскирования симметричного ключа, связанный с
аппаратным токеном (через gpg-агент) оказывается урезанным по сравнению
с аналогичной операцией, реализованной мной в Libgcrypt. Кроме этого
момента, для ВКО ГОСТ в GnuPG потребовалось реализовать отдельную
обвязку вокруг вызова gcry_pk_encrypt(), поскольку стандартная обвязка
рассчитана на работу с ECC shared point и ничего не знает об UKM.
Обновлённый патч доступен по адресу:
http://git.altlinux.org/people/manowar/packages/?p=gnupg2.git;a=blob;f=gnupg-2.2.8-gost.patch;h=a4ab5be731bc72536e5eea360c97185c5801dd6f;hb=a72c8dd7e206bfbbc1239fa9d7f32d7ec09808ca
.
3. В части работы со смарт-картами (токенами) потребовалось сделать
две вещи: использовать механизм выработки общего ключа
(CKM_GOSTR3410_DERIVE) со стороны gnupg-pkcs11-scd (включая сюда
подготовку бинарных данных UKM + публичный ключ с правильным порядком
байт) и реализовать вызов этого механизма в libpkcs11-helper, причём с
поддержкой ГОСТовой специфики. По аналогии с Libgcrypt, я решил не
добавлять в libpkcs11-helper отдельный тип операции "derive", а сделал
его частным случаем "decrypt".
Обновлённые патчи доступны по адресам:
http://git.altlinux.org/people/manowar/packages/?p=gnupg-pkcs11-scd.git;a=blob;f=gnupg-pkcs11-scd-0.9.2-gost.patch;h=e167433b02823324544c169d04a1fda5597f47b6;hb=8ba10a0014a7f0d1d69dcb29f3fbd708b56ecee4
и
http://git.altlinux.org/people/manowar/packages/?p=libpkcs11-helper.git;a=blob;f=libpkcs11-helper-1.22.0-gost-derive.patch;h=f64fe32a52c6a5abb784494347f4211c97e69b6c;hb=cddda377cc0a3c3aba2b806e47323f9f98aab95c
соответственно.
Реализация проверена на работоспособность (подпись + шифрование /
расшифровка + проверка) совместно с токенами "Рутокен ГОСТ ECP".
Из интересного. Алгоритм диверсификации ключа, реализованный в
настоящее время в OpenSSL (engines/ccgost) скорее всего содержит в себе
ошибку. Либо же ошибку содержит реализация на "Рутокен". Дело же в том,
что одинаковый результат диверсификации мне удалось получить только
после того, как я перевернул UKM (точнее, использовал его в обратном
порядке). Применительно к OpenSSL это выглядит так:
--- a/openssl/engines/ccgost/gost_keywrap.c
+++ b/openssl/engines/ccgost/gost_keywrap.c
@@ -35,7 +35,7 @@ void keyDiversifyCryptoPro(gost_ctx * ctx, const
unsigned char *inputKey,
for (j = 0, mask = 1; j < 8; j++, mask <<= 1) {
k = ((u4) outputKey[4 * j]) | (outputKey[4 * j + 1] << 8) |
(outputKey[4 * j + 2] << 16) | (outputKey[4 * j + 3] <<
24);
- if (mask & ukm[i]) {
+ if (mask & ukm[7 - i]) {
s1 += k;
} else {
s2 += k;
Подробная информация о списке рассылки Gnupg-ru