2017-04-14

Криптопро и экспорт ключей. Или воюем с OID 1.2.840.113549.1.12.1.80

Немного поковырялся с экспортом ключей и шифрованием гост.
Собрал openssl 1.1.1 с внешней (теперь) библиотекой engine gost.

В perl использую Digest::GOST::Cryptopro  и Crypt::GOST_PP. (Модуль от 2001 года Crypt::GOST не собирается. К тому же там нет кузнечика 2015 года - только Магма 89).

Итак, суть проблемы. Экспорт ключей из хранилища крипто-про через штатные средства системы делает нечитаемые openssl pkcs#12/p12/pfx.
Через утилитку P12FromGostCSP.exe лиссисофта (инфотекса) делаются (вроде) читаемые.

Генерируем через КриптоАРМ самоподписанный сертификат и импортируем его в хранилище.
Экспортируем через P12FromGostCSP в p12.pfx и успешно импортируем в Fox-XCA. После чего сохраняем из xca приватный ключ в нешифрованном PEM файле.

Для изучения проблемы удобно пользоваться ASN.1 Viewer и соответственно все манипуляции с ключами ведём только в бинарном DER формате (который на самом деле ASN.1 - в любом случае нам PEM/Base64 "обвязка" ни к чему).

Нашёл даже ещё более удобный онлайн сервис чтобы приводить асн1/сертификаты в JSON вид: http://gostcrypto.com/tool-syntax.html

Вот сам секретный ключ:
    0 30  228: SEQUENCE {
    3 06    9:  OBJECT IDENTIFIER id-tc26-gost-3410-12-512-paramSetA (1.2.643.7.1.2.1.2.1)
   14 06    8:  OBJECT IDENTIFIER id-tc26-gost3411-12-512 (1.2.643.7.1.1.2.3)
   24 04   64:  OCTET STRING
             :   28 a1 3c 57 05 eb 32 9d b6 e7 ab c4 09 88 e1 74
             :   ca b3 df 19 35 bc 75 8a ea c0 da 35 08 bc ef dc
             :   02 91 7d d9 ef 0f e0 41 1e d1 9f 73 94 33 98 bb
             :   30 e9 9c 8b e0 d3 40 37 c8 52 e5 8d 50 ae 54 8d
   90 04    8:  OCTET STRING
             :   61 99 e9 f6 2d 67 fb d8
  100 04  128:  OCTET STRING
             :   5a da 7d 4e 4d 7a 24 6c 12 83 b0 57 9f b7 9f ca
             :   b8 4b b0 ee 64 60 41 5c 18 5d 42 7f 8c c2 fb 88
             :   d5 d7 23 52 17 5e 9c 31 30 e3 6a 8e f1 e4 85 b9
             :   38 10 bf 97 2a 01 12 b5 0a 8b 6e 5c aa 01 01 db
             :   c6 4b 1f 83 2c 79 3a 03 67 a2 59 25 24 3a 42 54
             :   fc a5 c7 53 5b a5 d0 56 89 9b a4 b6 f2 1d 66 28
             :   e9 db 35 23 d8 31 1b 37 88 fc fc c1 0f 09 58 e5
             :   32 0a b3 71 e9 2a 56 ec 92 74 ab ad f4 27 e4 77
             : }
Первый блоб у нас секретная часть ключа, второй блоб непонятно (рабочая точка кривой?, секретная?),
последний блоб - публичный ключ. Его видно в сертификатах и легко вытащить программно.

Итого наш "секрет" имеет размер 64 байта (512 бит).
Будем пробовать его вытаскивать certutil.

Вот что мы видим для криптопро PFX:



