2023-01-12

Tor v3

Как обычно, несколько месяцев назад разобрался как получать ключи torv3 (и хранить их компактно) и уже всё забыл потому что не записал. Сама задача вроде простая. В системе tor v3 поменялся алгоритм формирования адресов .onion - и теперь там не sha1+rsa а es25519. Системы генерации "красивых" адресов вроде mkp224o выдают длиннющие последовательности из получившегося имени, приватного ключа, публичного ключа. А уж если это надо ещё и хранить... Фактически достаточно хранить всего 32 байтика на ключ (seed) - а уже из этого получать и приватный ключ, и публичный, и domain name. Кстати очень похожий подход в yggdrasil, только там "ванильные" ключи суть те, у кого начальная часть много нулей в начале, или какая-то красивая последовательность внутри из шестнадцатеричных чисел. Ну а ещё лучше те и другие критерии вместе. Как обычно люблю делать всё это на perl - а в итоге пришлось влезать в .xs - так как в Crypto::Ed25519 не хватило функций для работы с ключаим (потребовалась возможность влезать внутрь некоторых бывших атомарных операций над ключом). Итак, суть алгоритма ed25519. Генерируется некая случайная последовательность 256 бит (или 32 байта). Это наш seed. Фактически это уже можно считать нашим "секретным ключом", и некоторые разработчики его так и воспринимают. seed преобразуется в keypair. Вся магия вот в этой функции (выдрана из Crypt-Ed25519-1.05-0/ed25519/src/keypair.c).
void ed25519_create_keypair(unsigned char *public_key,
           unsigned char *private_key, const unsigned char *seed) {
    ge_p3 A;

    sha512(seed, 32, private_key);
    private_key[0] &= 248;
    private_key[31] &= 63;
    private_key[31] |= 64;

    ge_scalarmult_base(&A, private_key);
    ge_p3_tobytes(public_key, &A);
}
То есть считается private_key = sha512(seed), фиксируются несколько бит и проводятся операции над curve25519 и в итоге получаем public_key. Вот после sha512 и битовыми операциями - получаем так называемый expanded_key. И private key от tor v3 собственно и есть этот expanded_key. А. Теперь вспомнил почему забросил эту тему :) Вместо того, чтобы показать seed размером 32 байта - mkp224o показывает нам кучу всего ненужного: expanded_key размером 64 байта, public_key в 32 байта, который получается из expanded, и onion адрес, который производный от public_key (+ байт версии и 2 байта хешсуммы в конце). Так что хранить придётся 64 байта на ключ или перезапускать mkp224... Печаль.

2021-04-07

BLAKE3 (надеюсь доступно)

Чуток поковырялся с хеш алгоритмом BLAKE3.

Интересный хеш. Криптографически стойкий (пока не доказана эффективность но и обратного тоже нет). Но быстрее SHA-256, SHA-512, SHA1 и даже MD5.

Из полезного.

0. Очень быстрый алгоритм.
Операции проводятся над 32-битными целыми числами без знака.
Используются только операции:
ADD сложение "+",
XOR исключающее-или "^",
ROR циклический сдвиг ">>",
операция перемешивания слов по фиксированной таблице (всего 16 значений).

Всё это сопровождается весьма малым числом раундов (всего 7).


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

В итоге всё очень хорошо укладывается в целочисленные операции SIMD современных процессоров и их кеш память.

Но и этого разработчикам показалось мало, так как алгоритм ещё и практически неограниченно распараллеливается из-за использования бинарного дерева Меркла (блоками по 1024 байта).

1. Произвольная длина хеша. От 256 бит (32 байта) до... вам по пояс будет. Де-факто можно использовать как генератор псевдослучайных чисел - причём очень быстрого (см. п.0) блоками по 64 байта. Остаётся маленький шажок до шифрования.

2. Встроенные алгоритмы деривации (наследования) ключей KDF и MAK. Кому это надо - знают зачем. См. п.0. Фактически проводится стандартные раунды хеширования, меняются только флаги (и/или используется хеш ключевого материала в поле CV вместо IV).

