From 38dac94fcd255e2777f44d71c44c5fd966fb9b13 Mon Sep 17 00:00:00 2001 From: "berezuev.aleksey" Date: Mon, 21 Jul 2025 12:31:31 +0300 Subject: [PATCH 1/3] ignore vendor and IDE folders --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3422073 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea +.vscode + +vendor/ +composer.lock \ No newline at end of file From 674504a6c51f899488858f4aceb565b78e4ccc97 Mon Sep 17 00:00:00 2001 From: "berezuev.aleksey" Date: Mon, 21 Jul 2025 12:31:50 +0300 Subject: [PATCH 2/3] CryptoPro improve performance: use hashmap, remove redudant condition --- src/CryptoPro.php | 322 +++++++++++++++++++++++----------------------- 1 file changed, 160 insertions(+), 162 deletions(-) diff --git a/src/CryptoPro.php b/src/CryptoPro.php index 5b71355..a1c71e7 100644 --- a/src/CryptoPro.php +++ b/src/CryptoPro.php @@ -74,166 +74,166 @@ class CryptoPro */ protected array $methods = [ // Глобальные опции - 'help', // Печатает справку по программе - 'notime', // Не отображать время выполнения + 'help' => true, // Печатает справку по программе + 'notime' => true, // Не отображать время выполнения // Команды, специфичные для режима - 'lowenc', // Тестирование низкоуровневого шифрования/дешифрования - 'sfenc', // Упрощенное шифрование/дешифрование сообщений - 'lowsign', // Тестирование низкоуровневого подписания сообщений - 'sfsign', // Упрощенное подписание/проверка подписей сообщений - 'cmssfsign', // Упрощенное подписания/проверка подписей сообщений (устарело) - 'ipsec', // Тесты IPSec - 'defprov', // Манипуляции с дефолтным провайдером - 'property', // Получение/установка свойств сертификата для секретного ключа - 'mk', // Инициализация получения хэша (или вычисление хэша файла в Cpverify) - 'hash', // Получение хеша файла (или посчитать хэши файлов в cryptcp) - 'alg', // Установить хэш-алгоритм (или алгоритм хэширования в Cpverify) - 'certkey', // Изменить имя провайдера в сертификате секретного ключа - 'absorb', // Поглощение всех сертификатов из контейнеров с секретным ключом - 'tlss', // Запуск TLS сервера - 'tlsc', // Запуск TLS клиента - 'certlic', // Информация о лицензии сертификата - 'rc', // Проверка подписи PKCS#10/сертификата - 'minica', // Тест выпуска сертификатов - 'certprop', // Показать свойства сертификата - 'sfse', // Упрощенное тестирование SignedAndEnveloped сообщений - 'oid', // Получение/установка информации об OID - 'change', // Изменить пароль - 'passwd', // Установить или изменить пароль - 'keycopy', // Копирование контейнера - 'keyset', // Создать или открыть ключевой контейнер - 'card', // Информация о считывателях карт - 'enum', // Перечисление параметров CSP - 'perf', // Производственные тесты - 'speed', // Тесты скорости и установка оптимальной маски функции + 'lowenc' => true, // Тестирование низкоуровневого шифрования/дешифрования + 'sfenc' => true, // Упрощенное шифрование/дешифрование сообщений + 'lowsign' => true, // Тестирование низкоуровневого подписания сообщений + 'sfsign' => true, // Упрощенное подписание/проверка подписей сообщений + 'cmssfsign' => true, // Упрощенное подписания/проверка подписей сообщений (устарело) + 'ipsec' => true, // Тесты IPSec + 'defprov' => true, // Манипуляции с дефолтным провайдером + 'property' => true, // Получение/установка свойств сертификата для секретного ключа + 'mk' => true, // Инициализация получения хэша (или вычисление хэша файла в Cpverify) + 'hash' => true, // Получение хеша файла (или посчитать хэши файлов в cryptcp) + 'alg' => true, // Установить хэш-алгоритм (или алгоритм хэширования в Cpverify) + 'certkey' => true, // Изменить имя провайдера в сертификате секретного ключа + 'absorb' => true, // Поглощение всех сертификатов из контейнеров с секретным ключом + 'tlss' => true, // Запуск TLS сервера + 'tlsc' => true, // Запуск TLS клиента + 'certlic' => true, // Информация о лицензии сертификата + 'rc' => true, // Проверка подписи PKCS#10/сертификата + 'minica' => true, // Тест выпуска сертификатов + 'certprop' => true, // Показать свойства сертификата + 'sfse' => true, // Упрощенное тестирование SignedAndEnveloped сообщений + 'oid' => true, // Получение/установка информации об OID + 'change' => true, // Изменить пароль + 'passwd' => true, // Установить или изменить пароль + 'keycopy' => true, // Копирование контейнера + 'keyset' => true, // Создать или открыть ключевой контейнер + 'card' => true, // Информация о считывателях карт + 'enum' => true, // Перечисление параметров CSP + 'perf' => true, // Производственные тесты + 'speed' => true, // Тесты скорости и установка оптимальной маски функции // Дополнительные команды: - 'ask', // Получить контекст csp с помощью моего сертификата (по умолчанию: нет) - 'in', // Входной файл - 'out', // Выходной файл - 'add', // Добавить сертификат - 'attached', // Встроенная подпись - 'detached', // Отсоединенная подпись - 'base64', // Ввод/вывод с преобразованием base64<->DER - 'addsigtime', // Добавить атрибут времени подписи - 'cades_strict', // Строгая генерация атрибута signingCertificateV2 - 'cades_disable', // Отключить генерацию атрибута signingCertificateV2 - 'display_content', // Данные, которые должны отображаться на носителе/считывателе, встроены в содержимое сообщения - 'sign', // Подписать сообщение (или создать подписанное сообщение в cryptcp) - 'my', // Сертификат текущего пользователя - 'MY', // Сертификат локальной машины - 'CERT', // Часть имени поля Common Name или отпечаток сертификата - 'provname', // Имя провайдера (или имя криптопровайдера в Cpverify/cryptcp) - 'provtype', // Тип провайдера (или тип криптопровайдера в Cpverify/cryptcp) - 'cont', // Путь к контейнеру (или имя контейнера в Cpverify/cryptcp) - 'machinekeys', // Ключи на локальной машине - 'enum_cont', // Перечислить контейнеры - 'verifycontext', // Открытый контекст только для проверки - 'fqcn', // Отобразить полное имя контейнера - 'check', // Проверить контейнер - 'password', // Указать пароль - 'deletekeyset', // Удалить контейнер - 'container', // Имя контейнера - 'contsrc', // Имя исходного контейнера (весь путь) - 'contdest', // Имя конечного контейнера (весь путь) - 'verify', // Проверить файл с подписью (или проверить подпись сообщения/файла в cryptcp/Cpverify) - 'pinsrc', // Пароль исходного контейнера - 'pindest', // Пароль конечного контейнера - 'silent', // Не отображать пользовательский интерфейс - 'req_compliant', // Предварительный просмотр файла перед подписью/проверкой и проверка цепочки сертификатов (работает только с опцией '-detached') - 'list', // Получить список сертификатов - 'store', // Выбрать хранилище сертификатов + 'ask' => true, // Получить контекст csp с помощью моего сертификата (по умолчанию: нет) + 'in' => true, // Входной файл + 'out' => true, // Выходной файл + 'add' => true, // Добавить сертификат + 'attached' => true, // Встроенная подпись + 'detached' => true, // Отсоединенная подпись + 'base64' => true, // Ввод/вывод с преобразованием base64<->DER + 'addsigtime' => true, // Добавить атрибут времени подписи + 'cades_strict' => true, // Строгая генерация атрибута signingCertificateV2 + 'cades_disable' => true, // Отключить генерацию атрибута signingCertificateV2 + 'display_content' => true, // Данные, которые должны отображаться на носителе/считывателе, встроены в содержимое сообщения + 'sign' => true, // Подписать сообщение (или создать подписанное сообщение в cryptcp) + 'my' => true, // Сертификат текущего пользователя + 'MY' => true, // Сертификат локальной машины + 'CERT' => true, // Часть имени поля Common Name или отпечаток сертификата + 'provname' => true, // Имя провайдера (или имя криптопровайдера в Cpverify/cryptcp) + 'provtype' => true, // Тип провайдера (или тип криптопровайдера в Cpverify/cryptcp) + 'cont' => true, // Путь к контейнеру (или имя контейнера в Cpverify/cryptcp) + 'machinekeys' => true, // Ключи на локальной машине + 'enum_cont' => true, // Перечислить контейнеры + 'verifycontext' => true, // Открытый контекст только для проверки + 'fqcn' => true, // Отобразить полное имя контейнера + 'check' => true, // Проверить контейнер + 'password' => true, // Указать пароль + 'deletekeyset' => true, // Удалить контейнер + 'container' => true, // Имя контейнера + 'contsrc' => true, // Имя исходного контейнера (весь путь) + 'contdest' => true, // Имя конечного контейнера (весь путь) + 'verify' => true, // Проверить файл с подписью (или проверить подпись сообщения/файла в cryptcp/Cpverify) + 'pinsrc' => true, // Пароль исходного контейнера + 'pindest' => true, // Пароль конечного контейнера + 'silent' => true, // Не отображать пользовательский интерфейс + 'req_compliant' => true, // Предварительный просмотр файла перед подписью/проверкой и проверка цепочки сертификатов (работает только с опцией '-detached') + 'list' => true, // Получить список сертификатов + 'store' => true, // Выбрать хранилище сертификатов // КриптоПро 5 версии (общие команды) - 'tls1_2', // Использование TLS 1.2 - 'tls1_3', // Использование TLS 1.3 - 'ecdsa', // Подпись с использованием алгоритма ECDSA - 'aes', // Шифрование с использованием алгоритма AES - 'rsa', // Шифрование с использованием алгоритма RSA - 'ocsp', // Проверка статуса сертификата через OCSP - 'csr', // Генерация запроса на сертификат (CSR) - 'pkcs12', // Создание файла PKCS#12 - 'pkcs7', // Создание или проверка PKCS#7 подписи - 'signfile', // Подписать файл с помощью приватного ключа - 'verifyfile', // Проверка файла на наличие подписи - 'p12import', // Импорт PKCS#12 сертификатов - 'importkey', // Импорт приватного ключа - 'exportkey', // Экспорт приватного ключа - 'setprov', // Установить провайдер криптографии - 'getprov', // Получить информацию о текущем провайдере - 'backup', // Резервное копирование ключей - 'restore', // Восстановление ключей - 'log', // Записать лог операций - 'audit', // Аудит криптографических операций - 'timecheck', // Проверка времени подписания - 'signtime', // Время подписи - 'revoke', // Отозвать сертификат - 'expiry', // Проверка срока действия сертификата - 'validate', // Проверить корректность сертификата + 'tls1_2' => true, // Использование TLS 1.2 + 'tls1_3' => true, // Использование TLS 1.3 + 'ecdsa' => true, // Подпись с использованием алгоритма ECDSA + 'aes' => true, // Шифрование с использованием алгоритма AES + 'rsa' => true, // Шифрование с использованием алгоритма RSA + 'ocsp' => true, // Проверка статуса сертификата через OCSP + 'csr' => true, // Генерация запроса на сертификат (CSR) + 'pkcs12' => true, // Создание файла PKCS#12 + 'pkcs7' => true, // Создание или проверка PKCS#7 подписи + 'signfile' => true, // Подписать файл с помощью приватного ключа + 'verifyfile' => true, // Проверка файла на наличие подписи + 'p12import' => true, // Импорт PKCS#12 сертификатов + 'importkey' => true, // Импорт приватного ключа + 'exportkey' => true, // Экспорт приватного ключа + 'setprov' => true, // Установить провайдер криптографии + 'getprov' => true, // Получить информацию о текущем провайдере + 'backup' => true, // Резервное копирование ключей + 'restore' => true, // Восстановление ключей + 'log' => true, // Записать лог операций + 'audit' => true, // Аудит криптографических операций + 'timecheck' => true, // Проверка времени подписания + 'signtime' => true, // Время подписи + 'revoke' => true, // Отозвать сертификат + 'expiry' => true, // Проверка срока действия сертификата + 'validate' => true, // Проверить корректность сертификата // Cpverify команды - 'logfile', // Путь к файлу лога (заменяет вывод в stdout/stderr) - 'sleep', // Пауза перед началом выполнения (в миллисекундах) - 'wnd', // Показать окно с сообщением (MessageBox) - 'errwnd', // Показать MessageBox только при ошибке - // 'mk', // Дублируется выше, сохранено как первое описание - // 'verify', // Дублируется выше, сохранено как первое описание - 'rm', // Вычисление хэшей для файлов из реестра - 'addreg', // Сохранить хэш файла в реестре - 'delreg', // Удалить хэш файла из реестра - 'rv', // Проверка файлов из реестра - 'xm', // Вычисление хэшей и сохранение в XML - 'xv', // Проверка целостности по XML - 'x2r', // Копирование хэшей из XML в реестр - 'r2x', // Копирование хэшей из реестра в XML - 'file_sign', // Подпись файла с использованием контейнера - 'file_verify', // Проверка подписи файла - // 'alg', // Дублируется выше, сохранено как первое описание - 'inverted_halfbytes', // Реверс половинок байтов хэша (0 или 1) - // 'cont', // Дублируется выше, сохранено как первое описание - 'pin', // Пароль к контейнеру - // 'provname', // Дублируется выше, сохранено как первое описание - // 'provtype', // Дублируется выше, сохранено как первое описание - 'timestamp', // Дата подписи в формате dd.mm.yyyy - 'filename', // Имя основного файла для подписи/проверки/хэширования - 'hashvalue', // Явно указанный хэш (если не использовать .hsh) - 'signval', // Значение подписи (если не использовать .sgn) - 'catname', // Имя каталога (для групповых операций) - 'in_file', // Входной XML-файл - 'out_file', // Выходной XML-файл + 'logfile' => true, // Путь к файлу лога (заменяет вывод в stdout/stderr) + 'sleep' => true, // Пауза перед началом выполнения (в миллисекундах) + 'wnd' => true, // Показать окно с сообщением (MessageBox) + 'errwnd' => true, // Показать MessageBox только при ошибке + // 'mk' => true, // Дублируется выше, сохранено как первое описание + // 'verify' => true, // Дублируется выше, сохранено как первое описание + 'rm' => true, // Вычисление хэшей для файлов из реестра + 'addreg' => true, // Сохранить хэш файла в реестре + 'delreg' => true, // Удалить хэш файла из реестра + 'rv' => true, // Проверка файлов из реестра + 'xm' => true, // Вычисление хэшей и сохранение в XML + 'xv' => true, // Проверка целостности по XML + 'x2r' => true, // Копирование хэшей из XML в реестр + 'r2x' => true, // Копирование хэшей из реестра в XML + 'file_sign' => true, // Подпись файла с использованием контейнера + 'file_verify' => true, // Проверка подписи файла + // 'alg' => true, // Дублируется выше, сохранено как первое описание + 'inverted_halfbytes' => true, // Реверс половинок байтов хэша (0 или 1) + // 'cont' => true, // Дублируется выше, сохранено как первое описание + 'pin' => true, // Пароль к контейнеру + // 'provname' => true, // Дублируется выше, сохранено как первое описание + // 'provtype' => true, // Дублируется выше, сохранено как первое описание + 'timestamp' => true, // Дата подписи в формате dd.mm.yyyy + 'filename' => true, // Имя основного файла для подписи/проверки/хэширования + 'hashvalue' => true, // Явно указанный хэш (если не использовать .hsh) + 'signval' => true, // Значение подписи (если не использовать .sgn) + 'catname' => true, // Имя каталога (для групповых операций) + 'in_file' => true, // Входной XML-файл + 'out_file' => true, // Выходной XML-файл // Методы CryptCP (добавлены без дубликатов) - 'encr', // cryptcp: создать зашифрованное сообщение - 'decr', // cryptcp: расшифровать сообщение - // 'sign', // Дублируется (есть выше как 'Подписать сообщение'), но функциональность пересекается - // 'verify', // Дублируется (есть выше как 'Проверить файл с подписью'), но функциональность пересекается - 'addsign', // cryptcp: добавить подпись в сообщение - 'delsign', // cryptcp: удалить подпись из сообщения - 'addattr', // cryptcp: добавить в подпись неподписанный атрибут - 'signf', // cryptcp: создать подписи файлов в 'исходный_файл.sgn' - 'vsignf', // cryptcp: проверить подписи файлов, созданные с помощью команды '-signf' - 'addsignf', // cryptcp: добавить подпись файла в 'исходный_файл.sgn' - // 'hash', // Дублируется (есть выше как 'Получение хеша файла'), но функциональность пересекается - 'vhash', // cryptcp: проверить хэши файлов, созданные с помощью команды '-hash' - 'copycert', // cryptcp: скопировать сертификаты в заданное хранилище - 'cspcert', // cryptcp: скопировать сертификат из ключевого контейнера в хранилище - 'delcert', // cryptcp: удалить сертификат из хранилища - 'listdn', // cryptcp: вывести на экран политику имен КриптоПро УЦ - 'createuser', // cryptcp: зарегистрировать пользователя на КриптоПро УЦ - 'checkreg', // cryptcp: проверить состояние регистрации пользователя на КриптоПро УЦ - 'listtmpl', // cryptcp: вывести на экран шаблоны, доступные пользователю КриптоПро УЦ - 'createrqst', // cryptcp: создать запрос на сертификат и сохранить его в файле PKCS #10 - 'instcert', // cryptcp: установить сертификат из файла PKCS #7 или файла сертификата - 'createcert', // cryptcp: создать запрос на сертификат, отправить его в ЦС - 'pendcert', // cryptcp: проверить, не выпущен ли сертификат - 'sn', // cryptcp: сохранить/показать серийный номер лицензии - 'nochain', // cryptcp: не включать цепочку сертификатов - 'thumbprint', // cryptcp: выбор сертификата по отпечатку - - 'install', // certmgr: установить сертификат - 'delete', // certmgr: удалить сертификат - 'file' // certmgr: установить сертификат из файла + 'encr' => true, // cryptcp: создать зашифрованное сообщение + 'decr' => true, // cryptcp: расшифровать сообщение + // 'sign' => true, // Дублируется (есть выше как 'Подписать сообщение'), но функциональность пересекается + // 'verify' => true, // Дублируется (есть выше как 'Проверить файл с подписью'), но функциональность пересекается + 'addsign' => true, // cryptcp: добавить подпись в сообщение + 'delsign' => true, // cryptcp: удалить подпись из сообщения + 'addattr' => true, // cryptcp: добавить в подпись неподписанный атрибут + 'signf' => true, // cryptcp: создать подписи файлов в 'исходный_файл.sgn' + 'vsignf' => true, // cryptcp: проверить подписи файлов, созданные с помощью команды '-signf' + 'addsignf' => true, // cryptcp: добавить подпись файла в 'исходный_файл.sgn' + // 'hash' => true, // Дублируется (есть выше как 'Получение хеша файла'), но функциональность пересекается + 'vhash' => true, // cryptcp: проверить хэши файлов, созданные с помощью команды '-hash' + 'copycert' => true, // cryptcp: скопировать сертификаты в заданное хранилище + 'cspcert' => true, // cryptcp: скопировать сертификат из ключевого контейнера в хранилище + 'delcert' => true, // cryptcp: удалить сертификат из хранилища + 'listdn' => true, // cryptcp: вывести на экран политику имен КриптоПро УЦ + 'createuser' => true, // cryptcp: зарегистрировать пользователя на КриптоПро УЦ + 'checkreg' => true, // cryptcp: проверить состояние регистрации пользователя на КриптоПро УЦ + 'listtmpl' => true, // cryptcp: вывести на экран шаблоны, доступные пользователю КриптоПро УЦ + 'createrqst' => true, // cryptcp: создать запрос на сертификат и сохранить его в файле PKCS #10 + 'instcert' => true, // cryptcp: установить сертификат из файла PKCS #7 или файла сертификата + 'createcert' => true, // cryptcp: создать запрос на сертификат, отправить его в ЦС + 'pendcert' => true, // cryptcp: проверить, не выпущен ли сертификат + 'sn' => true, // cryptcp: сохранить/показать серийный номер лицензии + 'nochain' => true, // cryptcp: не включать цепочку сертификатов + 'thumbprint' => true, // cryptcp: выбор сертификата по отпечатку + + 'install' => true, // certmgr: установить сертификат + 'delete' => true, // certmgr: удалить сертификат + 'file' => true // certmgr: установить сертификат из файла ]; /** @@ -260,20 +260,18 @@ public function __construct(string $command = 'csptest') */ public function __call(string $name, array $arguments): self { - if (in_array($name, $this->methods)) { - $this->csp->addKey('-' . $name); - - // Если есть аргумент — добавь его тоже - if (!empty($arguments)) { - foreach ($arguments as $arg) { - $this->csp->addKey($arg); - } - } + if (!array_key_exists($name, $this->methods)) { + throw new BadMethodCallException("Метод '$name' не поддерживается"); + } - return $this; + $this->csp->addKey('-' . $name); + + // Если есть аргумент — добавь его тоже + foreach ($arguments as $arg) { + $this->csp->addKey($arg); } - throw new BadMethodCallException("Метод '$name' не поддерживается"); + return $this; } /** @@ -284,7 +282,7 @@ public function __call(string $name, array $arguments): self */ public function registerMethods(array $customMethods): self { - $this->methods = array_unique(array_merge($this->methods, $customMethods)); + $this->methods += $customMethods; return $this; } From 6235ce3a816a48c7f7e52a1bdbb73d91bc4c7724 Mon Sep 17 00:00:00 2001 From: "berezuev.aleksey" Date: Mon, 21 Jul 2025 13:00:55 +0300 Subject: [PATCH 3/3] fix bugs: return never on array, array to string conversion --- src/CryptoPro.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/CryptoPro.php b/src/CryptoPro.php index a1c71e7..685842b 100644 --- a/src/CryptoPro.php +++ b/src/CryptoPro.php @@ -706,13 +706,14 @@ public function addPatterns(array $patterns): self private function structureMatches(array $matches, array $fields): array { $chunkSize = count($fields); + $matchesSize = count($matches); if ($chunkSize === 0) { return []; // Невозможно структурировать без полей } // Проверяем, что количество совпадений кратно размеру чанка - if (count($matches) % $chunkSize !== 0) { - throw new RuntimeException("Несоответствие количества найденных совпадений ({count($matches)}) и ожидаемых полей ({$chunkSize}) для структурирования."); + if ($matchesSize % $chunkSize !== 0) { + throw new RuntimeException("Несоответствие количества найденных совпадений ({$matchesSize}) и ожидаемых полей ({$chunkSize}) для структурирования."); } $structuredData = []; @@ -746,7 +747,7 @@ public function run(): array return $this->success(); } - return $this->throwError(); + $this->throwError(); }