{    version: 3,
    authSafe: {
        contentType: "data",
        content: [
            0x30, 0x82, 0x04, 0xa3, 0x30, 0x82, 0x01, 0xca, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
            0x01, 0x07, 0x01, 0xa0, 0x82, 0x01, 0xbb, 0x04, 0x82, 0x01, 0xb7, 0x30, 0x82, 0x01, 0xb3, 0x30,
            0x82, 0x01, 0xaf, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02,
            0xa0, 0x81, 0xd4, 0x30, 0x81, 0xd1, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
            0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04, 0x08, 0xf1, 0xc8, 0xaf, 0xf2, 0x7f, 0xbd, 0x6a, 0xe1,
            0x02, 0x02, 0x07, 0xd0, 0x04, 0x81, 0xb0, 0xc2, 0x1c, 0x25, 0xa3, 0xe0, 0x75, 0xca, 0xf4, 0xab,
            0xf5, 0xc6, 0xe9, 0x34, 0xb9, 0x33, 0x30, 0xfd, 0xdf, 0xca, 0xc0, 0x45, 0x18, 0x81, 0x4e, 0x50,
            0xcf, 0xa6, 0xe2, 0x73, 0xf6, 0x2b, 0xf3, 0xd8, 0x42, 0xc5, 0x06, 0xef, 0xbd, 0xcc, 0x4a, 0x95,
            0xbe, 0xb9, 0x9d, 0x40, 0xeb, 0xb5, 0x5b, 0xed, 0x4e, 0xd5, 0xa0, 0xbc, 0x0a, 0xc0, 0x60, 0x7e,
            0xc2, 0xaa, 0x8f, 0xf3, 0x7b, 0x2b, 0xd9, 0x1b, 0xc7, 0x53, 0x8d, 0x33, 0x06, 0x7a, 0x75, 0x27,
            0xe2, 0xf1, 0xee, 0xb9, 0xb9, 0xfe, 0xc7, 0xb1, 0xea, 0x15, 0x38, 0xc5, 0xc2, 0x8a, 0xf3, 0xad,
            0x07, 0x18, 0x93, 0xad, 0x99, 0x4f, 0x1d, 0xb6, 0xe2, 0x25, 0x54, 0x91, 0xf6, 0x0e, 0x34, 0xed,
            0xea, 0x38, 0x6e, 0x17, 0xdd, 0x96, 0x01, 0xec, 0x0e, 0x36, 0xa4, 0xac, 0xf5, 0xbe, 0xd1, 0x08,
            0x1b, 0xef, 0x95, 0x8f, 0x47, 0x93, 0x1d, 0xdd, 0xc1, 0x88, 0x4f, 0x58, 0xa6, 0x34, 0xef, 0x17,
            0xf5, 0xb4, 0x82, 0x89, 0x83, 0xf0, 0xa7, 0xb0, 0xff, 0x93, 0x08, 0x97, 0x94, 0x71, 0xf5, 0x2a,
            0x9d, 0x22, 0x0b, 0x44, 0x51, 0x60, 0xf0, 0x1e, 0xf0, 0x8d, 0x92, 0x2b, 0x4c, 0xb6, 0x25, 0x66,
            0x1a, 0x23, 0xf1, 0x8a, 0x9f, 0xb8, 0x50, 0x31, 0x81, 0xc8, 0x30, 0x13, 0x06, 0x09, 0x2a, 0x86,
            0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x06, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00, 0x30,
            0x19, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x14, 0x31, 0x0c, 0x1e, 0x0a,
            0x00, 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x31, 0x30, 0x81, 0x95, 0x06, 0x09, 0x2b,
            0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x11, 0x01, 0x31, 0x81, 0x87, 0x1e, 0x81, 0x84, 0x00, 0x43,
            0x00, 0x72, 0x00, 0x79, 0x00, 0x70, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x2d, 0x00, 0x50, 0x00, 0x72,
            0x00, 0x6f, 0x00, 0x20, 0x00, 0x47, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x54, 0x00, 0x20, 0x00, 0x52,
            0x00, 0x20, 0x00, 0x33, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x32,
            0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x6f,
            0x00, 0x6e, 0x00, 0x67, 0x00, 0x20, 0x00, 0x43, 0x00, 0x72, 0x00, 0x79, 0x00, 0x70, 0x00, 0x74,
            0x00, 0x6f, 0x00, 0x67, 0x00, 0x72, 0x00, 0x61, 0x00, 0x70, 0x00, 0x68, 0x00, 0x69, 0x00, 0x63,
            0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65,
            0x00, 0x20, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x76, 0x00, 0x69, 0x00, 0x64, 0x00, 0x65,
            0x00, 0x72, 0x30, 0x82, 0x02, 0xd1, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
            0x01, 0xa0, 0x82, 0x02, 0xc2, 0x04, 0x82, 0x02, 0xbe, 0x30, 0x82, 0x02, 0xba, 0x30, 0x82, 0x02,
            0xb6, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x03, 0xa0, 0x82,
            0x02, 0x8e, 0x30, 0x82, 0x02, 0x8a, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
            0x16, 0x01, 0xa0, 0x82, 0x02, 0x7a, 0x04, 0x82, 0x02, 0x76, 0x30, 0x82, 0x02, 0x72, 0x30, 0x82,
            0x01, 0xde, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x18, 0x9e, 0x42, 0x75, 0xf7, 0xe9, 0x7f,
            0x0b, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x03, 0x03, 0x30, 0x22, 0x31,
            0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x52, 0x55, 0x31, 0x13, 0x30, 0x11,
            0x06, 0x03, 0x55, 0x04, 0x03, 0x1e, 0x0a, 0x04, 0x42, 0x04, 0x35, 0x04, 0x41, 0x04, 0x42, 0x00,
            0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x34, 0x30, 0x36, 0x31, 0x30, 0x31, 0x30, 0x32,
            0x36, 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x34, 0x30, 0x36, 0x31, 0x30, 0x31, 0x30, 0x32, 0x36,
            0x5a, 0x30, 0x22, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x52, 0x55,
            0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x1e, 0x0a, 0x04, 0x42, 0x04, 0x35, 0x04,
            0x41, 0x04, 0x42, 0x00, 0x31, 0x30, 0x81, 0xaa, 0x30, 0x21, 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07,
            0x01, 0x01, 0x01, 0x02, 0x30, 0x15, 0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x02, 0x01, 0x02,
            0x01, 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x03, 0x03, 0x81, 0x84, 0x00, 0x04,
            0x81, 0x80, 0x5a, 0xda, 0x7d, 0x4e, 0x4d, 0x7a, 0x24, 0x6c, 0x12, 0x83, 0xb0, 0x57, 0x9f, 0xb7,
            0x9f, 0xca, 0xb8, 0x4b, 0xb0, 0xee, 0x64, 0x60, 0x41, 0x5c, 0x18, 0x5d, 0x42, 0x7f, 0x8c, 0xc2,
            0xfb, 0x88, 0xd5, 0xd7, 0x23, 0x52, 0x17, 0x5e, 0x9c, 0x31, 0x30, 0xe3, 0x6a, 0x8e, 0xf1, 0xe4,
            0x85, 0xb9, 0x38, 0x10, 0xbf, 0x97, 0x2a, 0x01, 0x12, 0xb5, 0x0a, 0x8b, 0x6e, 0x5c, 0xaa, 0x01,
            0x01, 0xdb, 0xc6, 0x4b, 0x1f, 0x83, 0x2c, 0x79, 0x3a, 0x03, 0x67, 0xa2, 0x59, 0x25, 0x24, 0x3a,
            0x42, 0x54, 0xfc, 0xa5, 0xc7, 0x53, 0x5b, 0xa5, 0xd0, 0x56, 0x89, 0x9b, 0xa4, 0xb6, 0xf2, 0x1d,
            0x66, 0x28, 0xe9, 0xdb, 0x35, 0x23, 0xd8, 0x31, 0x1b, 0x37, 0x88, 0xfc, 0xfc, 0xc1, 0x0f, 0x09,
            0x58, 0xe5, 0x32, 0x0a, 0xb3, 0x71, 0xe9, 0x2a, 0x56, 0xec, 0x92, 0x74, 0xab, 0xad, 0xf4, 0x27,
            0xe4, 0x77, 0xa3, 0x81, 0xab, 0x30, 0x81, 0xa8, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
            0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0xde, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
            0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b,
            0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
            0x04, 0x14, 0xff, 0x31, 0x79, 0xbb, 0xc3, 0xb0, 0xc7, 0x48, 0x3d, 0xac, 0x64, 0x38, 0xce, 0x06,
            0x56, 0x55, 0xc9, 0x81, 0xc7, 0x88, 0x30, 0x47, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x40, 0x30,
            0x3e, 0x80, 0x14, 0xff, 0x31, 0x79, 0xbb, 0xc3, 0xb0, 0xc7, 0x48, 0x3d, 0xac, 0x64, 0x38, 0xce,
            0x06, 0x56, 0x55, 0xc9, 0x81, 0xc7, 0x88, 0xa1, 0x26, 0xa4, 0x24, 0x30, 0x22, 0x31, 0x0b, 0x30,
            0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x52, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
            0x55, 0x04, 0x03, 0x1e, 0x0a, 0x04, 0x42, 0x04, 0x35, 0x04, 0x41, 0x04, 0x42, 0x00, 0x31, 0x30,
            0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01,
            0x30, 0x0a, 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x03, 0x03, 0x03, 0x81, 0x81, 0x00,
            0x5a, 0x9b, 0x83, 0x59, 0x72, 0x6b, 0x99, 0xcb, 0xfd, 0x76, 0x62, 0xea, 0xfd, 0x90, 0xf1, 0xd5,
            0x30, 0x73, 0x77, 0x71, 0x46, 0xd6, 0xeb, 0x57, 0x39, 0xbc, 0x58, 0x61, 0x9e, 0x4b, 0x2c, 0x80,
            0xf9, 0xca, 0xe6, 0x62, 0xef, 0x36, 0xa4, 0x9e, 0xd0, 0x00, 0xb7, 0xd5, 0xcf, 0xf0, 0xed, 0x23,
            0x09, 0xc1, 0x93, 0xf8, 0xde, 0x85, 0x71, 0x23, 0x94, 0xc3, 0xb2, 0xe4, 0x88, 0x24, 0xa4, 0x36,
            0x68, 0x64, 0x17, 0x0e, 0x31, 0x1b, 0xae, 0x16, 0x4a, 0x24, 0xad, 0x98, 0xda, 0x12, 0x53, 0x06,
            0x97, 0xab, 0x46, 0x61, 0x28, 0xe9, 0xcf, 0x3d, 0x4e, 0xfd, 0xdd, 0x3f, 0x55, 0xbb, 0x96, 0x43,
            0xcf, 0x01, 0x8c, 0x61, 0x4f, 0xbb, 0xd7, 0x67, 0x25, 0xb2, 0x46, 0xd4, 0x00, 0xbb, 0x95, 0x64,
            0x5e, 0xf2, 0x40, 0xb0, 0x23, 0xc4, 0xc3, 0xc6, 0xd5, 0x14, 0xd2, 0x48, 0xbb, 0xa2, 0xde, 0x12,
            0x31, 0x15, 0x30, 0x13, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31,
            0x06, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00
        ]
    },
    macData: {
        mac: {
            digestAlgorithm: {
                name: "SHA-1",
                id: "sha1"
            },
            digest: [
                0xa8, 0xc4, 0xab, 0x31, 0x0c, 0xa5, 0x5c, 0x38, 0xda, 0xd4, 0xf6, 0x9e, 0xb7, 0x8a, 0x05, 0xc6,
                0xe5, 0xc8, 0xbd, 0x41
            ]
        },
        macSalt: [
            0xaa, 0xbf, 0x9e, 0xa1, 0xb4, 0x1b, 0x04, 0x44, 0x02, 0x34, 0x2e, 0x8f, 0xc7, 0xa3, 0x99, 0x75,
            0xfc, 0x79, 0xef, 0x91
        ],
        iterations: 2000
    }
}

