Итак задача та же: нужно получить "бесплатно" закрытые ключи из "дефакто" стандартного гостовского провайдера в 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 round1fe38c76f62a4998b9525fc772eccacac152844a0599f158c9007ac7116e076fb round1$ openssl dgst -engine gost -md_gost94 -hex round1md_gost94(round1)= fb76e01671ac07908c159f59a0442815acaccc2e77fc25958b99a4626fc738fegostsum есть в пакетах, собирается из gost engine от openssl (есть на github) да, и он выдаёт другой порядок байт, что надо учитывать.Всё это было и в первой части - тут чуть подробнее.
Теперь продолжение:
Снимаем транспортную кодировку с помощью openssl.
IV=C16E378ABE17ADBC (игнорируем остаток 7C29E4F5EA4EEED9)MODE=CFB (Режим шифрования - он по умолчанию для gost89 в openssl)
IV (Начальный вектор): SALT(0:7) (соль больше блока шифрования магмы - для IV отрезаем её до 8 байт=16 шестнадцатеричных символов = 64 бита - или игнорируем warning)
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.dec0: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 DHalgId:43556(AA24)
type:KeyExchange
OID:1.2.643.2.2.98
OID.alg=43556(AA24)
OID_groupId:3:PUBKEY_ALG4D414731 = 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-2001DHid-GostR3411-94-CryptoProParamSetТакже тут поработали такие не(до)документированные алгоритмы:CALG_PRO_EXPORT CALG_PRO12_EXPORT CALG_SIMPLE_EXPORTУпоминается, что они "работают в соответствии с рекомендациями ТК26" - но как обратить их работу надо ещё смотреть.И надо помнить, что у нас есть пароль на экспорт (может быть и не участвует) и публичный ключ (из сертификата).Публичный ключ (получить легко)=3271B0ABC9CC92142384D0B10ADCBC4124A1D5A9AFD440F6A99AADDD882E70CF DB9AED1682A945DF956E04F8C97E8333CF839B461353BED1A04CD99304372B71Части приватного ключа (при экспорте приватного в формате PEM)=00DC1DFB629158E86D246F26DADD3289562910A1D65FD74E523A636351B8C33D4597BEC52D5D4704(видимо что-то фокс зашифровал)Экспорт приватного ключа фоксом в 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 0aK=042031967658C0647ACDBD2C8A8D55CC031803208D94292C16221F68D9D7CAA5D73E