Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Alexey Khudyakov  
#1 Оставлено : 28 октября 2025 г. 14:30:27(UTC)
Alexey Khudyakov

Статус: Новичок

Группы: Участники
Зарегистрирован: 24.10.2025(UTC)
Сообщений: 3
Российская Федерация

Сказал(а) «Спасибо»: 2 раз
Здравствуйте, коллеги.

Подскажите, пожалуйста, советом.
Для подключения к API ЕПГУ при помощи СВОКС есть требование:
Цитата:

Подписать указанное значение с использованием закрытого ключа ИС организации с использованием алгоритмов ГОСТ Р 34.10-2012 и ГОСТ Р 34.11-2012 в формате PKCS#7 с открепленными данными;


Два вопроса:
- решает ли задачу подписания в формате PKCS#7 с открепленными данными команда cryptcp.x64.exe -sign -dn "CN=ООО «....»" -detached -cert -hashalg 1.2.643.7.1.1.2.2 INPUT_FILE.txt INPUT_FILE.sig ?
- в каком примере в samples-sources.jar можно подсмотреть реализацию подписания строки в формате PKCS#7 с открепленными данными? Я смотрел на пример ZapretInfoExample.java и пытался сделать по аналогии, но падает на подписании signature.sign();


Код:
        JCPInit.initProviders(false);

        InputStream privateKeyInputStream = SignUtilTest.class.getClassLoader().getResourceAsStream("static/test.pfx");
        KeyStore keyStore = KeyStore.getInstance(JCSP.PFX_STORE_NAME, JCSP.PROVIDER_NAME);
        keyStore.load(privateKeyInputStream, KEY_PASSWORD.toCharArray());
        //Получение всех CN из контейнера
        keyStore.aliases().asIterator().forEachRemaining(System.out::println);

        // Получение приватного ключа
        log.info("Получение приватного ключа...");
        PrivateKey privateKey = (PrivateKey) keyStore.getKey(ALIAS, KEY_PASSWORD.toCharArray());
        log.info("Приватный ключ успешно получен. Алгоритм приватного ключа: {}", privateKey.getAlgorithm());
        X509Certificate certificate = (X509Certificate) keyStore.getCertificate(ALIAS);


        final Signature signature = Signature.getInstance(JCP.GOST_SIGN_2012_256_NAME);
        signature.initSign(privateKey);
        signature.update(INPUT_DATA.getBytes(StandardCharsets.UTF_8));
        final byte[] sign = signature.sign();



Алгоритм приватного ключа: GOST3410DH_2012_256
Ошибка выглядит так:
Цитата:

java.security.SignatureException: Unsupported method.

at ru.CryptoPro.JCSP.Key.AbstractKeySpec.signature(Unknown Source)
at ru.CryptoPro.JCP.Sign.cl_0.engineSign(Unknown Source)
at java.base/java.security.Signature.sign(Signature.java:713)
at ru.sample.sign.util.SignUtilTest.shouldCreatePKCS7(SignUtilTest.java:149)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)


Версия КриптоПро Java CSP 5.0.42119-A
Версия BouncyCastle bcprov-jdk15on 1.60

Заранее спасибо.
Offline Евгений Афанасьев  
#2 Оставлено : 28 октября 2025 г. 17:48:13(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 4,064
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 21 раз
Поблагодарили: 740 раз в 698 постах
Добрый день.

По п.1 нужно сравнить получаемое сообщение с ожидаемым. Скорее всего, будет создана отделенная подпись PKCS7 или CMS на алгоритме ГОСТ 2012 (256).

Скорее всего, у вас провайдер по умолчанию - не JCSP, а JCP.
У Signature надо явно указать имя провайдера - JCSP.PROVIDER_NAME. Или задать в панели управления JCP (скрипт ControlPane) провайдер по умолчанию - JCSP.
thanks 1 пользователь поблагодарил Евгений Афанасьев за этот пост.
Alexey Khudyakov оставлено 28.10.2025(UTC)
Offline Alexey Khudyakov  
#3 Оставлено : 28 октября 2025 г. 18:16:15(UTC)
Alexey Khudyakov

Статус: Новичок

Группы: Участники
Зарегистрирован: 24.10.2025(UTC)
Сообщений: 3
Российская Федерация

Сказал(а) «Спасибо»: 2 раз
По пункту 1 - знать бы это ожидаемое... Разработка идет практически вслепую, спросить не у кого.

По ошибке: да, Вы правы, ошибка ушла если явно указать провайдер. Формируется и подписывается.
Однако, если проверять подпись с помощью cptools, то дает ошибку при проверке (0x80090008: Указан неправильный алгоритм.)