Версия контейнера 3, затем идёт блоб данных, затем секция HMAC контрольной суммы.
КС на алгоритме SHA-1, видим соль, количество итераций, и саму сумму.
Чуток исследований и получаем следующий алгоритм проверки суммы:

use v5.10;
use Digest::SHA qw/hmac_sha1 sha1/;
use Encode qw/encode/;
use utf8;

sub unhex($){my $d=shift;$d=~s/[^0-9a-fA-F]//g;pack'H*',$d}
sub tohex($){my $d=uc unpack 'H*',shift;$d=~s/../$& /g;chop $d;$d}
$salt=unhex '70 FA F5 FD AB EE 39 0F 1F CE 34 B8 3F 87 17 A2 D2 11 25 75';
$rounds=2000;
$ver=3;
$pass='1234Ё';
$pass=encode('UCS-2BE', $pass."\0");
$data=((pack'C',$ver) x 64) . substr($salt x 4, 0, 64) . substr($pass x 16, 0, 64);
say "ToHash:",tohex $data;
for (my $i=0;$i<$rounds;$i++){$data=sha1($data)}
say "Hmac_Key:",uc unpack'H*', $data;

$crc=unhex 'a8, 0xc4, 0xab, 0x31, 0x0c, 0xa5, 0x5c, 0x38, 0xda, 0xd4, 0xf6, 0x9e, 0xb7, 0x8a, 0x05, 0xc6,
                0xe5, 0xc8, 0xbd, 0x41';
$blob=unhex '';
my $crc1=hmac_sha1($blob, $data);
say "Data is: ".($crc eq $crc1? "Valid": "Invalid");

Но это пока не проблема.
Проблема внутри блоба. Посмотрим его отдельно.
http://gostcrypto.com/tool-asn1.html

OBJECT IDENTIFIER pkcs8ShroudedKeyBag (1.2.840.113549.1.12.10.1.2)
[0] {
 SEQUENCE {
  SEQUENCE {
   OBJECT IDENTIFIER pbeWithSHAAnd3-KeyTripleDES-CBC (1.2.840.113549.1.12.1.3)
    SEQUENCE {
      OCTET STRING   f1 c8 af f2 7f bd 6a e1
      INTEGER 2000
    }
  }
  OCTET STRING
             :          c2 1c 25 a3 e0 75 ca f4 ab f5 c6 e9 34 b9 33 30
             :          fd df ca c0 45 18 81 4e 50 cf a6 e2 73 f6 2b f3
             :          d8 42 c5 06 ef bd cc 4a 95 be b9 9d 40 eb b5 5b
             :          ed 4e d5 a0 bc 0a c0 60 7e c2 aa 8f f3 7b 2b d9
             :          1b c7 53 8d 33 06 7a 75 27 e2 f1 ee b9 b9 fe c7
             :          b1 ea 15 38 c5 c2 8a f3 ad 07 18 93 ad 99 4f 1d
             :          b6 e2 25 54 91 f6 0e 34 ed ea 38 6e 17 dd 96 01
             :          ec 0e 36 a4 ac f5 be d1 08 1b ef 95 8f 47 93 1d
             :          dd c1 88 4f 58 a6 34 ef 17 f5 b4 82 89 83 f0 a7
             :          b0 ff 93 08 97 94 71 f5 2a 9d 22 0b 44 51 60 f0
             :          1e f0 8d 92 2b 4c b6 25 66 1a 23 f1 8a 9f b8 50
   }
 }

Иногда экспортируется вот в таком формате: pbeWithSHAAnd3-KeyTripleDES-CBC
Но чаще вот в этом:
   65 06   11:           OBJECT IDENTIFIER pkcs8ShroudedKeyBag (1.2.840.113549.1.12.10.1.2)
   78 a0  219:           [0] {
   81 30  216:            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
             :                d0 c5 eb df 99 b7 b7 82 7c e0 b1 a6 7f a7 57 10
  118 02    2:               INTEGER 2000
             :              }
             :             }
  122 04  175:             OCTET STRING, encapsulates {
  125 82    5:              [2]
             :               d5 12 ea 73 dc
             :             }
             :            }