3. При хранении значений бинарного дерева произвольного уровня можно не пересчитывать весь хеш заново (при отсутствии изменений внутри некоторых блоков(. Похоже на то, что используется в BitTorrent (там считается и хранится SHA1 хеш каждого блока отдельно), TTH и AICH. Но в отличии от них - хеши одинаковых блоков будут разными, если они находятся по разным смещениям (внутри блока состояния, участвующего в вычислении хеша есть меняющийся счётчик 1024-байтных блоков-чанков).

Ещё раз - алгоритм ОЧЕНЬ быстрый. Быстрее даже MD5. Авторы обещают, что большая длинна хеша важнее количества раундов - и алгоритм пройдёт инспекцию криптоаналитиков.
Очень на это надеюсь. И думаю что за алгоритмом есть хорошее будущее.

== tldr; BEGIN ==

Из плохого. Рефренная реализация на языке rust. Быстрая SIMD реализация b3sum и библиотека blake3 - на языке rust. Готовых модулей Perl пока нет. Встречались реализации на других языках (C#/Blake3.NET .NET 5.0 wtf), но они использовали внешнюю библиотеку blake3 на rust.

Зато есть реализация на C, но тоже оптимизированная под SIMD и с ассемблерным кодом под разные платформы/ассемблеры - но не многопоточная (хотя и это и не помогло в понимании работы алгоритма), однако позволило сделать версию под VS с выдачей отладочной информации о входах-выходах функции компрессии и изменениях внутреннего состояния в ней. Заодно пришло понимание запутанности C реализации из-за алгоритмических оптимизаций (гораздо больше почти однотипных на первый взгляд функций чем в рефрене) и куча кода непонятного на первый взгляд назначения.

В итоге таки пришлось чуток поплавать по поверхности этого странного языка, так как его рефренную реализацию оказалось проще понять и использовать для реализации на Perl. Многое в простом rust коде было понятно даже без начальных знаний о языке - а код на C был в этом лишь подспорьем.

Установка среды rust, настройка окружения, первая сборка. Копание в библиотеке blake3. Первый println! внутри функции компрессии. И до готового решения (очень пока грязного - не нашёл способа как потокобезопасно передавать открытые файлы вглубь функций, которые делают параллельные вычисления) чтобы b3sum выдала в mailslot на perl дерево Меркла блоков файла (который кладёт это дерево в sqlite базу). Переписывание библиотеки Win32::Mailslot - понимание того, что я не знаю perl xs и не знаю как её поправить чтобы понимала строки с нулями. Как использовать функцию newSVpn если нет нормальных примеров а автор Mailslot про неё вообще не знал (он честно сказал что это его первый подход к XS - и судя по коду он нормально знал только msvc). Неспроста этого модуля нет в cpan. Но тут вспомнил про Win32API::File - спасибо автору за чистый и понятный код, который я уже когда-то даже правил (очень нужная мне в моей считалке хешей функция SetEndOfFile).

И в итоге b3sum уделывает мою старую считалку стоя и в рост (которую, как я думал, ограничивает лишь производительность диска) - даже с чудовищно вкряченным и отвратительным решением, с тремя переходами на unsafe код и обратно, открывающим и закрывающим mailslot на каждый чих расчёта суммы блока дерева.

== tldr; END ==

Итак. Алгоритм BLAKE3.

Используемые обозначения:
блок - 64 байта, обработка хешируемых данных идёт такими "кусочками". Может быть меньше, если входных данных не хватает - тогда недостающая часть заполняется нулями до 64 байт.
чанк - 1024 байта (1 килобайт или по рекомендациям МЭК кибибайт 1 КиБ или KiB) - набор из 16 блоков по 64 байта. Может быть меньше (до 1), если блоков не хватает. Используется для "нулевого" уровня дерева Меркла - хеши чанков попарно объединяются для получения корневого хеша.
u8/u32/u64 - беззнаковые целые, соответственно 8 бит (байт), 32 бита (двойное слово, DWORD), 64 бита (unsigned long, QWORD).

1. IV инициализационный вектор - 256 бит или 8 u32.
Он используется много где - гугл даёт ссылки на него же в SHA256 и BitCoin - пишут это набор первых 32 бит дробной части (иррациональных) квадратных корней простых чисел по возрастанию: 2, 3, 5, 7, 11, 13, 17, 23):

67e6096a85ae67bb72f36e3c3af54fa57f520e518c68059babd9831f19cde05b

Ну или как он же записан как u32 в шестнадцатеричном виде:

const IV: [u32; 8] = [
  0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
  0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
];

Он используется как ключ (первые 4 u32 - кроме случаев MAK и KDF) и как начальный CV каждого чанка (все 8 слов).

2. Функция компрессии compress.

На вход подаются:

    $block_words,    # [u32; 16]
    $chaining_value, # [u32; 8]
    $counter,        # u64
    $block_len,      # u32
    $flags,          # u8

block_words - блок хешируемых данных (512 бит / 64 байт / 16 u32).
Zero filled: если данных не достаточно (менее 64 байт), остаток блока заполняется нулями до 64 байт. Пустой блок соответственно 64 нулевых байта.

chaining_value - значение хеша предыдущего 64-байтного блока (256 бит / 8 u32).
Сюда же подсовывается IV для первого блока или хеш ключа для HMAK/KDF.

counter - счётчик 1024-байтных чанков (chunks, тут используются как блоки дерева Меркла) (64 бита / 1 u64). Для цепочки из 64-байтных блоков внутри одного чанка этот счётчик не изменяется. Для компрессии пар хешей (с флагом "PARENT") тут ставят ноль. Для получения "продолжения" корневого (выходного) хеша - используется как инкрементный счётчик.

block_len - длина блока данных (block_words) в байтах. Отведено 32 бита, но размер блока ограничен числом 64 (0x40). Компрессия пар хешей в дереве Меркла - 2 хеша по 32 байта итого те же 64 байта. Если обрабатывается "хвост" файла (или сам файл короткий) - может быть число меньше 64 (вплоть до 0 для пустого блока).

flags - тоже расширяется до 32 бит, но в алгоритме сейчас используются только 7 бит.
Возможные значения и назначения битовых полей flags (константы):
CHUNK_START 1 << 0 (x01)
        начальный блок чанка
CHUNK_END 1 << 1 (x02)
        конечный блок чанка
PARENT         1 << 2 (x04)
        признак компрессии хешей в дереве меркла
ROOT         1 << 3 (x08)
        выходной "корневой" узел (получение итогового хеша)
KEYED_HASH 1 << 4 (x10)
        признак KDF (вместо IV для CV берётся хеш ключа)
DERIVE_KEY_CONTEXT  1 << 5 (x20)
        признак HMAK (вместо IV для CV берётся хеш статического ключа)
DERIVE_KEY_MATERIAL 1 << 6 (x40)
        хеширование ключа для HMAK/KDF

Флаги объединяются по ИЛИ. Например для короткого чанка (до 64 байт):
    CHUNK_START | CHUNK_END  = x03
Если это окажется ещё и выходной хеш (для короткого или пустого файла):
    CHUNK_START | CHUNK_END | ROOT = x0B

Функция компрессии собирает из входных значений блок внутреннего состояния (state) и он будет модифицироваться функцией g на основе хешируемых данных (block_words). Сами данные перемешиваются функцией permute между раундами хеширования.

Размер блока state тот же, что и блок данных - 64 байта или 16 DWORD.

CVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCVCV
IVIVIVIVIVIVIVIVIVIVIVIVIVIVIVIVCCCCCCCCCCCCCCCCSSSSSSSSFLFLFLFL
CV - хеш предыдущего блока chaining_value,
IV - "ключ" хеша - первые 4 слова IV,
CC - счётчик чанков counter (u64),
SS - размер блока данных block_len (0-64),
FL - флаги блока flags

Для примера, вот state начального блока нулевого чанка файла:
67e6096a85ae67bb72f36e3c3af54fa57f520e518c68059babd9831f19cde05b
67e6096a85ae67bb72f36e3c3af54fa500000000000000004000000001000000
CV=IV, CC=0, SS=x40 (64 байта), FL=01 (CHUNK_START)

Затем блок state подвергается 7 одинаковым раундам компрессии с последующим перемешиванием входных данных block:
    round(&mut state, &block); // round 1
    permute(&mut block);
    round(&mut state, &block); // round 2
    permute(&mut block);
    round(&mut state, &block); // round 3
    permute(&mut block);
    round(&mut state, &block); // round 4
    permute(&mut block);
    round(&mut state, &block); // round 5
    permute(&mut block);
    round(&mut state, &block); // round 6
    permute(&mut block);
    round(&mut state, &block); // round 7

Старшие 8 слов state накладываются (через XOR) на младшие 8 слов state и результат используется в дальнейшем как "промежуточный" 256-битный хеш блока, а на старшие 8 слов (тоже через XOR) накладывается входной хеш CV (чтобы сформировать очередной 64 байтный кусок выходного хеша).

Отсутствие необходимости накладывать и хранить входной хеш CV на "старшие" 32 байта выходного хеша и даёт разделение "оптимизированных" алгоритмов на похожие внешне функции compress_inplace (меняет входной массив CV на выходной хеш и ничего не возвращает) и compress_xof (возвращает 64 байта "полного" хеша но не трогает входной хеш).

Для полноты картины приведу все три "внутренних функции": g, round, permute.

// The mixing function, G, which mixes either a column or a diagonal.
fn g(state: &mut [u32; 16],
    a: usize, b: usize, c: usize, d: usize, mx: u32, my: u32) {
    state[a] = state[a] + state[b] + mx;
    state[d] = rotr32(state[d] ^ state[a], 16);
    state[c] = state[c] + state[d];
    state[b] = rotr32(state[b] ^ state[c], 12);
    state[a] = state[a] + state[b] + my;
    state[d] = rotr32(state[d] ^ state[a], 8);
    state[c] = state[c] + state[d];
    state[b] = rotr32(state[b] ^ state[c], 7);
}

fn round(state: &mut [u32; 16], m: &[u32; 16]) {
    // Mix the columns.
    g(state, 0, 4,  8, 12, m[0], m[1]);
    g(state, 1, 5,  9, 13, m[2], m[3]);
    g(state, 2, 6, 10, 14, m[4], m[5]);
    g(state, 3, 7, 11, 15, m[6], m[7]);
    // Mix the diagonals.
    g(state, 0, 5, 10, 15, m[8], m[9]);
    g(state, 1, 6, 11, 12, m[10], m[11]);
    g(state, 2, 7,  8, 13, m[12], m[13]);
    g(state, 3, 4,  9, 14, m[14], m[15]);
}

const MSG_PERMUTATION: [usize; 16] =
[2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8];

fn permute(m: &mut [u32; 16]) {
    let mut permuted = [0; 16];
    for i in 0..16 {
        permuted[i] = m[MSG_PERMUTATION[i]];
    }
    *m = permuted;
}

Необходимые примечания:
Все операции проводят над беззнаковыми целыми 32-битными числами u32.

Сложение в функции g допускает переполнение данных - следует это игнорировать. Если компилятор языка программирования пытается как-то обработать это событие (как rust) приходится использовать обработчик, например: a.wrapping_add(b).wrapping_add(с);.

Циклический сдвиг вправо rotr32 часто реализуется в железе процессоров, но в языках программирования обычно приходится его имитировать:
rotr32($w, $c) {
    return ($w >> $c) | ($w << (32 - $c))
}
У rust есть w.rotate_right(c), но без знания языка думаю проще так, как я привёл в алгоритме.
Работающую реализацию для rust берите из рефрена.

2. Работа алгоритма.
Для примера - файл из 4 КиБ нулей.

Чанк 0:

Блок 0:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s67e6096a85ae67bb72f36e3c3af54fa57f520e518c68059babd9831f19cde05b67e6096a85ae67bb72f36e3c3af54fa500000000000000004000000001000000
=9231a599f35b97d564eb5fdfa8ff50b7387df3bba731d079a2bdfc062c391746
В поле CV=IV, flag=01 (CHUNK_START). CC=0, SS=64. Результат уходит в CV следующего блока.

Блок 1:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s9231a599f35b97d564eb5fdfa8ff50b7387df3bba731d079a2bdfc062c39174667e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=51df97ebd73fca0cbdb54464751250262e10e08821594a95a733d850472be538
В поле CV перешло значение хеша предыдущего блока, flag=00 (нет флагов - это ни начальный блок, ни конечный блок). CC=0, SS=64. Результат уходит в следующий блок.

Блок 2:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s51df97ebd73fca0cbdb54464751250262e10e08821594a95a733d850472be53867e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=c96ad7d259f51db5a0a588aa0dccb1aefc96ed2be293492ee57cb9af3dce3fcb

Блок 3:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sc96ad7d259f51db5a0a588aa0dccb1aefc96ed2be293492ee57cb9af3dce3fcb67e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=dc31895819eb00eff3ce2fe529ec6b62e82235af29a3079c4d6973e859d47f29

Блок 4:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sdc31895819eb00eff3ce2fe529ec6b62e82235af29a3079c4d6973e859d47f2967e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=d33a742003892cace13957e2aa6e62678e217d02d1cfab903df7497f1547a339

Блок 5:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sd33a742003892cace13957e2aa6e62678e217d02d1cfab903df7497f1547a33967e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=cb8e7ad10ab1278aa325c60fdc80cb08dd6817fcebaf6d8d530dacf465d391af

Блок 6:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
scb8e7ad10ab1278aa325c60fdc80cb08dd6817fcebaf6d8d530dacf465d391af67e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=55f4038fbe2a8a69c82bc85921eb13383ece3a00efbb55e094c7de109a32a06b

Блок 7:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s55f4038fbe2a8a69c82bc85921eb13383ece3a00efbb55e094c7de109a32a06b67e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=cdccced87c71be1ddce70a516d4e7fe999db28a305dd24ec000df3b9814f06be

Блок 8:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
scdccced87c71be1ddce70a516d4e7fe999db28a305dd24ec000df3b9814f06be67e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=1fd462eceb0f82406066ade50b951b1e6444e0d29bcd52ebea1dafcd7187e641

Блок 9:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s1fd462eceb0f82406066ade50b951b1e6444e0d29bcd52ebea1dafcd7187e64167e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=c42e11b60b4990b7a98d51413e45c2b0975fb169744a1e140ae269e55f9b4762

Блок 10:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sc42e11b60b4990b7a98d51413e45c2b0975fb169744a1e140ae269e55f9b476267e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=7c27dde46486e97ed86b80fd0dc006d069aeef9fc2e59fe7decbf28d21a15ec8

Блок 11:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s7c27dde46486e97ed86b80fd0dc006d069aeef9fc2e59fe7decbf28d21a15ec867e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=73fbc93b838ed503ff81772684f5006e3ddd3ce5328404ce9dd091c4118abd78

Блок 12:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s73fbc93b838ed503ff81772684f5006e3ddd3ce5328404ce9dd091c4118abd7867e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=33d13f301543053763674eac769711fbbe2a2ade5ab40ce6b8ff1e5cd086175e

Блок 13:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s33d13f301543053763674eac769711fbbe2a2ade5ab40ce6b8ff1e5cd086175e67e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=c0f0286d206316ed8390232eaa002265703739d896b6f6ba68eb8b4401253529

Блок 14:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sc0f0286d206316ed8390232eaa002265703739d896b6f6ba68eb8b440125352967e6096a85ae67bb72f36e3c3af54fa500000000000000004000000000000000
=4d40bcb0ea55c14046ccb2966abc2ce83f6ff41d319b350da0dd1e2128ed9e55

Блок 15:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s4d40bcb0ea55c14046ccb2966abc2ce83f6ff41d319b350da0dd1e2128ed9e5567e6096a85ae67bb72f36e3c3af54fa500000000000000004000000002000000
=91715ad631c858232d522cc2ff678052288c8c540fc6ab6c5fa5104cb63e0d39
Последний 15 блок чанка 0. flag=02 (CHUNK_END). CC=0, SS=64. Результат - хеш чанка 0 запоминаем его в стеке дерева хешей.
 
Чанк 1:
Блок 16:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s67e6096a85ae67bb72f36e3c3af54fa57f520e518c68059babd9831f19cde05b67e6096a85ae67bb72f36e3c3af54fa501000000000000004000000001000000
=add617a39b1369d50c193577d7dd35155bbfc02569dfc87a9703447110197222
В поле CV снова IV, flag=01 (CHUNK_START). Теперь CC=1, SS=64. Результат уходит в CV следующего блока.

Блок 17:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sadd617a39b1369d50c193577d7dd35155bbfc02569dfc87a970344711019722267e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=358744d9a4600e85e639961a8058462acd4b000f66f1839692a08267d66e78fc
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s358744d9a4600e85e639961a8058462acd4b000f66f1839692a08267d66e78fc67e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=64d3367323e28e75c4cd3c5ca96c2ac36b5636fcd7a370e4769a964907ace752
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s64d3367323e28e75c4cd3c5ca96c2ac36b5636fcd7a370e4769a964907ace75267e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=dab384f0e7dec7573af7b10afa61c4678993fd6264d246fdca09d8ced61c2049
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sdab384f0e7dec7573af7b10afa61c4678993fd6264d246fdca09d8ced61c204967e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=ce358e6066c6790b3d7c9651875884d9ac4e2ceb88245c4ca0d13a04609d9104
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sce358e6066c6790b3d7c9651875884d9ac4e2ceb88245c4ca0d13a04609d910467e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=10e36eb93988e638b53e695d10bd8ee62fe00e800266140f6ed6d7ad793d4819
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s10e36eb93988e638b53e695d10bd8ee62fe00e800266140f6ed6d7ad793d481967e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=5d6d24cabaf7592c136ad1c3b741da309cfdb170ae1f56d7ab73c03999122823
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s5d6d24cabaf7592c136ad1c3b741da309cfdb170ae1f56d7ab73c0399912282367e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=1b45267e4479190c15ec38885f556c8d797eb4a06bb1690226e752c3deb76ad7
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s1b45267e4479190c15ec38885f556c8d797eb4a06bb1690226e752c3deb76ad767e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=02e013f1ee88abc5707c5b7e48a65d208a9c80ba7f8eeb8c848d69cd24cd83e6
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s02e013f1ee88abc5707c5b7e48a65d208a9c80ba7f8eeb8c848d69cd24cd83e667e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=bc25b0862aaf09c0ea9a7e06b8de2de4f8042d62ed8d5fd0d735f55ae7e78877
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sbc25b0862aaf09c0ea9a7e06b8de2de4f8042d62ed8d5fd0d735f55ae7e7887767e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=e69759670ca133f45e71b53eb10893bc599c2f0b7a9ec234e6aeedb99cb42d9e
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
se69759670ca133f45e71b53eb10893bc599c2f0b7a9ec234e6aeedb99cb42d9e67e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=17e96554e91e4672088c54cb8cda9e4bef0d6eb03aca535e47320bdf3c4fa623
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s17e96554e91e4672088c54cb8cda9e4bef0d6eb03aca535e47320bdf3c4fa62367e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=c74b056bea8f62c3c3666d9964a3dde21bac2050a1d7efb84df5f0a40fc75fe6
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sc74b056bea8f62c3c3666d9964a3dde21bac2050a1d7efb84df5f0a40fc75fe667e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=ab342e114522c87a27e5dbb4c5e764b5833587234d08d43de7a157a3b75dbfe4
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sab342e114522c87a27e5dbb4c5e764b5833587234d08d43de7a157a3b75dbfe467e6096a85ae67bb72f36e3c3af54fa501000000000000004000000000000000
=8b57c6d0da0f861c83e9dc199f943ebfb53b55817df4f821405373fff2e44381
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s8b57c6d0da0f861c83e9dc199f943ebfb53b55817df4f821405373fff2e4438167e6096a85ae67bb72f36e3c3af54fa501000000000000004000000002000000
=f0eef3b0033abb623278828fcc75f90c65bde353141ec7c6854eae1c515b93ca
Последний блок чанка CC=1. Видим flag=02 (CHUNK_END). Результат функции компрессии - хеш чанка. Помещаем его в стек. Видим в стеке два хеша уровня 0. Можем их сжать на первый уровень.

w91715ad631c858232d522cc2ff678052288c8c540fc6ab6c5fa5104cb63e0d39f0eef3b0033abb623278828fcc75f90c65bde353141ec7c6854eae1c515b93ca
s67e6096a85ae67bb72f36e3c3af54fa57f520e518c68059babd9831f19cde05b67e6096a85ae67bb72f36e3c3af54fa500000000000000004000000004000000
=a04fc7e7e6831a11965e686a56952b0830aadd1555beabcc79b8db5c93e680d3
В данные для сжатия помещаем два хеша - чанка 0 и чанка 1. CV=IV, CC=0, SS (block_len) = 32+32=64 (x40), flag=04 (PARENT). Результат опять помещаем в кеш, но уже уровень хеша 1. 

Чанк 2:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s67e6096a85ae67bb72f36e3c3af54fa57f520e518c68059babd9831f19cde05b67e6096a85ae67bb72f36e3c3af54fa502000000000000004000000001000000
=7f821a86de35c192613c3e103f382ef6a7df07230051086271bb994ff9c0ba39
Видим опять начало, flag=01, CV=IV, CC=2. Всё стандартно.

w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s7f821a86de35c192613c3e103f382ef6a7df07230051086271bb994ff9c0ba3967e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=ebd2d22250f4f6d6e8d7b9fd4ae34beb988b756b5c87a4e7265fa920c0423164
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sebd2d22250f4f6d6e8d7b9fd4ae34beb988b756b5c87a4e7265fa920c042316467e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=05431ccfb5eed2fcdedc84e404d4d0024e54781848d483ee14c8f9bdde554dc6
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s05431ccfb5eed2fcdedc84e404d4d0024e54781848d483ee14c8f9bdde554dc667e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=f79e1f84c89f3f7e95ae8e31c6a1c04f326de78e5653959ac72ee4531060258a
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sf79e1f84c89f3f7e95ae8e31c6a1c04f326de78e5653959ac72ee4531060258a67e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=8c3ee51d6747319d72ad18708215c906bc26b1f90d1cde1eb4cd927e0de508c4
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s8c3ee51d6747319d72ad18708215c906bc26b1f90d1cde1eb4cd927e0de508c467e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=1e063b48476c20245fd23ab63065f9214e5b7ec50e8975ddbd6743a241ff4265
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s1e063b48476c20245fd23ab63065f9214e5b7ec50e8975ddbd6743a241ff426567e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=4d0f586ffa2249a1feb1fe0aed06dc70fe065c4c0ce15fab3236a9477deaf639
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s4d0f586ffa2249a1feb1fe0aed06dc70fe065c4c0ce15fab3236a9477deaf63967e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=698d5aa32a96b4898829718c52ed5715b55a0085caced06f5ff60af9ce688ae1
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s698d5aa32a96b4898829718c52ed5715b55a0085caced06f5ff60af9ce688ae167e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=7000ef9435bf8200074e600d473518eb67c37713f5b23ab61738accab34679a2
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s7000ef9435bf8200074e600d473518eb67c37713f5b23ab61738accab34679a267e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=c3eeef621f954007a33219b9a764ef12853b0565bf8a64bd70ccb9b4e9270707
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sc3eeef621f954007a33219b9a764ef12853b0565bf8a64bd70ccb9b4e927070767e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=9a8bda17191b163ecdad499b6a78d6df069cee3460ae152f40d1848079932ddb
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s9a8bda17191b163ecdad499b6a78d6df069cee3460ae152f40d1848079932ddb67e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=ab33a88ea4b17897e20d47b4196795de5b3e0a241b4d8c6058b4bf12fcc68a66
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sab33a88ea4b17897e20d47b4196795de5b3e0a241b4d8c6058b4bf12fcc68a6667e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=fbee852ea87041e006bc4711b1ee8f6ee867db6b0b7b3e718f143fa215da980f
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sfbee852ea87041e006bc4711b1ee8f6ee867db6b0b7b3e718f143fa215da980f67e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=6d442b7526ec31addc6ea4a9572c152a00b2618f148c819498db6ad6b3df4689
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s6d442b7526ec31addc6ea4a9572c152a00b2618f148c819498db6ad6b3df468967e6096a85ae67bb72f36e3c3af54fa502000000000000004000000000000000
=a933911631986c5bf5eb3d565b8272b7548f06c91243599228fe00a9364a1cdd
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sa933911631986c5bf5eb3d565b8272b7548f06c91243599228fe00a9364a1cdd67e6096a85ae67bb72f36e3c3af54fa502000000000000004000000002000000
=252ebfbe777d31bcfb3180109814eaccf5958ef2878c36bbe1415289dce2b88c
Конец чанка 2, flag=02, результат в кеш.

Чанк 3:
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s67e6096a85ae67bb72f36e3c3af54fa57f520e518c68059babd9831f19cde05b67e6096a85ae67bb72f36e3c3af54fa503000000000000004000000001000000
=14c71b1e1990510bbe49818a62f0a3ee72ac490d314b5029bcac56e577eedcaf
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s14c71b1e1990510bbe49818a62f0a3ee72ac490d314b5029bcac56e577eedcaf67e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=9e03744b1e18ec692bd94f3f0294f5fb430cfb02f6f3403db27318835c83ea8c
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s9e03744b1e18ec692bd94f3f0294f5fb430cfb02f6f3403db27318835c83ea8c67e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=b2de534a865036900d6734d18c0598cb6d73e5e2f8625c2b4e82ce3623a0fa5e
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sb2de534a865036900d6734d18c0598cb6d73e5e2f8625c2b4e82ce3623a0fa5e67e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=19d48611dc5fc81a813227ef8bf18f7ad3daedd6dc55f351bda1e6624d311536
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s19d48611dc5fc81a813227ef8bf18f7ad3daedd6dc55f351bda1e6624d31153667e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=b1f2b77ae67a7d343a6b9fe8038aac43a8abc7918734f2ee0d4c029df6d7fdf5
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
sb1f2b77ae67a7d343a6b9fe8038aac43a8abc7918734f2ee0d4c029df6d7fdf567e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=9572c6222251c613c911350ad6a389756658ee300f4cf39b514f6e2181a2f1b3
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s9572c6222251c613c911350ad6a389756658ee300f4cf39b514f6e2181a2f1b367e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=3dec0615ce2cd5b923e1b72bb65b5b772f9b38f2a9830dc785709c1ba6173bea
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s3dec0615ce2cd5b923e1b72bb65b5b772f9b38f2a9830dc785709c1ba6173bea67e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=2b9098ee566fc965ea341b2d295f2e96239f5efa1c76e72823c488f6527cd3fe
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s2b9098ee566fc965ea341b2d295f2e96239f5efa1c76e72823c488f6527cd3fe67e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=54c54d9be2c8a07abf78f5680d6595670fbab016c909c0584fb138eb0e6a046d
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s54c54d9be2c8a07abf78f5680d6595670fbab016c909c0584fb138eb0e6a046d67e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=234e24b7027729a5012b0fb569addeee90fca6e2aacb2f372cef1a9132a4f90a
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s234e24b7027729a5012b0fb569addeee90fca6e2aacb2f372cef1a9132a4f90a67e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=651d261375454b846f30c6fce47b97538b83838f21f0930e5b791cbc80ac0344
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s651d261375454b846f30c6fce47b97538b83838f21f0930e5b791cbc80ac034467e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=47076480adad22dbb3499bac0e49c4dbd54bedce127ddb95cbb5ba374f16a2cd
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s47076480adad22dbb3499bac0e49c4dbd54bedce127ddb95cbb5ba374f16a2cd67e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=8c56a4205ada710a66652ad28565836dd3d91dbdaa6d8e8667bf93432a40003e
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s8c56a4205ada710a66652ad28565836dd3d91dbdaa6d8e8667bf93432a40003e67e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=caaeee3b896bbfc03543304e8414db7663fbab11032da8d538e1faab4a052f4b
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
scaaeee3b896bbfc03543304e8414db7663fbab11032da8d538e1faab4a052f4b67e6096a85ae67bb72f36e3c3af54fa503000000000000004000000000000000
=127c8d909ba4c62c4806faf54d0025591764138686b9cbb1bdf9c5f62a0408b7
w00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
s127c8d909ba4c62c4806faf54d0025591764138686b9cbb1bdf9c5f62a0408b767e6096a85ae67bb72f36e3c3af54fa503000000000000004000000002000000
=48dc5df2fd74599ae870a2c1086d39fa117aa91084f0687c49c6439c90e31863
Конец чанка 3. flag=02. Хеш в стек и видим там снова два хеша нулевого уровня. Сжимаем.

w252ebfbe777d31bcfb3180109814eaccf5958ef2878c36bbe1415289dce2b88c48dc5df2fd74599ae870a2c1086d39fa117aa91084f0687c49c6439c90e31863
s67e6096a85ae67bb72f36e3c3af54fa57f520e518c68059babd9831f19cde05b67e6096a85ae67bb72f36e3c3af54fa500000000000000004000000004000000
=580f4b19f0952c41fccedc302ae73758cfa2ab094deead97b2c25b6f6829ecd1
Ещё одно сжатие хешей уровня 0. Данные - хеши чанка 2 и чанка 3. CV=IV, CC=0, flag=4 (PARENT).  Результат в стек и видим там два хеша 1 уровня. Сжимаем и их. Поскольку входные данные кончились и стек будет пуст - результат и будет наш корневой хеш.
wa04fc7e7e6831a11965e686a56952b0830aadd1555beabcc79b8db5c93e680d3580f4b19f0952c41fccedc302ae73758cfa2ab094deead97b2c25b6f6829ecd1
s67e6096a85ae67bb72f36e3c3af54fa57f520e518c68059babd9831f19cde05b67e6096a85ae67bb72f36e3c3af54fa50000000000000000400000000c000000
=b6fb73fc46938c981e2b0b4b1ef282adcfc89854d01bfe3972fdc4785b41b2c79a6b6935c6f03d4d7933b9e798a866fc32fa6138b1ab393ee073b3e568a81fa6
Вызываем функцию сжатия хеша. В данных - сжатые хеши уровня 1 чанков 0+1 и 2+3.  
Сжатие "корневое", так что в flags=0C (PARENT=4 | ROOT=8). Результат обрезаем до 32 байт:
b6fb73fc46938c981e2b0b4b1ef282adcfc89854d01bfe3972fdc4785b41b2c7
Это и есть итоговый 256 битный хеш BLAKE3.

Итог. На уровне чанков мы имеем такую картину:
LEVEL 0
CHUNK 0: 91715ad631c858232d522cc2ff678052288c8c540fc6ab6c5fa5104cb63e0d39
CHUNK 1: f0eef3b0033abb623278828fcc75f90c65bde353141ec7c6854eae1c515b93ca

CHUNK 2: 252ebfbe777d31bcfb3180109814eaccf5958ef2878c36bbe1415289dce2b88c
CHUNK 3: 48dc5df2fd74599ae870a2c1086d39fa117aa91084f0687c49c6439c90e31863

LEVEL 1
CHUNK0+1: a04fc7e7e6831a11965e686a56952b0830aadd1555beabcc79b8db5c93e680d3
CHUNK2+3: 580f4b19f0952c41fccedc302ae73758cfa2ab094deead97b2c25b6f6829ecd1

LEVEL 2
ROOT: b6fb73fc46938c981e2b0b4b1ef282adcfc89854d01bfe3972fdc4785b41b2c7

Если интересна тема, дам как меняется состояние при несбалансированном дереве, неполных чанках, MAK, KDF. Чуть позже.

2021-02-25

Подключение iSCSI: Authentication Failure OneWayCHAP / MutualCHAP (Решение)

Имеем:
usb флешка подключается к локальному компу под ubuntu - надо её монтировать в windows. 

Решение с использованием iSCSI target/initiator.

(CAVE) ubuntu 20.04 локальный компьютер (target)
(SERV) windows 10 - удалённый рабочий стол (initiator)

Типовые настройки:

sudo apt install tgt

/etc/tgt/conf.d/usb-flash.cfg:

<target iqn.2020-03.myhost.ru:lun1>
backing-store /dev/disk/by-id/usb-Netac_OnlyDisk_6237111-0:0
initiator-address 192.168.1.30
incominguser iqn.1991-05.com.microsoft:serv.local SecretStringOne
outgoinguser iqn.1991-05.com.microsoft:serv.local SecretStringTwo
</target>

sudo systemctl restart tgt

[192.168.1.30] - адрес SERV
/dev/disk/by-id/usb-Netac_OnlyDisk_6237111-0:0 - root нашего диска - его можно его глянуть когда воткнута флешка - чтобы не угадывать что за /dev/sdxxx назначено системой.

Через gui windows10 iqn.2020-03.myhost.ru:lun1 вижу и можно монтировать (непросто, да).

Задача - монтировать скриптом one-click.
Решение: powershell

Connect-IscsiTarget

Проблема - читаем доки - вроде всё правильно, но преследует ошибка:

PS C:\WINDOWS\system32>> Connect-IscsiTarget -NodeAddress iqn.2020-03.myhost.ru:lun1 -AuthenticationType OneWayCHAP -ChapUsername iqn.1991-05.com.microsoft:serv.local -ChapSecret SecretStringOne
Connect-IscsiTarget : Authentication Failure.
строка:1 знак:1
+ Connect-IscsiTarget -NodeAddress "iqn.2020-03.h001.ru:lun1" -Authenti ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (MSFT_iSCSITarget:ROOT/Microsoft/...SFT_iSCSITarget) [Connect-IscsiTarget]
   , CimException
    + FullyQualifiedErrorId : HRESULT 0xefff0009,Connect-IscsiTarget

Аналогично не работает и MutualCHAP

Решение: использовать верхний регистр типа аутентификации: ONEWAYCHAP и MUTUALCHAP (Не верьте докам!)

Connect-IscsiTarget -NodeAddress iqn.2020-03.myhost.ru:lun1 -AuthenticationType ONEWAYCHAP -ChapUsername iqn.1991-05.com.microsoft:serv.local -ChapSecret SecretStringOne

Осталось заставить MutualCHAP работать.

2019-03-26

Экспорт приватных ключей Гост. ч.2

Снова дошли руки до гостовских ключей.

Итак задача та же: нужно получить "бесплатно" закрытые ключи из "дефакто" стандартного гостовского провайдера в openssl.

Система Windows 10.0.17134.648
Ключ с привязанным секретным ключом установлен через CSP.

Запускаем certmgr.msc. Личное - Сертификаты.
Жмём ПКМ на сертификат с привязанным ключом гост (экспортируемым).
Все задачи - Экспорт.
Далее. - Да, экспортировать закрытый ключ - Далее
Файл обмена личной информацией - PKCS #12 (.PFX).
Галочки можно не трогать - но я снял все. Лишнее не надо.
Далее. Галочку на пароль. Вбиваем 123 и 123 в подтверждение.
Шифрование TripleDES-SHA1 (можно и AES256-SHA256 - hmac проверка будет чуть другой).
Далее - Имя файла выбираем 123-try3.pfx - Далее - "Экспорт выполнен" - Готово.

Файл с приватным ключом лежит на диске. Радуемся но не долго.

$ openssl pkcs12 -info -engine gost -password pass:123 -in 123-try3.pfx
engine "gost" set.
MAC: sha1, Iteration 2000
MAC length: 20, salt length: 20
PKCS7 Data
Shrouded Keybag: undefined, Iteration 2000
Bag Attributes
    localKeyID: 01 00 00 00
    friendlyName: 9d09886d-f53d-4e57-85b1-c3c25b0cd72e
    Microsoft CSP Name: Crypto-Pro GOST R 34.10-2001 Cryptographic Service Provider
Error outputting keys and certificates
25769902144:error:06074079:digital envelope routines:EVP_PBE_CipherInit:unknown pbe algorithm:crypto/evp/evp_pbe.c:95:TYPE=1.2.840.113549.1.12.1.80
25769902144:error:23077073:PKCS12 routines:PKCS12_pbe_crypt:pkcs12 algor cipherinit error:crypto/pkcs12/p12_decr.c:41:
25769902144:error:2306A075:PKCS12 routines:PKCS12_item_decrypt_d2i:pkcs12 pbe crypt error:crypto/pkcs12/p12_decr.c:94:

Встречает наш знакомый oid=1.2.840.113549.1.12.1.80.

$ openssl asn1parse -inform der -in 123-try3.pfx
    0:d=0  hl=4 l=1140 cons: SEQUENCE
    4:d=1  hl=2 l=   1 prim: INTEGER           :03
    7:d=1  hl=4 l=1072 cons: SEQUENCE
   11:d=2  hl=2 l=   9 prim: OBJECT            :pkcs7-data
   22:d=2  hl=4 l=1057 cons: cont [ 0 ]
   26:d=3  hl=4 l=1053 prim: OCTET STRING      [HEX DUMP]:
30820419308201D606092A864886F70D010701A08201C7048201C3308201BF308201BB060B2A864886F70D010C0A0102A081B23081AF3024060A2A864886F70D010C015030160410C16E378ABE17ADBC7C29E4F5EA4EEED9020207D0048186C4A7BE9F5DEC55369A1E0B357B2D052256F2052E10642B47CC8A567351E81584FFD7DCB7D2384EEC4566A02A67F9EF7504D7A8FA4CCC51722D53770F2B4B4D0667F030E9060A6C0F4ED3D73342C0C1C86FD9669E9808B98A372BC0AF8919CC502F9C74351C60B43AD89D6F4155035CDA5EBE92C36D3D2C8EA562F0F5584529552258AAC84CC43181F6301306092A864886F70D0109153106040401000000305706092A864886F70D010914314A1E4800390064003000390038003800360064002D0066003500330064002D0034006500350037002D0038003500620031002D00630033006300320035006200300063006400370032006530818506092B060104018237110131781E7600430072007900700074006F002D00500072006F00200047004F0053005400200052002000330034002E00310030002D0032003000300031002000430072007900700074006F006700720061007000680069006300200053006500720076006900630065002000500072006F007600690064006500723082023B06092A864886F70D010701A082022C048202283082022430820220060B2A864886F70D010C0A0103A08201F8308201F4060A2A864886F70D01091601A08201E4048201E0308201DC3082018BA0030201020208661C4EDBFE648D91300806062A8503020203301F310B30090603550406130252553110300E0603550403130770756232303031301E170D3139303332353136343330305A170D3230303332353136343330305A301F310B30090603550406130252553110300E06035504031307707562323030313063301C06062A8503020213301206072A85030202240006072A850302021E0103430004403271B0ABC9CC92142384D0B10ADCBC4124A1D5A9AFD440F6A99AADDD882E70CFDB9AED1682A945DF956E04F8C97E8333CF839B461353BED1A04CD99304372B71A381A83081A5300E0603551D0F0101FF0404030202DC301D0603551D250416301406082B0601050507030206082B06010505070304301D0603551D0E0416041475C3BDAB0E1B5534DD35457A201AC7F46DB1DF5530440603551D23043D303B801475C3BDAB0E1B5534DD35457A201AC7F46DB1DF55A123A421301F310B30090603550406130252553110300E0603550403130770756232303031300F0603551D13040830060101FF020101300806062A850302020303410056D6DF338FE5D629243277F31DB56FCB5B7CBCAF8EFD8F8644CCB7359EACCE86B02131C1A5029750F7D831B907000DFE38DFCD18A98203773384C18B4890FAD13115301306092A864886F70D0109153106040401000000
 1083:d=1  hl=2 l=  59 cons: SEQUENCE
 1085:d=2  hl=2 l=  31 cons: SEQUENCE
 1087:d=3  hl=2 l=   7 cons: SEQUENCE
 1089:d=4  hl=2 l=   5 prim: OBJECT            :sha1
 1096:d=3  hl=2 l=  20 prim: OCTET STRING      [HEX DUMP]:
BA88838B4D071952A12D2AE49E91B16E9D1E4719
 1118:d=2  hl=2 l=  20 prim: OCTET STRING      [HEX DUMP]:
767C58C151C9125E72367411A97E9E706C95905C
 1140:d=2  hl=2 l=   2 prim: INTEGER           :07D0

Из предыдущего поста понятно как проверить целостность pkcs7-data - тут алгоритм видимо стандартный - но я его привёл perl скриптом. Скрипт всё ещё работает. Пароль кодируем в UCS2 - размножаем и дополняем номером версии (3) и солью, хешируем SHA1 ROUNDS раз и делаем HMAC_SHA1.

Номером версии=03
ROUNDS=0x7D0 (2000)
SALT=767C58C151C9125E72367411A97E9E706C95905C
HMAC=BA88838B4D071952A12D2AE49E91B16E9D1E4719

Если выводить с "AES256-SHA256" меняем алгоритм суммы SHA256 и HMAC_SHA256.
Но всё равно никаких 3Des и AES в файле не используется.

$VER=3;
$PASS='123';
$ROUNDS=0x7D0;
$SALT=pack 'H*', '767C58C151C9125E72367411A97E9E706C95905C';
$SHA1_NEED=pack 'H*','BA88838B4D071952A12D2AE49E91B16E9D1E4719';
$BLOB=pack 'H*', <<EOF;
30820419308201D606092A864886F70D010701A08201C7048201C3308201BF308201BB060B2A864886F70D010C0A0102A081B23081AF3024060A2A864886F70D010C015030160410C16E378ABE17ADBC7C29E4F5EA4EEED9020207D0048186C4A7BE9F5DEC55369A1E0B357B2D052256F2052E10642B47CC8A567351E81584FFD7DCB7D2384EEC4566A02A67F9EF7504D7A8FA4CCC51722D53770F2B4B4D0667F030E9060A6C0F4ED3D73342C0C1C86FD9669E9808B98A372BC0AF8919CC502F9C74351C60B43AD89D6F4155035CDA5EBE92C36D3D2C8EA562F0F5584529552258AAC84CC43181F6301306092A864886F70D0109153106040401000000305706092A864886F70D010914314A1E4800390064003000390038003800360064002D0066003500330064002D0034006500350037002D0038003500620031002D00630033006300320035006200300063006400370032006530818506092B060104018237110131781E7600430072007900700074006F002D00500072006F00200047004F0053005400200052002000330034002E00310030002D0032003000300031002000430072007900700074006F006700720061007000680069006300200053006500720076006900630065002000500072006F007600690064006500723082023B06092A864886F70D010701A082022C048202283082022430820220060B2A864886F70D010C0A0103A08201F8308201F4060A2A864886F70D01091601A08201E4048201E0308201DC3082018BA0030201020208661C4EDBFE648D91300806062A8503020203301F310B30090603550406130252553110300E0603550403130770756232303031301E170D3139303332353136343330305A170D3230303332353136343330305A301F310B30090603550406130252553110300E06035504031307707562323030313063301C06062A8503020213301206072A85030202240006072A850302021E0103430004403271B0ABC9CC92142384D0B10ADCBC4124A1D5A9AFD440F6A99AADDD882E70CFDB9AED1682A945DF956E04F8C97E8333CF839B461353BED1A04CD99304372B71A381A83081A5300E0603551D0F0101FF0404030202DC301D0603551D250416301406082B0601050507030206082B06010505070304301D0603551D0E0416041475C3BDAB0E1B5534DD35457A201AC7F46DB1DF5530440603551D23043D303B801475C3BDAB0E1B5534DD35457A201AC7F46DB1DF55A123A421301F310B30090603550406130252553110300E0603550403130770756232303031300F0603551D13040830060101FF020101300806062A850302020303410056D6DF338FE5D629243277F31DB56FCB5B7CBCAF8EFD8F8644CCB7359EACCE86B02131C1A5029750F7D831B907000DFE38DFCD18A98203773384C18B4890FAD13115301306092A864886F70D0109153106040401000000
EOF

use Encode 'encode';
use Digest::SHA qw(hmac_sha1 sha1);
$KEY=encode('UCS-2BE', $PASS."\0");
$KEY=((pack'C',$VER) x 64) . substr($SALT x 4, 0, 64) . substr($KEY x 32, 0, 64);
$KEY=sha1($KEY) for 1..$ROUNDS;
$SHA1_GOT=hmac_sha1($BLOB, $KEY);
use v5.10;
say 'HMAC: ',unpack 'H*', $KEY;
say 'NEED: ',unpack 'H*', $SHA1_NEED;
say 'CALC: ',unpack 'H*', $SHA1_GOT;

Продолжаем. Берём в буфер обмена содержимое pkcs7-data - пишем в файл и парсим asn1.

$ xxd -r -p > 123-try3.pkcs7
(paste)

$ openssl asn1parse -inform der -in 123-try3.pkcs7
    0:d=0  hl=4 l=1049 cons: SEQUENCE
    4:d=1  hl=4 l= 470 cons: SEQUENCE
    8:d=2  hl=2 l=   9 prim: OBJECT            :pkcs7-data
   19:d=2  hl=4 l= 455 cons: cont [ 0 ]
   23:d=3  hl=4 l= 451 prim: OCTET STRING      [HEX DUMP]:
308201BF308201BB060B2A864886F70D010C0A0102A081B23081AF3024060A2A864886F70D010C015030160410C16E378ABE17ADBC7C29E4F5EA4EEED9020207D0048186C4A7BE9F5DEC55369A1E0B357B2D052256F2052E10642B47CC8A567351E81584FFD7DCB7D2384EEC4566A02A67F9EF7504D7A8FA4CCC51722D53770F2B4B4D0667F030E9060A6C0F4ED3D73342C0C1C86FD9669E9808B98A372BC0AF8919CC502F9C74351C60B43AD89D6F4155035CDA5EBE92C36D3D2C8EA562F0F5584529552258AAC84CC43181F6301306092A864886F70D0109153106040401000000305706092A864886F70D010914314A1E4800390064003000390038003800360064002D0066003500330064002D0034006500350037002D0038003500620031002D00630033006300320035006200300063006400370032006530818506092B060104018237110131781E7600430072007900700074006F002D00500072006F00200047004F0053005400200052002000330034002E00310030002D0032003000300031002000430072007900700074006F006700720061007000680069006300200053006500720076006900630065002000500072006F00760069006400650072
  478:d=1  hl=4 l= 571 cons: SEQUENCE
  482:d=2  hl=2 l=   9 prim: OBJECT            :pkcs7-data
  493:d=2  hl=4 l= 556 cons: cont [ 0 ]
  497:d=3  hl=4 l= 552 prim: OCTET STRING      [HEX DUMP]:
3082022430820220060B2A864886F70D010C0A0103A08201F8308201F4060A2A864886F70D01091601A08201E4048201E0308201DC3082018BA0030201020208661C4EDBFE648D91300806062A8503020203301F310B30090603550406130252553110300E0603550403130770756232303031301E170D3139303332353136343330305A170D3230303332353136343330305A301F310B30090603550406130252553110300E06035504031307707562323030313063301C06062A8503020213301206072A85030202240006072A850302021E0103430004403271B0ABC9CC92142384D0B10ADCBC4124A1D5A9AFD440F6A99AADDD882E70CFDB9AED1682A945DF956E04F8C97E8333CF839B461353BED1A04CD99304372B71A381A83081A5300E0603551D0F0101FF0404030202DC301D0603551D250416301406082B0601050507030206082B06010505070304301D0603551D0E0416041475C3BDAB0E1B5534DD35457A201AC7F46DB1DF5530440603551D23043D303B801475C3BDAB0E1B5534DD35457A201AC7F46DB1DF55A123A421301F310B30090603550406130252553110300E0603550403130770756232303031300F0603551D13040830060101FF020101300806062A850302020303410056D6DF338FE5D629243277F31DB56FCB5B7CBCAF8EFD8F8644CCB7359EACCE86B02131C1A5029750F7D831B907000DFE38DFCD18A98203773384C18B4890FAD13115301306092A864886F70D0109153106040401000000

Видим теперь два объекта - второй это сертификат - и нам не нужен. Ключ в первом "мешке". Повторяем для него процедуру.

$ xxd -r -p > 123-try3.pkcs8
(paste)
$ openssl asn1parse -inform der -in 123-try3.pkcs8
    0:d=0  hl=4 l= 447 cons: SEQUENCE
    4:d=1  hl=4 l= 443 cons: SEQUENCE
    8:d=2  hl=2 l=  11 prim: OBJECT            :pkcs8ShroudedKeyBag
   21:d=2  hl=3 l= 178 cons: cont [ 0 ]
   24:d=3  hl=3 l= 175 cons: SEQUENCE
   27:d=4  hl=2 l=  36 cons: SEQUENCE
   29:d=5  hl=2 l=  10 prim: OBJECT            :1.2.840.113549.1.12.1.80
   41:d=5  hl=2 l=  22 cons: SEQUENCE
   43:d=6  hl=2 l=  16 prim: OCTET STRING      [HEX DUMP]:
C16E378ABE17ADBC7C29E4F5EA4EEED9
   61:d=6  hl=2 l=   2 prim: INTEGER           :07D0
   65:d=4  hl=3 l= 134 prim: OCTET STRING      [HEX DUMP]:
C4A7BE9F5DEC55369A1E0B357B2D052256F2052E10642B47CC8A567351E81584FFD7DCB7D2384EEC4566A02A67F9EF7504D7A8FA4CCC51722D53770F2B4B4D0667F030E9060A6C0F4ED3D73342C0C1C86FD9669E9808B98A372BC0AF8919CC502F9C74351C60B43AD89D6F4155035CDA5EBE92C36D3D2C8EA562F0F5584529552258AAC84CC4
  202:d=2  hl=3 l= 246 cons: SET
  205:d=3  hl=2 l=  19 cons: SEQUENCE
  207:d=4  hl=2 l=   9 prim: OBJECT            :localKeyID
  218:d=4  hl=2 l=   6 cons: SET
  220:d=5  hl=2 l=   4 prim: OCTET STRING      [HEX DUMP]:01000000
  226:d=3  hl=2 l=  87 cons: SEQUENCE
  228:d=4  hl=2 l=   9 prim: OBJECT            :friendlyName
  239:d=4  hl=2 l=  74 cons: SET
  241:d=5  hl=2 l=  72 prim: BMPSTRING
  315:d=3  hl=3 l= 133 cons: SEQUENCE
  318:d=4  hl=2 l=   9 prim: OBJECT            :Microsoft CSP Name
  329:d=4  hl=2 l= 120 cons: SET
  331:d=5  hl=2 l= 118 prim: BMPSTRING

Вот мы и добрались до этого unknown gost 1.2.840.113549.1.12.1.80 штатными средствами openssl.

Если загрузить исходный pfx в онлайн просмотрщик - можно было увидеть всю структуру сразу.

    0 30 1140: SEQUENCE {
    4 02    1:  INTEGER 3
    7 30 1072:  SEQUENCE {
   11 06    9:   OBJECT IDENTIFIER data (1.2.840.113549.1.7.1)
   22 a0 1057:   [0] {
   26 04 1053:    OCTET STRING, encapsulates {
   30 30 1049:     SEQUENCE {
   34 30  470:      SEQUENCE {
   38 06    9:       OBJECT IDENTIFIER data (1.2.840.113549.1.7.1)
   49 a0  455:       [0] {
   53 04  451:        OCTET STRING, encapsulates {
   57 30  447:         SEQUENCE {
   61 30  443:          SEQUENCE {
   65 06   11:           OBJECT IDENTIFIER pkcs8ShroudedKeyBag (1.2.840.113549.1.12.10.1.2)
   78 a0  178:           [0] {
   81 30  175:            SEQUENCE {
   84 30   36:             SEQUENCE {
   86 06   10:              OBJECT IDENTIFIER pbeUnknownGost (1.2.840.113549.1.12.1.80)
   98 30   22:              SEQUENCE {
  100 04   16:               OCTET STRING
             :                c1 6e 37 8a be 17 ad bc 7c 29 e4 f5 ea 4e ee d9
  118 02    2:               INTEGER 2000
             :              }
             :             }
  122 04  134:             OCTET STRING
             :              c4 a7 be 9f 5d ec 55 36 9a 1e 0b 35 7b 2d 05 22
             :              56 f2 05 2e 10 64 2b 47 cc 8a 56 73 51 e8 15 84
             :              ff d7 dc b7 d2 38 4e ec 45 66 a0 2a 67 f9 ef 75
             :              04 d7 a8 fa 4c cc 51 72 2d 53 77 0f 2b 4b 4d 06
             :              67 f0 30 e9 06 0a 6c 0f 4e d3 d7 33 42 c0 c1 c8
             :              6f d9 66 9e 98 08 b9 8a 37 2b c0 af 89 19 cc 50
             :              2f 9c 74 35 1c 60 b4 3a d8 9d 6f 41 55 03 5c da
             :              5e be 92 c3 6d 3d 2c 8e a5 62 f0 f5 58 45 29 55
             :              22 58 aa c8 4c c4
             :            }
             :           }
  259 31  246:           SET {
  262 30   19:            SEQUENCE {
  264 06    9:             OBJECT IDENTIFIER localKeyId (1.2.840.113549.1.9.21)
  275 31    6:             SET {
  277 04    4:              OCTET STRING, encapsulates {
  279 01    0:               BOOLEAN true
             :              }
             :             }
             :            }
  283 30   87:            SEQUENCE {
  285 06    9:             OBJECT IDENTIFIER friendlyName (1.2.840.113549.1.9.20)
  296 31   74:             SET {
  298 1e   72:              BMPString "9d09886d-f53d-4e57-85b1-c3c25b0cd72e"
             :             }
             :            }
  372 30  133:            SEQUENCE {
  375 06    9:             OBJECT IDENTIFIER keyProviderNameAttr (1.3.6.1.4.1.311.17.1)
  386 31  120:             SET {
  388 1e  118:              BMPString "Crypto-Pro GOST R 34.10-2001 Cryptographic Service Provider"
             :             }
             :            }
             :           }
             :          }
             :         }
             :        }
             :       }
             :      }
  508 30  571:      SEQUENCE {
  512 06    9:       OBJECT IDENTIFIER data (1.2.840.113549.1.7.1)
  523 a0  556:       [0] {
  527 04  552:        OCTET STRING, encapsulates {
  531 30  548:         SEQUENCE {
  535 30  544:          SEQUENCE {
  539 06   11:           OBJECT IDENTIFIER certBag (1.2.840.113549.1.12.10.1.3)
  552 a0  504:           [0] {
  556 30  500:            SEQUENCE {
  560 06   10:             OBJECT IDENTIFIER x509Certificate (1.2.840.113549.1.9.22.1)
  572 a0  484:             [0] {
  576 04  480:              OCTET STRING, encapsulates {
  580 30  476:               SEQUENCE {
  584 30  395:                SEQUENCE {
  588 a0    3:                 [0] {
  590 02    1:                  INTEGER 2
             :                 }
  593 02    8:                 INTEGER
             :                  66 1c 4e db fe 64 8d 91
  603 30    8:                 SEQUENCE {
  605 06    6:                  OBJECT IDENTIFIER id-GostR3411-94-with-GostR3410-2001 (1.2.643.2.2.3)
             :                 }
  613 30   31:                 SEQUENCE {
  615 31   11:                  SET {
  617 30    9:                   SEQUENCE {
  619 06    3:                    OBJECT IDENTIFIER countryName (2.5.4.6)
  624 13    2:                    PrintableString "RU"
             :                   }
             :                  }
  628 31   16:                  SET {
  630 30   14:                   SEQUENCE {
  632 06    3:                    OBJECT IDENTIFIER commonName (2.5.4.3)
  637 13    7:                    PrintableString "pub2001"
             :                   }
             :                  }
             :                 }
  646 30   30:                 SEQUENCE {
  648 17   13:                  UTCTime Mon Mar 25 2019 19:43:00 GMT+0300 (Москва, стандартное время)
  663 17   13:                  UTCTime Wed Mar 25 2020 19:43:00 GMT+0300 (Москва, стандартное время)
             :                 }
  678 30   31:                 SEQUENCE {
  680 31   11:                  SET {
  682 30    9:                   SEQUENCE {
  684 06    3:                    OBJECT IDENTIFIER countryName (2.5.4.6)
  689 13    2:                    PrintableString "RU"
             :                   }
             :                  }
  693 31   16:                  SET {
  695 30   14:                   SEQUENCE {
  697 06    3:                    OBJECT IDENTIFIER commonName (2.5.4.3)
  702 13    7:                    PrintableString "pub2001"
             :                   }
             :                  }
             :                 }
  711 30   99:                 SEQUENCE {
  713 30   28:                  SEQUENCE {
  715 06    6:                   OBJECT IDENTIFIER id-GostR3410-2001 (1.2.643.2.2.19)
  723 30   18:                   SEQUENCE {
  725 06    7:                    OBJECT IDENTIFIER id-GostR3410-2001-CryptoPro-XchA-ParamSet (1.2.643.2.2.36.0)
  734 06    7:                    OBJECT IDENTIFIER id-GostR3411-94-CryptoProParamSet (1.2.643.2.2.30.1)
             :                   }
             :                  }
  743 03   67:                  BIT STRING, unused 0 bits, encapsulates {
  745 04   64:                   OCTET STRING
             :                    32 71 b0 ab c9 cc 92 14 23 84 d0 b1 0a dc bc 41
             :                    24 a1 d5 a9 af d4 40 f6 a9 9a ad dd 88 2e 70 cf
             :                    db 9a ed 16 82 a9 45 df 95 6e 04 f8 c9 7e 83 33
             :                    cf 83 9b 46 13 53 be d1 a0 4c d9 93 04 37 2b 71
             :                  }
             :                 }
  812 a3  168:                 [3] {
  815 30  165:                  SEQUENCE {
  818 30   14:                   SEQUENCE {
  820 06    3:                    OBJECT IDENTIFIER keyUsage (2.5.29.15)
  825 01    1:                    BOOLEAN true
  828 04    4:                    OCTET STRING, encapsulates {
  830 03    2:                     BIT STRING, unused 2 bits
             :                      110111B
             :                    }
             :                   }
  834 30   29:                   SEQUENCE {
  836 06    3:                    OBJECT IDENTIFIER extKeyUsage (2.5.29.37)
  841 04   22:                    OCTET STRING, encapsulates {
  843 30   20:                     SEQUENCE {
  845 06    8:                      OBJECT IDENTIFIER clientAuth (1.3.6.1.5.5.7.3.2)
  855 06    8:                      OBJECT IDENTIFIER emailProtection (1.3.6.1.5.5.7.3.4)
             :                     }
             :                    }
             :                   }
  865 30   29:                   SEQUENCE {
  867 06    3:                    OBJECT IDENTIFIER subjectKeyIdentifier (2.5.29.14)
  872 04   22:                    OCTET STRING, encapsulates {
  874 04   20:                     OCTET STRING
             :                      75 c3 bd ab 0e 1b 55 34 dd 35 45 7a 20 1a c7 f4
             :                      6d b1 df 55
             :                    }
             :                   }
  896 30   68:                   SEQUENCE {
  898 06    3:                    OBJECT IDENTIFIER authorityKeyIdentifier (2.5.29.35)
  903 04   61:                    OCTET STRING, encapsulates {
  905 30   59:                     SEQUENCE {
  907 80   20:                      [0]
             :                       75 c3 bd ab 0e 1b 55 34 dd 35 45 7a 20 1a c7 f4
             :                       6d b1 df 55
  929 a1   35:                      [1] {
  931 a4   33:                       [4] {
  933 30   31:                        SEQUENCE {
  935 31   11:                         SET {
  937 30    9:                          SEQUENCE {
  939 06    3:                           OBJECT IDENTIFIER countryName (2.5.4.6)
  944 13    2:                           PrintableString "RU"
             :                          }
             :                         }
  948 31   16:                         SET {
  950 30   14:                          SEQUENCE {
  952 06    3:                           OBJECT IDENTIFIER commonName (2.5.4.3)
  957 13    7:                           PrintableString "pub2001"
             :                          }
             :                         }
             :                        }
             :                       }
             :                      }
             :                     }
             :                    }
             :                   }
  966 30   15:                   SEQUENCE {
  968 06    3:                    OBJECT IDENTIFIER basicConstraints (2.5.29.19)
  973 04    8:                    OCTET STRING, encapsulates {
  975 30    6:                     SEQUENCE {
  977 01    1:                      BOOLEAN true
  980 02    1:                      INTEGER 1
             :                     }
             :                    }
             :                   }
             :                  }
             :                 }
             :                }
  983 30    8:                SEQUENCE {
  985 06    6:                 OBJECT IDENTIFIER id-GostR3411-94-with-GostR3410-2001 (1.2.643.2.2.3)
             :                }
  993 03   65:                BIT STRING, unused 0 bits
             :                 56 d6 df 33 8f e5 d6 29 24 32 77 f3 1d b5 6f cb
             :                 5b 7c bc af 8e fd 8f 86 44 cc b7 35 9e ac ce 86
             :                 b0 21 31 c1 a5 02 97 50 f7 d8 31 b9 07 00 0d fe
             :                 38 df cd 18 a9 82 03 77 33 84 c1 8b 48 90 fa d1
             :               }
             :              }
             :             }
             :            }
             :           }
 1060 31   21:           SET {
 1062 30   19:            SEQUENCE {
 1064 06    9:             OBJECT IDENTIFIER localKeyId (1.2.840.113549.1.9.21)
 1075 31    6:             SET {
 1077 04    4:              OCTET STRING, encapsulates {
 1079 01    0:               BOOLEAN true
             :              }
             :             }
             :            }
             :           }
             :          }
             :         }
             :        }
             :       }
             :      }
             :     }
             :    }
             :   }
             :  }
 1083 30   59:  SEQUENCE {
 1085 30   31:   SEQUENCE {
 1087 30    7:    SEQUENCE {
 1089 06    5:     OBJECT IDENTIFIER sha1 (1.3.14.3.2.26)
             :    }
 1096 04   20:    OCTET STRING
             :     ba 88 83 8b 4d 07 19 52 a1 2d 2a e4 9e 91 b1 6e
             :     9d 1e 47 19
             :   }
 1118 04   20:   OCTET STRING
             :    76 7c 58 c1 51 c9 12 5e 72 36 74 11 a9 7e 9e 70
             :    6c 95 90 5c
 1140 02    2:   INTEGER 2000
             :  }
             : }

Продолжаем снимать транспортную кодировку.
Получили в данный момент такие цифры:



PASS=123
SALT=C16E378ABE17ADBC7C29E4F5EA4EEED9
ROUNDS=0x7D0
ENCRYPTED KEYBAG:
C4A7BE9F5DEC55369A1E0B357B2D052256F2052E10642B47CC8A567351E81584FFD7DCB7D2384EEC4566A02A67F9EF7504D7A8FA4CCC51722D53770F2B4B4D0667F030E9060A6C0F4ED3D73342C0C1C86FD9669E9808B98A372BC0AF8919CC502F9C74351C60B43AD89D6F4155035CDA5EBE92C36D3D2C8EA562F0F5584529552258AAC84CC4


Получаем ключ для расшифровки (сорри - опять perl).

use Digest::GOST::CryptoPro qw(gost);
$KEY=encode('UCS-2LE', $PASS);
for ($i=1;$i<=$ROUNDS;$i++){$KEY=gost($KEY.$SALT.pack('n',$i))}
say 'PASSWORD=',unpack 'H*',$KEY;

Для предыдущих цифр получаем ключ:
KEY=c2bb428f981f30d8e623db786d9bd780e7d9f785a950211530142ae46fab8dce
Вот раунды хеширования если будете повторять: 310032003300 c16e378abe17adbc7c29e4f5ea4eeed9 0001 fb76e01671ac07908c159f59a0442815acaccc2e77fc25958b99a4626fc738fe c16e378abe17adbc7c29e4f5ea4eeed9 0002 cdae166434edddd770cbc0d7294f4031d83309206bc15a3089cbde622fba0ce7 c16e378abe17adbc7c29e4f5ea4eeed9 0003 ...
9350e6ec445712728c6d7c6c02efb9068f295a3f451af8df33613bfc42412d71 c16e378abe17adbc7c29e4f5ea4eeed9 07d0
Хеш сумму можно получить штатными средствами так:
$ echo 310032003300 c16e378abe17adbc7c29e4f5ea4eeed9 0001 | xxd -r -p > round1
$ gostsum round1
fe38c76f62a4998b9525fc772eccacac152844a0599f158c9007ac7116e076fb round1
$ openssl dgst -engine gost -md_gost94 -hex round1
md_gost94(round1)= fb76e01671ac07908c159f59a0442815acaccc2e77fc25958b99a4626fc738fe
gostsum есть в пакетах, собирается из gost engine от openssl (есть на github) да, и он выдаёт другой порядок байт, что надо учитывать.
Всё это было и в первой части - тут чуть подробнее.
Теперь продолжение:
Снимаем транспортную кодировку с помощью openssl.
Что используем:
Симметричный шифр: gost89 (он же magma)

MODE=CFB (Режим шифрования - он по умолчанию для gost89 в openssl)
IV (Начальный вектор): SALT(0:7) (соль больше блока шифрования магмы - для IV отрезаем её до 8 байт=16  шестнадцатеричных символов = 64 бита - или игнорируем warning)
IV=C16E378ABE17ADBC (игнорируем остаток 7C29E4F5EA4EEED9)
KEY (Ключ - получили выше) 256 бит = 32 байта = 64 hex цифры.
KEY=c2bb428f981f30d8e623db786d9bd780e7d9f785a950211530142ae46fab8dce
$ xxd -r -p > 123-try3.enc
(paste keybag C4A7BE9F5DEC55369A1E0B...)
$ CRYPT_PARAMS=1.2.643.2.2.31.1 openssl enc -engine gost -d -gost89 -in 123-try3.enc -out 123-try3.dec \
-K c2bb428f981f30d8e623db786d9bd780e7d9f785a950211530142ae46fab8dce  -iv C16E378ABE17ADBC7C29E4F5EA4EEED9
На всякий случай задали параметры шифрования через env CRYPT_PARAMS но по умолчанию они же стоят. Должны получить asn1 c экспортным ключом (первый asci символ "0").
$ openssl asn1parse -inform der -in 123-try3.dec
    0:d=0  hl=3 l= 131 cons: SEQUENCE     3:d=1  hl=2 l=   1 prim: INTEGER           :00     6:d=1  hl=2 l=  10 cons: SEQUENCE     8:d=2  hl=2 l=   6 prim: OBJECT            :GOST R 34.10-2001    16:d=2  hl=2 l=   0 prim: NULL    18:d=1  hl=2 l= 114 prim: OCTET STRING      [HEX DUMP]: 0720000024AA00004D41473120000000
306030580408FEF0268E68E6A7EA302804207987275594A59F491E62F636F794BDD49A5CD547E0D901DF3AD58DA9EFFC2657040468369E8AA022030205A0A01C06062A8503020262301206072A85030202240006072A850302021E010404B30785AA
Содержимое блоба - это то, что мы получаем, если экспорт приватного ключа сделать через winapi. То есть транспортную кодировку мы полностью сняли.
Осталось то что получили внутрь openssl прописать :)
Посмотрим что нам даёт криптопро в своей экспортной структуре.
Заголовок структуры 07 - PRIVATEKEYBLOB (06 - PUBLICKEY).
Такой параметр передаётся в функцию ExportKey.
000020 - размер ключа? Или тут всё таки 00002007 ?
АА24 - algid:
algInfo name:DH 34.10-2001
longName:GOST R 34.10-2001 256 DH
algId:43556(AA24)
type:KeyExchange
OID:1.2.643.2.2.98
OID.alg=43556(AA24)
OID_groupId:3:PUBKEY_ALG
4D414731 = MAG1 "Магический заголовок"?
00000020 - опять размер ключа?
Дальше в структуре снова идёт asn1.
Отрезаем заголовок и смотрим что там:
0:d=0  hl=2 l=  96 cons: SEQUENCE
    2:d=1  hl=2 l=  88 cons: SEQUENCE
    4:d=2  hl=2 l=   8 prim: OCTET STRING      [HEX DUMP]:FEF0268E68E6A7EA
   14:d=2  hl=2 l=  40 cons: SEQUENCE
   16:d=3  hl=2 l=  32 prim: OCTET STRING      [HEX DUMP]:
7987275594A59F491E62F636F794BDD49A5CD547E0D901DF3AD58DA9EFFC2657
   50:d=3  hl=2 l=   4 prim: OCTET STRING      [HEX DUMP]:68369E8A
   56:d=2  hl=2 l=  34 cons: cont [ 0 ]
   58:d=3  hl=2 l=   2 prim: BIT STRING
   62:d=3  hl=2 l=  28 cons: cont [ 0 ]
   64:d=4  hl=2 l=   6 prim: OBJECT            :GOST R 34.10-2001 DH
   72:d=4  hl=2 l=  18 cons: SEQUENCE
   74:d=5  hl=2 l=   7 prim: OBJECT            :id-GostR3410-2001-CryptoPro-XchA-ParamSet
   83:d=5  hl=2 l=   7 prim: OBJECT            :id-GostR3411-94-CryptoProParamSet
   92:d=1  hl=2 l=   4 prim: OCTET STRING      [HEX DUMP]:B30785AA
Или на онлайн сервисе:
    0 30   96: SEQUENCE {
    2 30   88:  SEQUENCE {
    4 04    8:   OCTET STRING
             :    fe f0 26 8e 68 e6 a7 ea
   14 30   40:   SEQUENCE {
   16 04   32:    OCTET STRING
             :     79 87 27 55 94 a5 9f 49 1e 62 f6 36 f7 94 bd d4
             :     9a 5c d5 47 e0 d9 01 df 3a d5 8d a9 ef fc 26 57
   50 04    4:    OCTET STRING
             :     68 36 9e 8a
             :   }
   56 a0   34:   [0] {
   58 03    2:    BIT STRING, unused 5 bits
             :     101B
   62 a0   28:    [0] {
   64 06    6:     OBJECT IDENTIFIER id-GostR3410-2001DH (1.2.643.2.2.98)
   72 30   18:     SEQUENCE {
   74 06    7:      OBJECT IDENTIFIER id-GostR3410-2001-CryptoPro-XchA-ParamSet (1.2.643.2.2.36.0)
   83 06    7:      OBJECT IDENTIFIER id-GostR3411-94-CryptoProParamSet (1.2.643.2.2.30.1)
             :     }
             :    }
             :   }
             :  }
   92 04    4:  OCTET STRING
             :   b3 07 85 aa
             : }

Вот это нам ещё предстоит расшифровать.
Шифрованный приватный ключ (ещё не совсем сам приватный ключ, годный для openssl):
7987275594A59F491E62F636F794BDD49A5CD547E0D901DF3AD58DA9EFFC2657
Размер уже совпадает с ожидаемым секретным ключом, т.е. тут работает
симметричный алгоритм и никакой дополнительной структуры больше нет.
(Матрёшки asn1 наконец закончились).
Соли, контрольные суммы или что-то ещё:
FEF0268E68E6A7EA
68369E8A
B30785AA

Отсылки на:
id-GostR3410-2001-CryptoPro-XchA-ParamSet
id-GostR3410-2001DH
id-GostR3411-94-CryptoProParamSet
Также тут поработали такие не(до)документированные алгоритмы:
CALG_PRO_EXPORT CALG_PRO12_EXPORT CALG_SIMPLE_EXPORT

Упоминается, что они "работают в соответствии с рекомендациями ТК26" -
но как обратить их работу надо ещё смотреть.

И надо помнить, что у нас есть пароль на экспорт (может быть и не участвует)
и публичный ключ (из сертификата).
Публичный ключ (получить легко)=
3271B0ABC9CC92142384D0B10ADCBC4124A1D5A9AFD440F6A99AADDD882E70CF DB9AED1682A945DF956E04F8C97E8333CF839B461353BED1A04CD99304372B71

Части приватного ключа (при экспорте приватного в формате PEM)=
00DC1DFB629158E86D246F26DADD3289562910A1D65FD74E523A636351B8C33D
4597BEC52D5D4704
(видимо что-то фокс зашифровал)
Экспорт приватного ключа фоксом в pkcs8 без шифра даёт вот это:
{
    privateKeyAlgorithm: {
        name: "GOST R 34.10-2001",
        id: "id-GostR3410-2001",
        namedCurve: "X-256-A",
        sBox: "D-A"
    },
    privateKey: [
        0x04, 0x20, 0x31, 0x96, 0x76, 0x58, 0xc0, 0x64, 0x7a, 0xcd, 0xbd, 0x2c, 0x8a, 0x8d, 0x55, 0xcc,
        0x03, 0x18, 0x03, 0x20, 0x8d, 0x94, 0x29, 0x2c, 0x16, 0x22, 0x1f, 0x68, 0xd9, 0xd7, 0xca, 0xa5,
        0xd7, 0x3e
    ]
}

Приватный ключ=
042031967658C0647ACDBD2C8A8D55CC031803208D94292C16221F68D9D7CAA5D73E
Осталось это получить из шифрованного ключа.
...

Дополнения.

По адресу: https://tc26.ru/standard/rs/%D0%A0%2050.1.111-2016.pdf https://www.s-terra.ru/upload/medialibrary/9bb/rekomendacii-po-standartizacii-kriptografia.pdf нашлось описание хотелок ТК26, оформленных в виде
РЕКОМЕНДАЦИИ ПО СТАНДАРТИЗАЦИИ
ИСПОЛЬЗОВАНИЕ КРИПТОГРАФИЧЕСКИХ АЛГОРИТМОВ,
СОПУТСТВУЮЩИХ ПРИМЕНЕНИЮ СТАНДАРТОВ
ГОСТ Р 34.10-2012 И ГОСТ Р 34.11-2012
Утверждены решением заседания
технического комитета по стандартизации
«Криптографическая защита информации»
(Протокол №13 от 24.04.2014 г.)
В которых в пункте 5.6 "Экспорт и импорт ключей" дают такой алгоритм :
1) Порождается случайный набор UKM.
2) С помощью функции диверсификации, использующей в качестве ключа диверсификации ключ экспорта Ke,
и в качестве значения seed случайный набор UKM, производится формирование ключа, обозначаемого KEKe(UKM).
KEKe(UKM) = KDF(Ke,label,UKM).
3) Вычисляется значение имитовставки по ГОСТ 28147-89 длины 4 байта от данных K
на ключе KEKe(UKM), синхропосылка при этом полагается равной первым 8 байтам
UKM. Полученный набор обозначается через CEK_MAC.
Compute a 4-byte checksum value, gost28147IMIT (UKM, KEK(UKM), CEK).  Call the result CEK_MAC. [rfc4357]
4) Ключ K зашифровывается по алгоритму ГОСТ 28147-89 в режиме простой замены
с использованием ключа KEKe(UKM). Результат зашифрования обозначается через
CEK_ENC.
Encrypt CEK in ECB mode using KEK(UKM).  Call the ciphertext CEK_ENC. [rfc4357]
5) Экспортным представлением ключа полагается набор (UKM | CEK_ENC | CEK_MAC).

