Итак задача та же: нужно получить "бесплатно" закрытые ключи из "дефакто" стандартного гостовского провайдера в 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-2001DH
id-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