pbeUnknownGost: OID=1.2.840.113549.1.12.1.80


Суть алгоритма в следующем. Генерируется 16-байтная соль.
В данном случае SALT=d0 c5 eb df 99 b7 b7 82 7c e0 b1 a6 7f a7 57 10
Количество итераций ROUNDS=2000=0x7C0
Берётся пароль, кодировка UCS-2LE.

use Digest::GOST::CryptoPro qw(gost);
$salt="\x11" x 16;$rounds=0x7D0;$pass='1';$pass=encode('UCS-2LE', $pass); $key=$pass;for (my $i=1;$i<=$rounds;$i++){$key=gost($key.$salt.pack('n',$i))}

Полученный ключ используется как
1) ключ шифрования для экспорта приватного из криптопровайдера и 
2) ключ шифрования блоба от криптопровайдера алгоритмом гост89.
Encrypt_Gost89(D, IV=>"\x11" x 16, Key=>"\x22" x 32);
То есть для расшифровки надо сначала расшифровать блоб симметричным алгоритмом
Гост89, KEY=$key, IV=$salt, MODE=CFB
А затем что-то сделать с ключом, чтобы расшифровать транспортную кодировку
криптопровайдера ALG_XXX_EXPORT.
Да, да. Ключ дважды зашифрован - от провайдера идёт зашифрованный секретный ключ,
благо "пароль" мы уже знаем, а потом его ещё раз шифрует certutil.
Алгоритм транспортного шифрования для "новых" ключей (после 2012 года)
CALG_PRO12_EXPORT 0x6621.

