Статус: Новичок
Группы: Участники
Зарегистрирован: 21.10.2020(UTC) Сообщений: 6
|
День добрый всем. Подскажите как все правильно сделать при проверке подписи c помощью phpcades. Приходят данные в виде JWT-сообщения. Сообщение разделено точками на 3 части. Первая часть содержит информацию об алгоритме шифрования. Вторая часть - не зашифрованные данные. Третья часть - ЭЦП, которая подписывает первые две части, разделенных точкой. Есть публичный сертификат pub_cert.cer. Третью часть из base64 я преобразую в бинарный вид размером 64 байта (JWT.input.txt.sgn) и проверяю подпись сообщения (в файле JWT.input.txt) с помощью команды: Код:/opt/cprocsp/bin/amd64/csptestf -keys -verify GOST12_256 -in JWT.input.txt -signature JWT.input.txt.sgn -cert pub_cert.cer
Команда успешно отрабатывает, возвращая: Код:CSP (Type:80) v4.0.9017 KC2 Release Ver:4.0.9944 OS:Linux CPU:AMD64 FastCode:READY:SSSE3.
AcquireContext: OK. HCRYPTPROV: 28395443
GetProvParam(PP_NAME): Crypto-Pro GOST R 34.10-2012 KC2 CSP
Public key imported from cert file: Tokareva_200914.cer
Hash object created with alg: GOST12_256 0x8021
The data buffer has been hashed.
Signature was verified OK
Total: SYS: 0,000 sec USR: 0,000 sec UTC: 0,020 sec
[ErrorCode: 0x00000000]
Но хочется такую проверку делать не вызывая внешних утилит. Долго копался. Собрал php7.1 с поддержкой openssl + curl + gostengine. Руководствовался статьей https://cyber01.ru/kak-d...-2012-v-centos-redhat-7/Использую тестовый скрипт. Код:<?php
$sign = "ew0KICAiYWxnIjogImdvc3QzNC4xMC0yMDEyIiwNCiAgImtpZCI6ICIxRTRCMTJFQjczN0RBOEQ3MjBFRTNEOTQyQjQwQTQ0MDAzQzAxNkRCIg0KfQ.eyJxcmNJZCI6IkFEMTAwMDJQN0lNNTBENUw5NEw5VjhQU0dKT0lIVVVHIiwidHJ4SWQiOiJBMDI4ODA3MzcwMzk5ODAxMDAwMDA0NDgxODE1RkJB
MSIsImFtb3VudCI6MTAwLCJvcGVyYXRpb25JZCI6Mzc0MTk0MTAsInN0YXR1cyI6ImNvbXBsZXRlZCIsIm9wZXJhdGlvblRpbWVzdGFtcCI6IjIwMjAtMTAtMTRUMDc6Mzc6MDMuNzI5WiJ9.nhycHs6AZpOX7CJCPCPJII5jmxEmWAkKUhYbyPJVtqwkNozGPCtDMsQYjKcvmh0BXfQSr2ZPPNzJnsHkUnVvNQ";
$bs = explode('.', $sign);
$sign_info = $bs[0];
$sign_data = $bs[1];
$sign_sign = $bs[2];
// Конвертированная подпись из base64 в hex
$sign_sign_hex = "9e1c9c1ece80669397ec22423c23c9208e639b112658090a52161bc8f255b6ac24368cc63c2b4332c4188ca72f9a1d015df412af664f3cdcc99ec1e452756f35";
// Разделяем подпись пробелами группами по 2 цифры на байт
$splittedArray = str_split($sign_sign_hex, 2);
$sign_sign_split = implode(" ", $splittedArray);
// Вычисляем хэш сообщения по GOST
$digest = openssl_digest($sign_info . "." . $sign_data, 'GOST R 34.11-2012 with 256 bit hash', false);
$cert = new CPCertificate();
$cert->Import(file_get_contents("./pub_cert.cer"));
$hd = new CPHashedData();
$hd->set_Algorithm(HASH_ALGORITHM_GOSTR_3411);
$hd->SetHashValue($digest);
$rs = new CPRawSignature();
/*
Signature
[in] Значение электронной подписи в виде строки шестнадцатеричных цифр, группами по две цифры на байт, разделённых пробелами.
*/
$r = $rs->VerifyHash($hd, $sign_sign_split, $cert);
print("Result: $r\n");
Завершается ошибкой: Код:PHP Fatal error: Uncaught Exception: Invalid Signature. (0x80090006) in /home/open/www/cert/test_certificate.php:33
Stack trace:
#0 /home/open/www/cert/test_certificate.php(33): CPRawSignature->VerifyHash(Object(CPHashedData), '9e 1c 9c 1e ce ...', Object(CPCertificate))
#1 {main}
thrown in /home/open/www/cert/test_certificate.php on line 33
Ругается на не правильную подпись. Уже все перепробовал. Что я делаю не так?
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 13,683   Сказал «Спасибо»: 572 раз Поблагодарили: 2302 раз в 1803 постах
|
Здравствуйте.
HASH_ALGORITHM_GOSTR_3411 - ? Это 2001 или 2012 ?) |
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 13,683   Сказал «Спасибо»: 572 раз Поблагодарили: 2302 раз в 1803 постах
|
Цитата:// Разделяем подпись пробелами группами по 2 цифры на байт Зачем? |
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 13,683   Сказал «Спасибо»: 572 раз Поблагодарили: 2302 раз в 1803 постах
|
Автор: Андрей *  Цитата:// Разделяем подпись пробелами группами по 2 цифры на байт Зачем? понятно, из CPDN взято это описание. |
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 21.10.2020(UTC) Сообщений: 6
|
Автор: Андрей *  Здравствуйте.
HASH_ALGORITHM_GOSTR_3411 - ? Это 2001 или 2012 ?) Смотрел в исходниках, в /opt/cprocsp/src/phpcades/dllmain.cpp. Еще раз внимательно посмотрел. Оказалось, что есть еще одна константа CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256. Сейчас без ошибки отработал.
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 21.10.2020(UTC) Сообщений: 6
|
Автор: FreeZz  Автор: Андрей *  Здравствуйте.
HASH_ALGORITHM_GOSTR_3411 - ? Это 2001 или 2012 ?) Смотрел в исходниках, в /opt/cprocsp/src/phpcades/dllmain.cpp. Еще раз внимательно посмотрел. Оказалось, что есть еще одна константа CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256. Сейчас без ошибки отработал. Хм. Отработал без ошибки - это значит все нормально, видимо. В php когда функция null возвращает - это false, как всем известно. Просто в cpdn VerifyHash что-то возвращает. А php, видимо, придется try ... catch использовать.
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 21.10.2020(UTC) Сообщений: 6
|
Вот еще вопрос. В этой тестовом скрипте я использую функцию openssl Код:$digest = openssl_digest($sign_info . "." . $sign_data, 'GOST R 34.11-2012 with 256 bit hash', false);
А с помощью какого-то объекта и метода phpcades возможно получить такой не подписанный хэш?
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 21.10.2020(UTC) Сообщений: 6
|
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 26.11.2020(UTC) Сообщений: 6
|
@FreeZz А не могли бы поделиться кодом, что в итоге получилось
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 21.10.2020(UTC) Сообщений: 6
|
Автор: pz6tnk  @FreeZz А не могли бы поделиться кодом, что в итоге получилось Да, конечно. Привожу весь код тестового скрипта. Если не возникает исключения в try, то значит подпись была проверена. Сертификат Tokareva_200914.cer это сертификат в формате DER сгенерированный в Крипто Про, видимо, публичный без контейнера закрытого ключа. Его мне выдал банк. Как понять алгоритм 256 или 512 - я подбирал "методом тыка" через командную строку Код:
/opt/cprocsp/bin/amd64/csptestf -keys -verify GOST12_256 -in JWT.input.txt -signature JWT.input.txt.sgn -cert Tokareva_200914.cer
JWT.input.txt: Код:
ew0KICAiYWxnIjogImdvc3QzNC4xMC0yMDEyIiwNCiAgImtpZCI6ICIxRTRCMTJFQjczN0RBOEQ3MjBFRTNEOTQyQjQwQTQ0MDAzQzAxNkRCIg0KfQ.eyJxcmNJZCI6IkFEMTAwMDJQN0lNNTBENUw5NEw5VjhQU0dKT0lIVVVHIiwidHJ4SWQiOiJBMDI4ODA3MzcwMzk5ODAxMDAwMDA0NDgxODE1RkJBMSIsImFtb3VudCI6MTAwLCJvcGVyYXRpb25JZCI6Mzc0MTk0MTAsInN0YXR1cyI6ImNvbXBsZXRlZCIsIm9wZXJhdGlvblRpbWVzdGFtcCI6IjIwMjAtMTAtMTRUMDc6Mzc6MDMuNzI5WiJ9
Тестовый скрипт: Код:
<?php
$sign = "ew0KICAiYWxnIjogImdvc3QzNC4xMC0yMDEyIiwNCiAgImtpZCI6ICIxRTRCMTJFQjczN0RBOEQ3MjBFRTNEOTQyQjQwQTQ0MDAzQzAxNkRCIg0KfQ.eyJxcmNJZCI6IkFEMTAwMDJQN0lNNTBENUw5NEw5VjhQU0dKT0lIVVVHIiwidHJ4SWQiOiJBMDI4ODA3MzcwMzk5ODAxMDAwMDA0NDgxODE1RkJB
MSIsImFtb3VudCI6MTAwLCJvcGVyYXRpb25JZCI6Mzc0MTk0MTAsInN0YXR1cyI6ImNvbXBsZXRlZCIsIm9wZXJhdGlvblRpbWVzdGFtcCI6IjIwMjAtMTAtMTRUMDc6Mzc6MDMuNzI5WiJ9.nhycHs6AZpOX7CJCPCPJII5jmxEmWAkKUhYbyPJVtqwkNozGPCtDMsQYjKcvmh0BXfQSr2ZPPNzJnsHkUnVvNQ";
$message = "ew0KICAiYWxnIjogImdvc3QzNC4xMC0yMDEyIiwNCiAgImtpZCI6ICIxRTRCMTJFQjczN0RBOEQ3MjBFRTNEOTQyQjQwQTQ0MDAzQzAxNkRCIg0KfQ.eyJxcmNJZCI6IkFEMTAwMDJQN0lNNTBENUw5NEw5VjhQU0dKT0lIVVVHIiwidHJ4SWQiOiJBMDI4ODA3MzcwMzk5ODAxMDAwMDA0NDgxODE1R
kJBMSIsImFtb3VudCI6MTAwLCJvcGVyYXRpb25JZCI6Mzc0MTk0MTAsInN0YXR1cyI6ImNvbXBsZXRlZCIsIm9wZXJhdGlvblRpbWVzdGFtcCI6IjIwMjAtMTAtMTRUMDc6Mzc6MDMuNzI5WiJ9";
$bs = explode('.', $sign);
$sign_info = $bs[0];
$sign_data = $bs[1];
$sign_sign = $bs[2];
$cert = new CPCertificate();
$cert->Import(file_get_contents("./Tokareva_200914.cer"));
// Конвертированная подпись из base64 в hex
$sign_sign_hex = "9e1c9c1ece80669397ec22423c23c9208e639b112658090a52161bc8f255b6ac24368cc63c2b4332c4188ca72f9a1d015df412af664f3cdcc99ec1e452756f35";
// Разделяем подпись пробелами группами по 2 цифры на байт
$splittedArray = str_split($sign_sign_hex, 2);
$sign_sign_split = implode(" ", $splittedArray);
// Вычисляем хэш сообщения по GOST через пересобранный с gostengine opensll 1.1.0h
//$digest = openssl_digest($sign_info . "." . $sign_data, 'GOST R 34.11-2012 with 256 bit hash', false);
//print("OPENSSL Digest: " . $digest . "\n");
//
// Вычисляем хэш полученных не зашифрованных данных с помощью cadesphp
$hd1 = new CPHashedData();
$hd1->set_Algorithm(CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256);
$hd1->set_DataEncoding(BASE64_TO_BINARY);
$hd1->Hash(base64_encode($sign_info . "." . $sign_data));
print("CADES Hash: " . $hd1->get_Value() . "\n");
$digest = $hd1->get_Value();
$hd = new CPHashedData();
$hd->set_Algorithm(CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256);
$hd->SetHashValue($digest);
$rs = new CPRawSignature();
/*
Signature
[in] Значение электронной подписи в виде строки шестнадцатеричных цифр, группами по две цифры на байт, разделённых пробелами.
*/
try {
$r = $rs->VerifyHash($hd, $sign_sign_hex, $cert);
} catch(Exception $e) {
print("Error rised!\n");
printf($e->getMessage());
}
// 0x80091004 Invalid cryptographic message type Неправильный формат файла
// 0x80091010 The streamed cryptographic message is not ready to return data Пустой файл
// 0x80092002 CRYPT_E_BAD_ENCODE - An error occurred during encode or decode operation.
// 0x800B0100 TRUST_E_NOSIGNATURE - No signature was present in the subject.
// 0x80090006 NTE_BAD_SIGNATURE - Invalid Signature.
// 0x8009200B Не удается найти сертификат и закрытый ключ
Отредактировано пользователем 8 декабря 2020 г. 10:01:11(UTC)
| Причина: Не указана
|
|
|
|
Быстрый переход
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.
Important Information:
The Форум КриптоПро uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close