| ||||
| ||||
Делаю проверку подписи с помощью низкоуровневых функций (само сообщение в формате PKCS#7). Вот с чем столкнулся - получаю открытый ключ получателя из этого сообщения. Но CryptImportKey его не хочет принимать ("Плохие данные"). Потом я посмотрел что выдает CryptExportKey и обнаружил, что открытого ключа эти данные не содержат. Точнее там содержится какая-то структура. Дак вот, как я могу импортировать открытый ключ, имея только его? Или мне необходимо, чтобы для проверки подписи был установлен в хранилище сертификат открытого ключа? | ||||
Ответы: | ||||
| ||||
Вот еще один вопрос по этой теме: Даже если я импортирую ключ, полученный с помощьюCryptExportKey, то у меня выдается "Неправильная подпись". Вот код, которым я проверяю подпись: CryptAcquireContext(&hCryptProv, NULL, csp_name, csp_type, CRYPT_VERIFYCONTEXT); if (!CryptImportKey(hCryptProv, (BYTE*)pubkey, ps, 0, 0, &hPubKey)) { WriteLog("Не могу импортировать открытый ключ."); } if (!CryptCreateHash(hCryptProv, algid, 0, 0, &hHash)) { WriteLog("Не могу создать хэш-объект."); } if(kl && !CryptHashData(hHash, (BYTE*)data, ds, 0)) { WriteLog("Не могу хэшировать данные."); } if(CryptVerifySignature(hHash, (BYTE*)sign, ss, hPubKey, NULL, 0)) { WriteLog("Подпись верифицирована."); } else { WriteLog("Подпись не верифицирована."); } В pubkey содержатся выходные данные CryptExportKey; data - данные, которые подписывались; sign - зашифрованный хэш. | ||||
| ||||
Экспортируете как PUBLICKEYBLOB? А перед экспортом подпись проверяется? По поводу 1го вопроса - не совсем ясно как вы из PKCS7 получаете открытый ключ, но скорее всего Вам поможет CryptImportPublicKeyInfo. | ||||
| ||||
По первому вопросу - просто вытаскиваю этот ключ из PKCS#7-сообщения. Так и не разобрался как импортировать этот ключ. Вот что я делаю: char *pubkey = NULL; //тут считываю в pubkey открытый ключ из сообщения. этот ключ сходится с тем, который указан в сертификате открытого ключа memset(&pInfo, 0, sizeof(CERT_PUBLIC_KEY_INFO)); pInfo.Algorithm.pszObjId = oid; pInfo.PublicKey.cbData = ps; pInfo.PublicKey.pbData = (BYTE *) pubkey; if (!CryptImportPublicKeyInfo(hCryptProv, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &pInfo, &hPubKey)) { WriteLog("Не могу импортировать открытый ключ."); } Выдается сообщение "Встречено неверное значение тега ASN1". Теперь относительно самой проверки подписи. На время эксперимента, я просто экспортировал открытый ключ в файл. Если я подписываю данные низкоуровневыми функциями, а затем проверяю подпись также низкоуровневыми функциями, то все нормально. Если же я подписываю данные с помощью функции CryptSignMessage, а проверку делаю функциями CryptCreateHash, CryptHashData и т.д., то мне выдается сообщение, что подпись неверна. И еще, когда я сформировал подпись низкоуровневыми функциями, то оказалось, что данной последовательности байтов (зашифрованный хэш) не содержится в PKCS#7-сообщении, полученном из CryptSignMessage. Как это можно понять? | ||||
| ||||
Вот что еще хотел уточнить. Я просмотрел с помощью программы dumpasn1 данные, которые получил с помощью функции CryptSignMessage: 0 30 5217: SEQUENCE { 4 06 9: OBJECT IDENTIFIER ’1 2 840 113549 1 7 2’ 15 A0 5202: [0] { 19 30 5198: SEQUENCE { 23 02 1: INTEGER 1 26 31 12: SET { 28 30 10: SEQUENCE { 30 06 6: OBJECT IDENTIFIER ’1 2 643 2 2 9’ 38 05 0: NULL : } : } 40 30 4044: SEQUENCE { 44 06 9: OBJECT IDENTIFIER ’1 2 840 113549 1 7 1’ 55 A0 4029: [0] { 59 04 4025: OCTET STRING : ’================================================’ : ’================================.. MICROSOFT ’ : ’FOUNDATION CLASS LIBRARY : Shifr Project Overvie’ : ’w..=============================================’ : ’==================================....The applic’ : ’ation wizard has created this Shifr application ’ : ’for ..you. This application not only demonstrat’ : ’es the basics of using the Microsoft ..Foundatio’ : [ Another 3641 characters skipped ] : } : } 4088 A0 903: [0] { 4092 30 899: SEQUENCE { 4096 30 816: SEQUENCE { 4100 A0 3: [0] { 4102 02 1: INTEGER 2 : } 4105 02 10: INTEGER : 79 8C DD 8A 00 00 00 00 35 D4 4117 30 10: SEQUENCE { 4119 06 6: OBJECT IDENTIFIER ’1 2 643 2 2 3’ 4127 05 0: NULL : } 4129 30 111: SEQUENCE { 4131 31 30: SET { 4133 30 28: SEQUENCE { 4135 06 9: OBJECT IDENTIFIER ’1 2 840 113549 1 9 1’ 4146 16 15: IA5String ’’ : } : } 4163 31 11: SET { 4165 30 9: SEQUENCE { 4167 06 3: OBJECT IDENTIFIER ’2 5 4 6’ 4172 13 2: PrintableString ’RU’ : } : } 4176 31 21: SET { 4178 30 19: SEQUENCE { 4180 06 3: OBJECT IDENTIFIER ’2 5 4 7’ 4185 13 12: PrintableString ’’ : } : } 4199 31 19: SET { 4201 30 17: SEQUENCE { 4203 06 3: OBJECT IDENTIFIER ’2 5 4 10’ 4208 13 10: PrintableString ’’ : } : } 4220 31 20: SET { 4222 30 18: SEQUENCE { 4224 06 3: OBJECT IDENTIFIER ’2 5 4 3’ 4229 13 11: PrintableString ’’ : } : } : } 4242 30 30: SEQUENCE { 4244 17 13: UTCTime ’041005041600Z’ 4259 17 13: UTCTime ’051005042500Z’ : } 4274 30 272: SEQUENCE { 4278 31 35: SET { 4280 30 33: SEQUENCE { 4282 06 9: OBJECT IDENTIFIER ’1 2 840 113549 1 9 1’ 4293 16 20: IA5String ’’ : } : } 4315 31 11: SET { 4317 30 9: SEQUENCE { 4319 06 3: OBJECT IDENTIFIER ’2 5 4 6’ 4324 13 2: PrintableString ’RU’ : } : } 4328 31 31: SET { 4330 30 29: SEQUENCE { 4332 06 3: OBJECT IDENTIFIER ’2 5 4 7’ 4337 1E 22: BMPString ’’ : } : } 4361 31 53: SET { 4363 30 51: SEQUENCE { 4365 06 3: OBJECT IDENTIFIER ’2 5 4 10’ 4370 1E 44: BMPString : ’’ : } : } 4416 31 19: SET { 4418 30 17: SEQUENCE { 4420 06 3: OBJECT IDENTIFIER ’2 5 4 3’ 4425 13 10: PrintableString ’’ : } : } 4437 31 48: SET { 4439 30 46: SEQUENCE { 4441 06 9: OBJECT IDENTIFIER ’1 2 840 113549 1 9 2’ 4452 13 33: PrintableString ’’ : } : } 4487 31 61: SET { 4489 30 59: SEQUENCE { 4491 06 3: OBJECT IDENTIFIER ’2 5 4 4’ 4496 1E 52: BMPString : ’’ : ’.0’ : } : } : } 4550 30 99: SEQUENCE { 4552 30 28: SEQUENCE { 4554 06 6: OBJECT IDENTIFIER ’1 2 643 2 2 19’ 4562 30 18: SEQUENCE { 4564 06 7: OBJECT IDENTIFIER ’1 2 643 2 2 36 0’ 4573 06 7: OBJECT IDENTIFIER ’1 2 643 2 2 30 1’ : } : } 4582 03 67: BIT STRING 0 unused bits, encapsulates { 4585 04 64: OCTET STRING : D3 F5 27 BF 62 EE 89 20 8F E6 4E F9 D2 48 C1 52 : D9 D5 4E A4 01 A3 35 59 ED EB 58 94 3D E1 D2 C7 : B3 1E 42 BF 0D 2A 77 A3 31 40 77 D3 F7 D8 1B C2 : 0A A8 45 01 DF 53 7C 34 7A 5B 8F AF C2 5C 0E 23 : } : } 4651 A3 261: [3] { 4655 30 257: SEQUENCE { 4659 30 14: SEQUENCE { 4661 06 3: OBJECT IDENTIFIER ’2 5 29 15’ 4666 01 1: BOOLEAN TRUE 4669 04 4: OCTET STRING, encapsulates { 4671 03 2: BIT STRING 4 unused bits : ’1111’B : } : } 4675 30 46: SEQUENCE { 4677 06 3: OBJECT IDENTIFIER ’2 5 29 37’ 4682 04 39: OCTET STRING, encapsulates { 4684 30 37: SEQUENCE { 4686 06 8: OBJECT IDENTIFIER ’1 3 6 1 5 5 7 3 2’ 4696 06 8: OBJECT IDENTIFIER ’1 3 6 1 5 5 7 3 4’ 4706 06 7: OBJECT IDENTIFIER ’1 2 643 2 2 34 6’ 4715 06 6: OBJECT IDENTIFIER ’1 2 643 3 7 1’ : } : } : } 4723 30 29: SEQUENCE { 4725 06 3: OBJECT IDENTIFIER ’2 5 29 14’ 4730 04 22: OCTET STRING, encapsulates { 4732 04 20: OCTET STRING : B0 7F 9F 24 D8 8D C7 0C 23 4C 25 BE 69 2C C6 AD : 34 6C 87 70 : } : } 4754 30 31: SEQUENCE { 4756 06 3: OBJECT IDENTIFIER ’2 5 29 35’ 4761 04 24: OCTET STRING, encapsulates { 4763 30 22: SEQUENCE { 4765 80 20: [0] : 48 01 19 9F C4 DF 2B 64 7C FC 45 E3 5B 2F AF 02 : 81 C8 C5 94 : } : } : } 4787 30 59: SEQUENCE { 4789 06 3: OBJECT IDENTIFIER ’2 5 29 31’ 4794 04 52: OCTET STRING, encapsulates { 4796 30 50: SEQUENCE { 4798 30 48: SEQUENCE { 4800 A0 46: [0] { 4802 A0 44: [0] { 4804 86 42: [6] : ’’ : } : } : } : } : } : } 4848 30 66: SEQUENCE { 4850 06 8: OBJECT IDENTIFIER ’1 3 6 1 5 5 7 1 1’ 4860 04 54: OCTET STRING, encapsulates { 4862 30 52: SEQUENCE { 4864 30 50: SEQUENCE { 4866 06 8: OBJECT IDENTIFIER ’1 3 6 1 5 5 7 48 2’ 4876 86 38: [6] ’’ : } : } : } : } : } : } : } 4916 30 10: SEQUENCE { 4918 06 6: OBJECT IDENTIFIER ’1 2 643 2 2 3’ 4926 05 0: NULL : } 4928 03 65: BIT STRING 0 unused bits : E6 F0 FE CA 95 F8 D8 85 1E B4 7D 18 17 D4 72 5C : 02 FB 2B 71 20 5C D8 53 07 F6 80 6F C0 1A 44 2A : D3 B3 57 09 D0 89 77 FD B3 0D F9 22 86 E7 69 2C : 03 A4 E9 21 93 F5 0A 0C 35 E9 47 32 61 A5 04 DC : } : } 4995 31 223: SET { 4998 30 220: SEQUENCE { 5001 02 1: INTEGER 1 5004 30 125: SEQUENCE { 5006 30 111: SEQUENCE { 5008 31 30: SET { 5010 30 28: SEQUENCE { 5012 06 9: OBJECT IDENTIFIER ’1 2 840 113549 1 9 1’ 5023 16 15: IA5String ’’ : } : } 5040 31 11: SET { 5042 30 9: SEQUENCE { 5044 06 3: OBJECT IDENTIFIER ’2 5 4 6’ 5049 13 2: PrintableString ’RU’ : } : } 5053 31 21: SET { 5055 30 19: SEQUENCE { 5057 06 3: OBJECT IDENTIFIER ’2 5 4 7’ 5062 13 12: PrintableString ’’ : } : } 5076 31 19: SET { 5078 30 17: SEQUENCE { 5080 06 3: OBJECT IDENTIFIER ’2 5 4 10’ 5085 13 10: PrintableString ’’ : } : } 5097 31 20: SET { 5099 30 18: SEQUENCE { 5101 06 3: OBJECT IDENTIFIER ’2 5 4 3’ 5106 13 11: PrintableString ’’ : } : } : } 5119 02 10: INTEGER : 79 8C DD 8A 00 00 00 00 35 D4 : } 5131 30 10: SEQUENCE { 5133 06 6: OBJECT IDENTIFIER ’1 2 643 2 2 9’ 5141 05 0: NULL : } 5143 30 10: SEQUENCE { 5145 06 6: OBJECT IDENTIFIER ’1 2 643 2 2 19’ 5153 05 0: NULL : } 5155 04 64: OCTET STRING : 5E 10 01 81 A5 D1 A8 D5 99 8A 2D 3A 05 8C FA 81 : 76 77 66 1E 7C AC B4 25 08 32 2C 9D 5E 93 D6 9F : 1C 53 3C F6 56 04 D4 82 30 DB B4 C2 1A C1 66 F9 : 02 75 EE CA DE D8 7D 20 EB 60 D8 C3 A3 2B 23 1C : } : } : } : } : } Правильно ли я понимаю, что зашифрованный хэш - это последний OCTET STRING? | ||||
| ||||
1)Как именно Вы считываете ОК из сообщения? 2)Как Вы вытаскиваете хэш из PKCS7 для проверки? 3)Зашифрованный хэш ОБЯЗАТЕЛЬНО содержится в PKCS7. Почему Вы решили что его там нет? :) 4)Да, совершенно верно. | ||||
| ||||
1. и 2. - Я просто вытаскиваю последовательность байтов из PKCS#7-сообщения, т.е. своими функциями я считываю данные из этого сообщения. Причем, считанные мною данные эквивалентны данным, которые показывает dumpasn1, за исключением того, что я представляю открытыый ключ (D3 F5 27...) и зашифрованный хэш (5E 10 01...) не в 16-й системе счисления, а в виде последовательности байтов, как они и шли в исходном сообщении. 3. - Уже сам осознал, что глупость сморозил :) Но: я низкоуровневыми функциями сформировал зашифрованную хэш-последовательность и попробовал найти ее в PKCS#7-сообщении (просто открыл в блокноте это сообщение/файл и через поиск попробовал искать). Или это мое заблуждение, что так можно найти хэш? | ||||
| ||||
Не надо поля PKCS7 вытаскивать своими функциями :) Есть набор низкоуровневых функций CryptMsg* которые позволяют все это сделать. Кстати можете попробовать ими и сравнить с результатом, который возвращает Ваш разбор. Найти можно, но тут надо иметь ввиду такой факт - если 2 раза подписать один и тот же текст гостовой подписью с одним и тем же ключем - получатся разные подписи. | ||||
| ||||
Я знаю, что есть низкоуровневые функции для работы с PKCS#7 сообщениями, но мне пришлось от них отказаться по некоторым причинам. Я вот заметил, что хэш получается разным. А как тогда проверяет подпись, например, CryptVerifyMessage. Я понимаю, что с помощью CryptMsg***, но ведь эти функции основаны на самых низкоуровневых криптографических функциях. И как-то ведь проверяется подпись, сформированная с ГОСТовским алгоритмом. И еще: что значит "подписать готовой подписью"? | ||||
| ||||
Если не вдаваться в математику, то проверяются след. образом: расшифровывается зашифрованный хэш, еще один хэш считается от сообщения и они сраниваются. "подписать гостовой подписью" - я имел ввиду по алгоритму ГОСТ Р3411/Р3410. | ||||
| ||||
Извените, не так прочитал (я про "готовую" подпись :). | ||||
| ||||
В принципе это я так и представлял :) Но ведь не суть каким функциями я пользуюсь - CryptVerifyMessage или CryptVerifySignature. Конечный результат ведь должен быть одним и тем же. У меня все-равно первостепенная задача - импортировать открытый ключ. Пожалуйста, подскажите что можно сделать с этим. | ||||
| ||||
Конечно одним и тем же. Я бы воспользовался функциями CryptMsg*. dumpasn1 показывает раскодированный ASN.1 ОК (что логично), в то время как CryptImportPublicKeyInfo хочет закодированный. | ||||
| ||||
Смотрите, если я буду пользоваться CryptMsg**, то: что будет, если я буду открывать сообщение (CryptMsgOpenToDecode) не передавая криптопровайдер. Просто у меня выдается "Неизвестный криптографический алгоритм" (или что-то в этом роде - я уже не помню). Именно по этим причинам я и отказался от этих функций. | ||||
| ||||
А туда и не надо передавать хэндл провайдера, без этого работает, если конечно провайдер присутствует в системе. | ||||
| ||||
Нет, Вы не правы. Если в системе установлено несколько криптопровайдеров, то эти функции попросту не работают - "Указан неправильный алгоритм". | ||||
| ||||
Работают... посмотрите наш csptest для примера. | ||||
| ||||
Я ничего не говорил про ваш пример. Конечно, он будет работать с Вашим криптопровайдером. Но я же сказал, что эти функции не работают, когда на компьютере стоит два или более российских криптопровайдера. Если бы все было так просто, то я бы и не поднимал эту тему :) | ||||
| ||||
И так, продолжим нашу беседу :) На компьютере стоит несколько российских криптопровайдеров, КриптоПРО установлен последним. Функции CryptMsg** и CryptVerifyMessageSignature не работают. Поэтому я вручную вытаскиваю зашифрованный хэш из сообщения, данные, которые подписывались. Заново формирую хэш, потом вызываю функцию проверки подписи (код этого момента указан во втором сообщении). Хэш, который я сам вытаскиваю из сообщения совпадает с хэшем, который возвращает функция CryptMsgGetParam. В чем может быть причина того, что функция CryptVerifySignature возвращает "Неправильная подпись". Заранее благодарен. | ||||