Полный код подписания:
Код:
    @Test
    void shouldCreatePKCS7() throws KeyStoreException, NoSuchProviderException, CertificateException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException, InvalidKeyException, SignatureException, Asn1Exception {
        JCPInit.initProviders(false);

        InputStream privateKeyInputStream = SignUtilTest.class.getClassLoader().getResourceAsStream("static/test.pfx");
        KeyStore keyStore = KeyStore.getInstance(JCSP.PFX_STORE_NAME, JCSP.PROVIDER_NAME);
        keyStore.load(privateKeyInputStream, KEY_PASSWORD.toCharArray());
        //Получение всех CN из контейнера
        keyStore.aliases().asIterator().forEachRemaining(System.out::println);

        // Получение приватного ключа
        log.info("Получение приватного ключа...");
        PrivateKey privateKey = (PrivateKey) keyStore.getKey(ALIAS, KEY_PASSWORD.toCharArray());
        log.info("Приватный ключ успешно получен. Алгоритм приватного ключа: {}", privateKey.getAlgorithm());
        X509Certificate certificate = (X509Certificate) keyStore.getCertificate(ALIAS);


        final Signature signature = Signature.getInstance(JCP.GOST_SIGN_2012_256_NAME, JCSP.PROVIDER_NAME);
        signature.initSign(privateKey);
        signature.update(INPUT_DATA.getBytes(StandardCharsets.UTF_8));
        final byte[] sign = signature.sign();

        // Формируем контекст подписи формата PKCS7.

        final ContentInfo all = new ContentInfo();
        all.contentType = new Asn1ObjectIdentifier(
                new OID(CMStools.STR_CMS_OID_SIGNED).value);

        final SignedData cms = new SignedData();
        all.content = cms;
        cms.version = new CMSVersion(1);

        // Идентификатор алгоритма хеширования.

        cms.digestAlgorithms = new DigestAlgorithmIdentifiers(1);
        final DigestAlgorithmIdentifier a = new DigestAlgorithmIdentifier(
                new OID(CMStools.DIGEST_OID).value);
        a.parameters = new Asn1Null();
        cms.digestAlgorithms.elements[0] = a;

        // Т.к. подпись отсоединенная, то содержимое отсутствует.

        cms.encapContentInfo = new EncapsulatedContentInfo(
                new Asn1ObjectIdentifier(new OID(CMStools.STR_CMS_OID_DATA).value), null);

        // Добавляем сертификат подписи.

        cms.certificates = new CertificateSet(1);
        final ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate asnCertificate =
                new ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate();

        final Asn1BerDecodeBuffer decodeBuffer =
                new Asn1BerDecodeBuffer(certificate.getEncoded());
        asnCertificate.decode(decodeBuffer);

        cms.certificates.elements = new CertificateChoices[1];
        cms.certificates.elements[0] = new CertificateChoices();
        cms.certificates.elements[0].set_certificate(asnCertificate);

        // Добавляем информацию о подписанте.

        cms.signerInfos = new SignerInfos(1);
        cms.signerInfos.elements[0] = new SignerInfo();
        cms.signerInfos.elements[0].version = new CMSVersion(1);
        cms.signerInfos.elements[0].sid = new SignerIdentifier();

        final byte[] encodedName = certificate.getIssuerX500Principal().getEncoded();
        final Asn1BerDecodeBuffer nameBuf = new Asn1BerDecodeBuffer(encodedName);
        final Name name = new Name();
        name.decode(nameBuf);

        final CertificateSerialNumber num = new CertificateSerialNumber(
                certificate.getSerialNumber());

        cms.signerInfos.elements[0].sid.set_issuerAndSerialNumber(
                new IssuerAndSerialNumber(name, num));
        cms.signerInfos.elements[0].digestAlgorithm =
                new DigestAlgorithmIdentifier(new OID(CMStools.DIGEST_OID).value);
        cms.signerInfos.elements[0].digestAlgorithm.parameters = new Asn1Null();
        cms.signerInfos.elements[0].signatureAlgorithm =
                new SignatureAlgorithmIdentifier(new OID(CMStools.SIGN_OID).value);
        cms.signerInfos.elements[0].signatureAlgorithm.parameters = new Asn1Null();
        cms.signerInfos.elements[0].signature = new SignatureValue(sign);

        final Asn1BerEncodeBuffer asnBuf = new Asn1BerEncodeBuffer();
        all.encode(asnBuf, true);
        byte[] result = asnBuf.getMsgCopy();

        Array.writeFile(FileUtils.getFile(FILE_FOR_SIGN), INPUT_DATA.getBytes(StandardCharsets.UTF_8));
        Array.writeFile(FileUtils.getFile(FILE_SIGNATURE_P7S), result);
    }
Offline Евгений Афанасьев  
#4 Оставлено : 28 октября 2025 г. 22:01:33(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 4,064
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 21 раз
Поблагодарили: 740 раз в 698 постах
0x80090008: Указан неправильный алгоритм.
Проверьте константы, которые участвуют в создании сообщения: DIGEST_OID, SIGN_OID. Это OID'ы для ГОСТ 2001, а надо, видимо, для ГОСТ 2012 (256): DIGEST_OID_2012_256, SIGN_OID_2012_256.
thanks 1 пользователь поблагодарил Евгений Афанасьев за этот пост.
Alexey Khudyakov оставлено 29.10.2025(UTC)
Offline Alexey Khudyakov  
#5 Оставлено : 29 октября 2025 г. 10:03:21(UTC)
Alexey Khudyakov

Статус: Новичок

Группы: Участники
Зарегистрирован: 24.10.2025(UTC)
Сообщений: 3
Российская Федерация

Сказал(а) «Спасибо»: 2 раз
Да, Вы снова правы.
Получилось, большое спасибо Вам!
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.