Старые Гост89 ключи и сеансовые ключи могут шифроваться CALG_SIMPLE_EXPORT 0x6620.
Ключи до 2012 года также могут быть зашифрованы CALG_PRO_EXPORT 0x661F.
Посмотрим, что у нас есть.
После расшифровки контейнера получаем такую структуру:

Try1:
07 20 00 00 42 AA 00 00 4D 41 47 31 40 00 00 00 
30 81 85 30 7D 04 08[B6 4C 7D F7 03 3B FB A1]
30 48 04 40[53 43 86 06 ED 3E 98 B2 11 46 1C 3A E3 60 72 42 B2 34 5C 7F 3A FB D4 E8 45 BF 51 92 34 21 66 BE 27 81 B7 71 25 C3 A1 03 B0 48 23 02 2F 99 A7 D2 A7 A0 76 EE 9C ED FE 1A A1 F5 A9 EC 26 62 AB 58]
04 04[24 CE 0F 03]A0 27 03 02 05 A0 A0 21 06 08 2A 85 03 07 01 01 06 02 30 15 06 09 2A 85 03 07 01 02 01 02 01 06 08 2A 85 03 07 01 01 02 03 04 04[B5 13 07 5C]

SALT=B6 4C 7D F7 03 3B FB A1
DATA=53 43 86 06 ED 3E 98 B2 11 46 1C 3A E3 60 72 42 B2 34 5C 7F 3A FB D4 E8 45 BF 51 92 34 21 66 BE 27 81 B7 71 25 C3 A1 03 B0 48 23 02 2F 99 A7 D2 A7 A0 76 EE 9C ED FE 1A A1 F5 A9 EC 26 62 AB 58
CRC1=24 CE 0F 03
CRC2=B5 13 07 5C