входной набор для порождения ключа: KDF(Ke,label,UKM)
выходной набор: UKM, CEK_ENC, CEK_MAC

label=26BDB878 (фиксированный набор - приведён в "рекомендациях")
UKM=FEF0268E68E6A7EA (очевидно самая длинная посылка, т.к. её размер минимум 8 байт)
CEK_ENC=7987275594A59F491E62F636F794BDD49A5CD547E0D901DF3AD58DA9EFFC2657
CEK_MAC=68369E8A или B30785AA (обе цифры длинной 4 байта - и могут быть MAC)
В секции 5.4 дают функцию диверсификации KDF_GOSTR3411_2012_256:
KDF(Kin,label,seed) = HMAC256(Kin,0x01|label|0x00|seed|0x01|0x00)
Осталось "угадать" значение Ke Читаем rfc4357 как "изуродовать" K до Ke:
6.5.  CryptoPro KEK Diversification Algorithm

   Given a random 64-bit UKM and a GOST 28147-89 key K, this algorithm
   creates a new GOST 28147-89 key K(UKM).

    1) Let K[0] = K;
    2) UKM is split into components a[i,j]:
       UKM = a[0]|..|a[7] (a[i] - byte, a[i,0]..a[i,7] - it's bits)
    3) Let i be 0.
    4) K[1]..K[8] are calculated by repeating the following algorithm
       eight times:
     A) K[i] is split into components k[i,j]:
        K[i] = k[i,0]|k[i,1]|..|k[i,7] (k[i,j] - 32-bit integer)
     B) Vector S[i] is calculated:
        S[i] = ((a[i,0]*k[i,0] + ... + a[i,7]*k[i,7]) mod 2^32) |
        (((~a[i,0])*k[i,0] + ... + (~a[i,7])*k[i,7]) mod 2^32);
     C) K[i+1] = encryptCFB (S[i], K[i], K[i])
     D) i = i + 1
    5) Let K(UKM) be K[8].

7.  Secret Key Diversification

   This algorithm creates a GOST 28147-89 key Kd, given GOST R 34.10-94
   or GOST R 34.10-2001 secret key K and diversification data D of size
   4..40 bytes.

    1) 40-byte blob B is created from D by cloning it enough times to
       fill all 40 bytes.  For example, if D is 40-bytes long, B = D; If
       D is 6-bytes long, B = D|D|D|D|D|D|D[0..3].
    2) B is split into 8-byte UKM and 32-byte SRCKEY (B = UKM|SRCKEY).
    3) The algorithm from Section 6.5 is used to create K(UKM) from key
       K and UKM, with two differences:
         * Instead of S[i], vector (0,0,0,UKM[i],ff,ff,ff,ff XOR UKM[i])
           is used.
         * During each encryption step, only 8 out of 32 GOST 28147-89
           rounds are done.
    4) Kd is calculated:
       Kd = encryptCFB (UKM, K(UKM), SRCKEY).
Лезем в код github/gost_engine Внутри test_keyexpimp.c проверочные значения одного из тестовых примеров из pdf tc26.
    unsigned char kdftree_key[] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
        0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
    };

    unsigned char kdf_label[] = { 0x26, 0xBD, 0xB8, 0x78 };
    unsigned char kdf_seed[] =  { 0xAF, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78 };
    const unsigned char kdf_etalon[] = {
        0x22, 0xB6, 0x83, 0x78, 0x45, 0xC6, 0xBE, 0xF6,
        0x5E, 0xA7, 0x16, 0x72, 0xB2, 0x65, 0x83, 0x10,
        0x86, 0xD3, 0xC7, 0x6A, 0xEB, 0xE6, 0xDA, 0xE9,
        0x1C, 0xAD, 0x51, 0xD8, 0x3F, 0x79, 0xD1, 0x6B,
        0x07, 0x4C, 0x93, 0x30, 0x59, 0x9D, 0x7F, 0x8D,
        0x71, 0x2F, 0xCA, 0x54, 0x39, 0x2F, 0x4D, 0xDD,
        0xE9, 0x37, 0x51, 0x20, 0x6B, 0x35, 0x84, 0xC8,
        0xF4, 0x3F, 0x9E, 0x6D, 0xC5, 0x15, 0x31, 0xF9
    };