Try2:
07 20 00 00 42 AA 00 00 4D 41 47 31 40 00 00 00 
30 81 85 30 7D 04 08[B0 FF 35 17 58 46 51 5D]
30 48 04 40[7E 72 A9 41 D9 83 52 F2 FE 93 4C 68 3C 55 0B 2F E8 34 93 3C 54 2F 9C 54 7D 6B AF C5 66 D5 20 7F A1 EC 44 6E 1D 2F C6 FA 4E FA A9 C3 A4 A8 E5 5D B2 62 3E E1 60 9B 8D 64 83 EC 46 6B 82 24 B5 8F]
04 04[28 33 16 9D]A0 27 03 02 05 A0 A0 21 06 08 2A 85 03 07 01 01 06 02 30 15 06 09 2A 85 03 07 01 02 01 02 01 06 08 2A 85 03 07 01 01 02 03 04 04[2E 89 9F 22]

Вначале структуры видны 16 байт заголовка, после чего идёт ASN.1
Опять видим соль (8 байт), данные (64 байта) и пара 4-байтных чисел (имитовставки или кс).
В заголовке видны цифры:
0x2007 - видимо сигнатура заголовка и заодно год создания стандарта структуры :)
CALG_DH_GR3410_2012_512_SF  = 0AA42h    ; Идентификатор алгоритма обмена ключей по Диффи-Хеллману на базе закрытого ключа пользователя.
Открытый ключ получается по ГОСТ Р 34.10 2012 (512 бит).