// код проверки:
    ret = gost_kdftree2012_256(kdf_result, 64, kdftree_key, 32, kdf_label, 4, kdf_seed, 8, 1);
    if (ret <= 0) {
        ERR_print_errors_fp(stderr);
 err = 5;
    } else {
        hexdump(stdout, "KDF TREE", kdf_result, 64);
        if (memcmp(kdf_result, kdf_etalon, 64) != 0) {
            fprintf(stdout, "ERROR! test failed\n");
     err = 6;
        }
    }

// добавляем "первое" контрольное значение:
    const unsigned char kdf_gost_etalon[] = {
 0xa1, 0xaa, 0x5f, 0x7d, 0xe4, 0x02, 0xd7, 0xb3,
 0xd3, 0x23, 0xf2, 0x99, 0x1c, 0x8d, 0x45, 0x34,
 0x01, 0x31, 0x37, 0x01, 0x0a, 0x83, 0x75, 0x4f,
 0xd0, 0xaf, 0x6d, 0x7c, 0xd4, 0x92, 0x2e, 0xd9
    };

// и его код проверки:
    ret = gost_kdftree2012_256(kdf_result, 32, kdftree_key, 32, kdf_label, 4, kdf_seed, 8, 1);
    if (ret <= 0) {
        ERR_print_errors_fp(stderr);
 err = 9;
    } else {
        hexdump(stdout, "KDF_GOSTR3411_2012_256", kdf_result, 32);
        if (memcmp(kdf_result, kdf_gost_etalon, 32) != 0) {
            fprintf(stdout, "ERROR! test failed\n");
     err = 10;
        }
    }
Работающий код для вычисления KDF() у нас есть. Внутри gost_keywrap.c обнаруживаем функции деривации ключа. Контрольных значений не видно.
Находим контрольные примеры в рекомендациях (5.7 п13):
13) Экспорт и импорт ключей
на параметрах szOID_Gost28147_89_TC26_Z_ParamSet
Ключ K:

 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
Величина UKM:
af 21 43 41 45 65 63 78
label:
26 bd b8 78
 KEKe(UKM) = KDF(Ke,label,UKM):

 a1 aa 5f 7d e4 02 d7 b3 d3 23 f2 99 1c 8d 45 34
 01 31 37 01 0a 83 75 4f d0 af 6d 7c d4 92 2e d9
 CEK_MAC:
 38 d5 8a a3
 CEK_ENC:
 b9 fb 92 42 95 0f 84 3f 0f bd 5b 9a 5e cf 9f 17
 f7 9e 6d 21 58 16 56 de 6d c5 85 dd 62 7a 44 0a
K=042031967658C0647ACDBD2C8A8D55CC031803208D94292C16221F68D9D7CAA5D73E