GR3410_1_MAGIC   = 3147414Dh            ; Признак ключей ГОСТ Р 34.10-94 и ГОСТ Р 34.10-2001.
040h = размер секретного ключа (64 байта).

Внутри ASN.1 нас дополнительно посылают на OID:
1.2.643.7.1.1.6.2
1.2.643.7.1.2.1.2.1
1.2.643.7.1.1.2.3

to be continued...

3 комментария:

Das Ich комментирует...

Привет. Столкнулся с тем же самым. Криптопро, не стесняясь, использует никому не известный 1.2.840.113549.1.12.1.80 и никто не может прочитать контейнер, ломаясь на неизвестном алгоритме.

Пока не покупал эту штуку, которая от "Лисси" (?), но интересно, а у них какой OID на том месте, где КП пишет 1.2.840.113549.1.12.1.80?

Gimly комментирует...

я доковырял транспортное шифрование и проверку целостности контейнера с этим 1.80 - а дальше всё упёрлось в экспортное шифрование приватного ключа.
Т.е можно рассматривать оид контейнера "вскрытым" (на perl сделал проги проверки-расчёта кс и расшифровки контейнера).

Лисси на рубоарде можно найти. Там и п12экспорт "полный" и фокс-ца 2.0.

Они в п12 пихают почти то же самое - только кс у них гостовская а не sha и алгоритм деривиации ключа от пароля чуть другой. Тоже вроде вскрылось нормально.

Загвоздка оказалась в экспортном шифровании ключа. И лисы и прошники получают ключ одинаково (а главное экспортируют-импортируют одно и то же).
создаётся параметр шифрования на основе пользовательского пароля - и передаётся в драйвер с параметром crypt_export (их там штуки три кодов экспортных шифров - для новых ключей обязателен новый гост - это требование сертификации). Так вот саму генерацию и передачу ключа в драйвер я вижу - а на выходе уже зашифрованный контейнер ключа. Что там в драйвере творится у меня дабаггер не видит (x64 debugger - он юзерлевел). А декомпилёный драйвер с ООП и таблицами виртуальных методов - там без реальной отладки даже куда лезть непонятно.
Т.е. параметры приватного ключа из расшифрованного транспортного контейнера не могу получить (чтобы отдать тому же openssl) - но могу передать блоб в драйвер кпро для дальнейшего импорта. Научиться бы раскрывать этот crypt_export - там 100% банальный гост, только с солением и многопроходной обработкой ключа (как и транспортное шифрование).

Unknown комментирует...

Gimly, вот есть такие данные:
'CP-01': {
title: 'Crypto-Pro GOST R 34.10-2001 Cryptographic Service Provider',
signature: algorithms['id-GostR3411-94-with-GostR3410-2001'],
publicKey: {id: 'id-GostR3410-2001', name: 'GOST R 34.10-2001', namedCurve: 'X-256-A'},
privateKey: {id: 'id-GostR3410-2001DH', name: 'GOST R 34.10-2001-DH', namedCurve: 'X-256-A'},
digest: {id: 'id-GostR3411-94', name: 'GOST R 34.11-94', sBox: 'D-A'},
wrapping: {id: 'id-Gost28147-89-CryptoPro-KeyWrap', name: 'GOST 28147-89-CPKW', sBox: 'E-A'},
hmac: algorithms['id-HMACGostR3411-94'],
agreement: algorithms['id-GostR3410-2001-CryptoPro-ESDH'],
encryption: {id: 'id-Gost28147-89', name: 'GOST 28147-89-CFB-CPKM', sBox: 'E-A'},
derivation: {id: 'PBKDF2', name: 'GOST R 34.11-94-PBKDF2', iterations: 2000}
},

Есть вероятность, что поля encryption и derivation используются уже для экспортного шифрования.
Т.е. почти то же, что и в первой, только pde типа PBKDF2 и для GOST 28147-89 используется sbox E-A.
Вопрос в том, какая соль и какой пароль использовать.