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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Скобелев Дмитрий  
#1 Оставлено : 23 мая 2021 г. 12:39:49(UTC)
Скобелев Дмитрий

Статус: Участник

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

Сказал(а) «Спасибо»: 1 раз
Пытаемся подписать хэш сообщения следующим кодом, тут проверку проходит.


Код:
fun signHashData(hashData: String, hashAlg: String): String? {
        Logger.log("Load key container to sign data.")
        // Тип контейнера по умолчанию.
        val keyStoreType: String = KeyStoreType.currentType()
        Logger.log("Default container type: $keyStoreType")

        // Загрузка ключа и сертификата.
        load(
            askPinInDialog, keyStoreType,
            currentAlias,
            null
        )
        if (privateKey == null) {
            Logger.log("Private key is null.")
            return null
        }

        // Формируем подпись.
        val chain = mutableListOf<X509Certificate>()

        if (certificates != null) {
            for (cert in certificates!!) {
                chain.add(cert as X509Certificate)
            }
        } else {
            chain.add(certificate!!)
        }
        var cAdESSignature = CAdESSignature(true, true) //Отсоединенная, подписываем хэш
        cAdESSignature.certificateStore =
            CollectionStore(mutableListOf(X509CertificateHolder(certificate!!.encoded)))
        Logger.log(
            "Single signature type: " +
                    if (cAdESType == CAdESType.CAdES_BES) "CAdES-BES" else "CAdES-X Long Type 1"
        )
        Logger.log(
            "Add one signer: " +
                    certificate!!.subjectDN+"\n public key Alg  "+certificate!!.publicKey.algorithm
        )

        if (cAdESType == CAdESType.CAdES_BES) {
            cAdESSignature.addSigner(
                JCSP.PROVIDER_NAME, null,
                null, privateKey, chain, cAdESType, null, false, null, null, null, true
            )
        }
        else {
            cAdESSignature.addSigner(
                JCSP.PROVIDER_NAME, null,
                null, privateKey, chain, cAdESType, CAdESSignVerifyPresenter.TSA_DEFAULT,
                false
            )
        }
        val signatureStream = ByteArrayOutputStream()
        Logger.log(
            "Compute signature for hash '" +
                    hashData + "\n" +
                    hashAlg
        )
        cAdESSignature.open(signatureStream)
        cAdESSignature.update(hashData.toByteArray()) //Возможно вот сюда нужно что-то другое вставлять?
        cAdESSignature.close()
        signatureStream.close()
        val sign = signatureStream.toByteArray()

        Logger.log(sign, true)
        Logger.log(sign.toString())

        // Проверяем подпись.
        Logger.log(
            "Verify CAdES signature of type: " +
                    if (cAdESType == CAdESType.CAdES_BES) "CAdES-BES" else "CAdES-X Long Type 1"
        )
        cAdESSignature = CAdESSignature(sign, hashData.toByteArray(), cAdESType, true)
        cAdESSignature.verify(chain)
        Logger.log("CAdES signature has been created and verified (OK)")
        return toBase64(sign)
    }


При попытке проверить через код
Код:

fun verify(
        dataInBase64: String?,
        signatureDataInBase64: String,
        isAttached: Boolean
    ): String {
        // Проверяем подпись.
        Logger.log(
            "Verify CAdES signature of type: " +
                    if (cAdESType == CAdESType.CAdES_BES) "CAdES-BES" else "CAdES-X Long Type 1"
        )
        val keyStoreType: String = KeyStoreType.currentType()

        load(
            askPinInDialog, keyStoreType,
            currentAlias,
            null
        )
        if (privateKey == null) {
            Logger.log("Private key is null.")
            return "null"
        }
        val chain = mutableListOf<X509Certificate>()
        if (certificates != null) {
            for (cert in certificates!!) {
                chain.add(cert as X509Certificate)
            }
        } else {
            chain.add(certificate!!)
        }
        val sign = signatureDataInBase64.replace("\n", "")
        val decodedSignature = Base64.getDecoder().decode(sign)
        val data =if (!isAttached) Base64.getDecoder().decode(dataInBase64) else null

        val cAdESSignature = CAdESSignature(decodedSignature, data, cAdESType)
        cAdESSignature.verify(chain)
        Logger.log("CAdES signature has been created and verified (OK)")
        return "true"
    }

подпись проверку не проходит. Так же не проходит проверку через инструменты КриптоПро - неверный хэш.
Не понятно как указать тип хэша для сертификата с открытым ключом ГОСТ Р 34.10-2012 256 бит (512 бит)
Как реализовать что-то подобное https://docs.cryptopro.r...-samples-cades-sign-hash
Просто отделенная подпись бинарных данных работает с тестовым сертификатом.
Код:
fun signData(dataInBase64: String, isAttached: Boolean): String? {
        Logger.log("Load key container to sign data.")
        // Тип контейнера по умолчанию.
        val keyStoreType: String = KeyStoreType.currentType()
        Logger.log("Default container type: $keyStoreType")

        // Загрузка ключа и сертификата.
        load(
            askPinInDialog, keyStoreType,
            currentAlias, null
        )
        if (privateKey == null) {
            Logger.log("Private key is null.")
            return null
        } // if

        // Формируем подпись.
        val chain = mutableListOf<X509Certificate>()
        val installedTrustCerts=InstallCAdESTestTrustCertExample(mcontext!!).getTrustCerts()
         //chain.add(installedTrustCerts.last())
        if (certificates != null) {
            for (cert in certificates!!) {
                chain.add(cert as X509Certificate)
            }
        } else {

            chain.add(certificate!!)
        }
        var cAdESSignature = CAdESSignature(!isAttached)
        cAdESSignature.certificateStore =
            CollectionStore(mutableListOf(X509CertificateHolder(certificate!!.encoded)))
        Logger.log(
            "Single signature type: " +
                    if (cAdESType == CAdESType.CAdES_BES) "CAdES-BES" else "CAdES-X Long Type 1"
        )
        Logger.log(
            "Add one signer: " +
                    certificate!!.subjectDN
        )
        if (cAdESType == CAdESType.CAdES_BES) {
            cAdESSignature.addSigner(
                JCSP.PROVIDER_NAME, null,
                null, privateKey, chain, cAdESType, null, false, null, null, null, true
            )
        }
        else {
            cAdESSignature.addSigner(
                JCSP.PROVIDER_NAME, null,
                null, privateKey, chain, cAdESType, CAdESSignVerifyPresenter.TSA_DEFAULT,
                false
            )
        }
        val signatureStream = ByteArrayOutputStream()
        Logger.log(
            "Compute signature for message '" +
                    dataInBase64 + "'"
        )
        cAdESSignature.open(signatureStream)
        val decodedBytes = Base64.getDecoder().decode(dataInBase64)
        cAdESSignature.update(decodedBytes)
        cAdESSignature.close()
        signatureStream.close()
        val sign = signatureStream.toByteArray()

        // Проверяем подпись.
        Logger.log(
            "Verify CAdES signature of type: " +
                    if (cAdESType == CAdESType.CAdES_BES) "CAdES-BES" else "CAdES-X Long Type 1"
        )
        val data= if (!isAttached) decodedBytes else null
        cAdESSignature = CAdESSignature(sign, data, cAdESType)
        cAdESSignature.verify(chain)
        Logger.log("CAdES подпись создана и проверена (OK)")
        return toBase64(sign)
    }



2. Попытка подписать бинарные данные действующим сертификатом info o sertifikate.txt (6kb) загружен 4 раз(а). приводит к ошибке, рутовые сертификаты устанавливаются при старте приложения root_certs.zip (3kb) загружен 1 раз(а).
Код:
I/JCP: ru.CryptoPro.JCP.pref.JCPPref.getBoolean :: System Preference Node: /ru/CryptoPro/reprov :: disable_tsp_cert_app_ext_checker = false
I/JCP: ru.CryptoPro.JCP.pref.JCPPref.getBoolean :: System Preference Node: /ru/CryptoPro/reprov :: disable_enroll_cert_type_ext_checker = false
W/System: A resource failed to call close. 
I/JCP: ru.CryptoPro.JCP.pref.JCPPref.getBoolean :: System Preference Node: /ru/CryptoPro/reprov :: disable_tsp_cert_app_ext_checker = false
I/JCP: ru.CryptoPro.JCP.pref.JCPPref.getBoolean :: System Preference Node: /ru/CryptoPro/reprov :: disable_enroll_cert_type_ext_checker = false
W/JCP: ru.CryptoPro.ssl.cl_39.<init> :: %% No appropriate keys for handshake
I/JCP: ru.CryptoPro.ssl.TrustManagerFactoryImpl.a :: trustStore is :  :: /data/user/0/ru.kck.signapp/security/cacerts
I/JCP: ru.CryptoPro.ssl.TrustManagerFactoryImpl.a :: trustStore type is :  :: BKS
I/JCP: ru.CryptoPro.ssl.TrustManagerFactoryImpl.a :: trustStore provider is :  :: 
I/JCP: ru.CryptoPro.ssl.TrustManagerFactoryImpl.a :: init truststore
W/JCP: ru.CryptoPro.ssl.pc_4.cl_4.<clinit> :: X.509 not found
    java.security.cert.CertificateException: X.509 not found
        at java.security.cert.CertificateFactory.getInstance(CertificateFactory.java:260)
******
Caused by: java.security.NoSuchAlgorithmException: The BC provider no longer provides an implementation for CertificateFactory.X.509.  Please see https://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html for more details.
        at sun.security.jca.Providers.checkBouncyCastleDeprecation(Providers.java:563)
        at sun.security.jca.Providers.checkBouncyCastleDeprecation(Providers.java:330)
        at java.security.cert.CertificateFactory.getInstance(CertificateFactory.java:254)
        	... 52 more
Validation failed for the target: 
    	serial: 43c3d60026adbe8449cb7479b2f73cc9
    	subject: SURNAME=Вавилова, GIVENNAME=Светлана Сергеевна, CN=ООО КСК ТЕХНОЛОГИИ, O=ООО КСК ТЕХНОЛОГИИ, L=Москва, ST=77 г. Москва, C=RU, EMAILADDRESS=s.vavilova@kck.ru, OID.1.2.643.3.131.1.1=#120C303037373138303634373937, OID.1.2.643.100.1=#120D31313537373436313231323436, OID.1.2.643.100.3=#120B3134383732313535343831
    	issuer: CN=Центральное информационно-техническое таможенное управление, O=Центральное информационно-техническое таможенное управление, STREET="ул. Новозаводская, д. 11/5", L=г. Москва, ST=77 Москва, C=RU, OID.1.2.643.3.131.1.1=#120C303037373330363534343731, OID.1.2.643.100.1=#120D31313137373436383839393431, EMAILADDRESS=vuc@ca.customs.ru
    	not before: Wed May 12 08:51:56 EDT 2021
    	not after: Fri Dec 31 07:51:56 EST 2021
    	signature provider: JCSP
    	validation date: null
    	revocation algorithm: CPPKIX
    	revocation validator: RevCheck
    	online: true
    For online validation by CRLDP parameter 'com.sun.security.enableCRLDP' (Oracle) or 'com.ibm.security.enableCRLDP' (IBM) must be set 'true' to enable or 'ocsp.enable' must be set 'true' (OCSP), or CRL passed for offline validation

Код:
System.setProperty("ru.CryptoPro.reprov.enableCRLDP", "true")
        System.setProperty("com.sun.security.enableCRLDP", "true")
        System.setProperty("com.ibm.security.enableCRLDP", "true")
        Security.setProperty("ocsp.enable", "true")

Отредактировано пользователем 23 мая 2021 г. 19:57:59(UTC)  | Причина: Не указана

Offline Евгений Афанасьев  
#2 Оставлено : 24 мая 2021 г. 14:49:41(UTC)
Евгений Афанасьев

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

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

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 583 раз в 554 постах
Здравствуйте.
1. hashAlg - хеш от data на алгоритме хеширования, соответствующем алгоритму ключа privateKey?
2. Лог выглядит так, будто:
А) вы установили cpSSL.jar - для CAdES он не нужен;
Б) в CRLDP в сертификатах цепочки есть https-ссылка, а не http (или выполняется переадресация на https), и она, при попытке скачать CRL для проверки цепочки сертификатов, загружает cpSSL. В сертификате должна быть по крайней одна рабочая https-ссылка на CRL.
Если нельзя выполнить п.(Б), то попробуйте удалить cpSSL.
Offline Скобелев Дмитрий  
#3 Оставлено : 24 мая 2021 г. 17:58:26(UTC)
Скобелев Дмитрий

Статус: Участник

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

Сказал(а) «Спасибо»: 1 раз
1. Да Screenshot_1621867330.png (314kb) загружен 8 раз(а)..
После декодирования подписи
Screenshot_1621868176.png (262kb) загружен 3 раз(а). sign.txt (5kb) загружен 0 раз(а).
из Base64 данный хэш присутствует в подписи в неизменном виде
Screenshot_162186787412.png (120kb) загружен 4 раз(а).
2. https ссылок не вижу в сертификате. Некоторые ссылки не доступны. Удаление cpSSL.jar приводит к ошибке error_class_load.txt (4kb) загружен 1 раз(а)..
Отключение
Код:
Security.setProperty(
            "ssl.KeyManagerFactory.algorithm",
            ru.CryptoPro.ssl.Provider.KEYMANGER_ALG
        )
        Security.setProperty(
            "ssl.TrustManagerFactory.algorithm",
            ru.CryptoPro.ssl.Provider.KEYMANGER_ALG
        )
        Security.setProperty("ssl.SocketFactory.provider", "ru.CryptoPro.ssl.SSLSocketFactoryImpl")
        Security.setProperty(
            "ssl.ServerSocketFactory.provider",
            "ru.CryptoPro.ssl.SSLServerSocketFactoryImpl"
        )
        if (Security.getProvider(ru.CryptoPro.ssl.Provider.PROVIDER_NAME) == null) {
            Security.addProvider(ru.CryptoPro.ssl.Provider())
        } 
тоже не решает проблемы

Отредактировано пользователем 24 мая 2021 г. 17:59:19(UTC)  | Причина: Не указана

Offline Евгений Афанасьев  
#4 Оставлено : 24 мая 2021 г. 21:22:07(UTC)
Евгений Афанасьев

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

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

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 583 раз в 554 постах
На счет п.2 я погорячился. Скорее всего, есть переадресация с http на https. Для инициализации провайдера вы используете CSPConfig.init или CSPConfig.initEx?
Offline Скобелев Дмитрий  
#5 Оставлено : 25 мая 2021 г. 7:22:16(UTC)
Скобелев Дмитрий

Статус: Участник

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

Сказал(а) «Спасибо»: 1 раз
CSPConfig.initEx, но пробовал и CSPConfig.init. Некоторые ссылки не доступны видимо из-за того что доступ к ним только из локальной сети? Может быть что программа упирается в недоступный ресурс и выдает ошибку или она проходит по всему списку?
В логах не всегда есть java.security.NoSuchAlgorithmException: The BC provider no longer provides an implementation for CertificateFactory.X.509. иногда просто Validation failed for the target.
После изучения форума так и не понял как включить режим FINE в логах, Пробовал менять уровень логирования в криптопровайдере (ACSP.apk)
Offline Евгений Афанасьев  
#6 Оставлено : 25 мая 2021 г. 8:37:50(UTC)
Евгений Афанасьев

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

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

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 583 раз в 554 постах
Включите логирование так https://docs.cryptopro.r...d/additional_information :
adb shell setprop log.tag.JCP DEBUG
Соберите лог из adb logcat и приложите тут.
Offline Скобелев Дмитрий  
#7 Оставлено : 25 мая 2021 г. 11:27:48(UTC)
Скобелев Дмитрий

Статус: Участник

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

Сказал(а) «Спасибо»: 1 раз
Прикладываю log.txt (137kb) загружен 4 раз(а).. Насколько вижу по логу цепочка строится, причину ошибки так и не увидел:(
Offline Скобелев Дмитрий  
#8 Оставлено : 27 мая 2021 г. 9:34:42(UTC)
Скобелев Дмитрий

Статус: Участник

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

Сказал(а) «Спасибо»: 1 раз
Добавил в подпись список отозванных сертификатов crl.zip (150kb) загружен 1 раз(а).
Код:
val setCRL=getCRLsFromAssets()
        cAdESSignature.setCRLStore(CollectionStore(setCRL))
        Logger.log(
            "Add one signer: " +
                    certificate!!.subjectDN
        )
        if (cAdESType == CAdESType.CAdES_BES) {
            cAdESSignature.addSigner(
                JCSP.PROVIDER_NAME, null,
                null, privateKey, chain, cAdESType, null, false, null, null, setCRL, true
            )
        }

Код:
private fun getCRLsFromAssets(): Set<X509CRL?> {
        val result: MutableSet<X509CRL?> = HashSet()
        val cf: CertificateFactory = CertificateFactory.getInstance("X509")
        try {
            val assetManager = mcontext!!.assets
            val files = assetManager.list(CRL_CERTS_DIRECTORY)

            if (files != null) {
                for (path in files) {
                    var crl: X509CRL
                    val cert = assetManager.open(CRL_CERTS_DIRECTORY + File.separator + path)

                    try {
                        crl = cf.generateCRL(cert) as X509CRL
                        result.add(crl)
                    }catch (ex: CertificateException){
                        Logger.log(ex.localizedMessage)
                    } finally {
                        if (cert != null) {
                            try {
                                cert.close()
                            } catch (e: IOException) {
                            }
                        } // if
                    }

                }
            }
        } catch (e: java.lang.Exception) {
            throw java.lang.Exception("Failed to retrieve any certificates from the input file", e)
        }
        return result
    }


Пробовал включенными и отключенными параметрами
Код:
/*  System.setProperty("ru.CryptoPro.reprov.enableCRLDP", "true")
        System.setProperty("com.sun.security.enableCRLDP", "true")
        System.setProperty("com.ibm.security.enableCRLDP", "true")
        System.setProperty(
            "com.sun.security.enableAIAcaIssuers",
            "true"
        ) // для загрузки сертификатов по AIA из сети
        System.setProperty(
            "com.ibm.security.enableAIAcaIssuers",
            "true"
        ) // для загрузки сертификатов по AIA из сети
        System.setProperty(
            "ru.CryptoPro.reprov.enableAIAcaIssuers",
            "true"
        ) // для загрузки сертификатов по AIA из сети
        Security.setProperty("ocsp.enable", "true")
*/

Ничего не помогает

Отредактировано пользователем 27 мая 2021 г. 11:44:21(UTC)  | Причина: Не указана

Offline Скобелев Дмитрий  
#9 Оставлено : 27 мая 2021 г. 9:46:36(UTC)
Скобелев Дмитрий

Статус: Участник

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

Сказал(а) «Спасибо»: 1 раз
При попытке подписать этим сертификатом через интент тоже ошибка
Screenshot_1622098154.png (225kb) загружен 6 раз(а).
Screenshot_1622098250.png (229kb) загружен 7 раз(а).
Screenshot_1622098341.png (223kb) загружен 4 раз(а).
Screenshot_1622097680.png (73kb) загружен 5 раз(а).
log2.txt (143kb) загружен 0 раз(а).

Отредактировано пользователем 27 мая 2021 г. 9:53:19(UTC)  | Причина: Не указана

Offline Скобелев Дмитрий  
#10 Оставлено : 7 июня 2021 г. 9:03:23(UTC)
Скобелев Дмитрий

Статус: Участник

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

Сказал(а) «Спасибо»: 1 раз
1. С подписанием конкретным сертификатом разобрались, там в CRL был редирект на https. Сделали проверку и скачивание списка отозванных сертификатов в папку приложения с последующей подстановкой в процессе подписи.
Если этот список находится в локальном хранилище и не просрочен, то запрос к серверу не требуется и его можно отключить через параметры.
Но если список отозванных сертификатов в локальном хранилище просрочен, и при этом отключена возможность подключиться к серверу для скачивания актуального списка, возникает ошибка.

Исходя из этого, уточняющий вопрос: можно ли отключить проверку/использование списка просроченных сертификатов?

2. Пока не нашли ответа на начальный вопрос в ветке - как правильно подписать хэш https://docs.cryptopro.r...-samples-cades-sign-hash для андроид версии.

Отредактировано пользователем 7 июня 2021 г. 9:08:09(UTC)  | Причина: Не указана

Offline Евгений Афанасьев  
#11 Оставлено : 7 июня 2021 г. 14:05:39(UTC)
Евгений Афанасьев

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

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

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 583 раз в 554 постах
Автор: Скобелев Дмитрий Перейти к цитате

можно ли отключить проверку/использование списка просроченных сертификатов?

В случае cades-подписи - нет. Так или иначе, цепочка сертификатов должна быть проверена. Вы, в принципе, можете оставить включенными параметры enableCRLDP: если есть доступ в сеть, то CRL будут скачаны, иначе - нет.
Автор: Скобелев Дмитрий Перейти к цитате

Пока не нашли ответа на начальный вопрос в ветке - как правильно подписать хэш https://docs.cryptopro.r...-samples-cades-sign-hash для андроид версии.

hashAlg в signHashData не надо перекодировать из base64, он уже перекодирован? Если хеш вычислен вами по данным с помощью MessageDigest, то попробуйте хешировать данные, как UTF-16LE.
https://support.cryptopr...etsja-v-kriptoarmcryptcp


Offline Скобелев Дмитрий  
#12 Оставлено : 16 июня 2021 г. 11:57:40(UTC)
Скобелев Дмитрий

Статус: Участник

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

Сказал(а) «Спасибо»: 1 раз
При подписи файла 1.txt (1kb) загружен 0 раз(а).
dataInBase64: 0LXRg9GL0LU=
получаем хэш ГОСТ Р 34.11-2012 256 - 8254466B9FE942F85BD6B8B243FE4D54966150E25BD3CE69D99462A698D9B5CB
при получении подписи хэша через cadesplugin

Код:
 signHash: function (sHashValue, hashAlg, certThumbprint) {
            const signHashByWebPlugin = function (sHashValue, hashAlg, certThumbprint) {
                return new Promise(function (resolve, reject) {
                    cadesplugin.async_spawn(function* (args) {
                        var oStore = yield cadesplugin.CreateObjectAsync("CAPICOM.Store");
                        yield oStore.Open(cadesplugin.CAPICOM_CURRENT_USER_STORE, cadesplugin.CAPICOM_MY_STORE,
                            cadesplugin.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED);

                        var oStoreCerts = yield oStore.Certificates;
                        var oCertificates = yield oStoreCerts.Find(
                            cadesplugin.CAPICOM_CERTIFICATE_FIND_SHA1_HASH, certThumbprint);
                        var certsCount = yield oCertificates.Count;
                        if (certsCount === 0) {
                            err = "Certificate not found: " + certThumbprint;
                            console.error(err);
                            return args[1](err);
                        }
                        var oCertificate = yield oCertificates.Item(1);

                        var oSigner = yield cadesplugin.CreateObjectAsync("CAdESCOM.CPSigner");
                        yield oSigner.propset_Certificate(oCertificate);
                        yield oSigner.propset_CheckCertificate(true);
                        // Сохраняем всю цепочку сертификатов https://docs.microsoft.com/ru-ru/windows/win32/seccrypto/signer-options
                        yield oSigner.propset_Options(cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN);


                        // Создаем объект CAdESCOM.HashedData
                        var oHashedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.HashedData");

                        // Инициализируем объект заранее вычисленным хэш-значением
                        // Алгоритм хэширования нужно указать до того, как будет передано хэш-значение
                        yield oHashedData.propset_Algorithm(hashAlg);
                        yield oHashedData.SetHashValue(sHashValue);

                        var oSignedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.CadesSignedData");
                        // Значение свойства ContentEncoding должно быть задано до заполнения свойства Content
                        //yield oSignedData.propset_ContentEncoding(cadesplugin.CADESCOM_BASE64_TO_BINARY);
                        //yield oSignedData.propset_Content(sHashValue);

                        var sSignedMessage = "";
                        try {
                            sSignedMessage = yield oSignedData.SignHash(oHashedData, oSigner, cadesplugin.CADESCOM_CADES_BES);
                            yield oStore.Close();
                        } catch (err) {
                            e = cadesplugin.getLastError(err);
                            console.error("Failed to create signature. Error: " + e);
                            yield oStore.Close();
                            return args[1](e);
                        }
                        return args[0](sSignedMessage);
                    }, resolve, reject);
                });
            };


получаем отсоединенную подпись 1server.txt.sig (3kb) загружен 1 раз(а). которую при сохранении как .sig можем проверить в CryptoTools

2021-06-16_153511.jpg (56kb) загружен 3 раз(а).

При попытке подписать этот же хеш этим же сертификатом, но через android

Код:
fun signHashData(hashData: String, hashAlg: String, currentAlias: String, pin: String?): String? {
        Logger.log("Load key container to sign data.")
        // Тип контейнера по умолчанию.
        val keyStoreType: String = KeyStoreType.currentType()
        Logger.log("Default container type: $keyStoreType")

        // Загрузка ключа и сертификата.
        if (pin != null) {
            load(
                false, keyStoreType,
                currentAlias, pin.toCharArray()
            )
        } else {
            load(
                true, keyStoreType,
                currentAlias, null
            )
        }
        if (privateKey == null) {
            Logger.log("Private key is null.")
            return null
        }

        // Формируем подпись.
        val chain = mutableListOf<X509Certificate>()

        if (certificates != null) {
            for (cert in certificates!!) {
                chain.add(cert as X509Certificate)
            }
        } else {
            chain.add(certificate!!)
        }
        var cAdESSignature = CAdESSignature(true, true)
        cAdESSignature.certificateStore =
            CollectionStore(mutableListOf(X509CertificateHolder(certificate!!.encoded)))

        val setCRL = getCRLsFromAssets()
        Logger.log(
            "Single signature type: " +
                    if (cAdESType == CAdESType.CAdES_BES) "CAdES-BES" else "CAdES-X Long Type 1"
        )
        Logger.log(
            "Add one signer: " +
                    certificate!!.subjectDN + "\n public key Alg  " + certificate!!.publicKey.algorithm
        )

        if (cAdESType == CAdESType.CAdES_BES) {
            cAdESSignature.addSigner(
                JCSP.PROVIDER_NAME, null,
                null, privateKey, chain, cAdESType, null, false, null, null, setCRL, true
            )
        } else {
            cAdESSignature.addSigner(
                JCSP.PROVIDER_NAME, null,
                null, privateKey, chain, cAdESType, CAdESSignVerifyPresenter.TSA_DEFAULT,
                false
            )
        }
        val signatureStream = ByteArrayOutputStream()
        Logger.log(
            "Compute signature for hash '" +
                    hashData + "\n" +
                    hashAlg
        )
        cAdESSignature.open(signatureStream)
        val encodedHash = toBase64(hashData.toByteArray())
        cAdESSignature.update(hashData.toByteArray())
        cAdESSignature.close()
        signatureStream.close()
        val sign = signatureStream.toByteArray()

        Logger.log(sign, true)

        // Проверяем подпись.
        Logger.log(
            "Verify CAdES signature of type: " +
                    if (cAdESType == CAdESType.CAdES_BES) "CAdES-BES" else "CAdES-X Long Type 1"
        )
        cAdESSignature = CAdESSignature(sign, hashData.toByteArray(), cAdESType, true)
        cAdESSignature.verify(chain, setCRL)
        Logger.log("CAdES signature has been created and verified (OK)")
        return toBase64(sign)
    }

получаем подпись, которая проходит проверку в данном методе, но не проходит проверку в CryptoTools - 1android.txt.sig (5kb) загружен 1 раз(а).
Screenshot_1623833118.jpg (322kb) загружен 1 раз(а).
2021-06-16_15351112.jpg (68kb) загружен 4 раз(а).

Пробовал перекодировать подписи из base64 и сравнить между собой, но видно только фрагменты данных
01.jpg (647kb) загружен 1 раз(а).
02.jpg (620kb) загружен 1 раз(а).

Пожалуйста, помогите разобраться.

Отредактировано пользователем 16 июня 2021 г. 12:00:17(UTC)  | Причина: Не указана

Offline Евгений Афанасьев  
#13 Оставлено : 29 июня 2021 г. 11:04:39(UTC)
Евгений Афанасьев

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

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

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 583 раз в 554 постах
Здравствуйте.
Я правильно понимаю, что основная проблема: вы делаете отделенную CAdES-подпись по хешу, но она не проверяется сторонним средством?
Offline Скобелев Дмитрий  
#14 Оставлено : 29 июня 2021 г. 13:55:27(UTC)
Скобелев Дмитрий

Статус: Участник

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

Сказал(а) «Спасибо»: 1 раз
Добрый день. Да.
Offline Евгений Афанасьев  
#15 Оставлено : 30 июня 2021 г. 17:45:44(UTC)
Евгений Афанасьев

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

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

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 583 раз в 554 постах
Сделал пример. Скорее всего, проблема в вашем случае в том, что неправильно подаются данные при проверке: для проверки подписи, выполненной по хешу, с тем же хешом, нужно вместо подписанных данных подавать тот же хеш. Или выбрать другой способ проверки - ниже проверка выполняется двумя способами.
Код:

import ru.CryptoPro.AdES.AdESConfig;
import ru.CryptoPro.CAdES.CAdESSignature;
import ru.CryptoPro.CAdES.CAdESType;
import ru.CryptoPro.JCP.JCP;
import ru.CryptoPro.JCP.KeyStore.JCPPrivateKeyEntry;
import ru.CryptoPro.JCP.params.JCPProtectionParameter;
import ru.CryptoPro.JCP.tools.Encoder;
import ru.CryptoPro.JCSP.JCSP;

import java.io.ByteArrayOutputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

public class RawCAdESExample {

    /**
    * Используется ГОСТ 2012 (256).
    */
    public static void main(String[] args) throws Exception {

        System.setProperty("com.sun.security.enableCRLDP", "true"); // используем CRL из CRL DP сертификата

        final String STORE_TYPE = JCSP.HD_STORE_NAME; // тип контейнера
        final String PROVIDER = JCSP.PROVIDER_NAME; // провайдер Java CSP
        final String ALIAS = "cades-2012-256"; // алиас ключа на алгоритме ГОСТ 2012 (256)
        final char[] PASSWORD = "password".toCharArray(); // пароль к ключу
        final byte[] DATA = "Hello, world!".getBytes(); // подписываемые данные

        // Задаем провайдер по умолчанию.

        AdESConfig.setDefaultProvider(PROVIDER);

        // Читаем закрытый ключ и цепочку сертификатов из контейнера.

        KeyStore keyStore = KeyStore.getInstance(STORE_TYPE, PROVIDER);
        keyStore.load(null, null);

        JCPProtectionParameter parameter = new JCPProtectionParameter(PASSWORD);
        JCPPrivateKeyEntry entry = (JCPPrivateKeyEntry) keyStore.getEntry(ALIAS, parameter);

        PrivateKey privateKey = entry.getPrivateKey();
        Certificate[] chain = entry.getCertificateChain();

        List<X509Certificate> certificates = new ArrayList<>();

        for (Certificate cert : chain) {
            certificates.add((X509Certificate) cert);
        } // for

        // Формируем отдельный хеш подписываемых данных на нужном
        // алгоритме ГОСТ 2012 (256). Он будет использован при подписи.

        MessageDigest md = MessageDigest.getInstance(
            JCP.GOST_DIGEST_2012_256_NAME, PROVIDER); // ГОСТ 2012 (256)

        final byte[] RAW_DIGEST = md.digest(DATA); // хеш данных

        // Создаем CAdES-BES подпись по хешу данных.

        CAdESSignature cAdESSignature = new CAdESSignature(true, true);

        cAdESSignature.addSigner( // добавляем подписанта
            PROVIDER,
            null,
            null,
            privateKey,
            certificates,
            CAdESType.CAdES_BES,
            null,
            false,
            null,
            null,
            null,
            true // добавляем цепочку сертификатов в подпись
        );

        ByteArrayOutputStream outSignatureStream = new ByteArrayOutputStream();
        cAdESSignature.open(outSignatureStream);

        cAdESSignature.update(RAW_DIGEST); // по хешу
        cAdESSignature.close();

        byte[] signature = outSignatureStream.toByteArray();
        System.out.println("%%% SIGNATURE:\n" + (new Encoder()).encode(signature));

        // 1. Проверка подписи по хешу.

        cAdESSignature = new CAdESSignature(signature, RAW_DIGEST, null, true); // используем хеш данных
        cAdESSignature.verify(null); // можно не задавать сертификаты, т.к. они есть в подписи

        System.out.println("%%% VERIFIED by HASH.");

        // 2. Проверка подписи по подписанным данным.

        cAdESSignature = new CAdESSignature(signature, DATA, null); // используем данные
        cAdESSignature.verify(null); // можно не задавать сертификаты, т.к. они есть в подписи

        System.out.println("%%% VERIFIED by DATA.");

    }
}

Результат проверки в cptools приложен cades_ver.jpg (95kb) загружен 10 раз(а).

Отредактировано пользователем 30 июня 2021 г. 18:00:04(UTC)  | Причина: Не указана

thanks 1 пользователь поблагодарил Евгений Афанасьев за этот пост.
Скобелев Дмитрий оставлено 01.07.2021(UTC)
Offline Скобелев Дмитрий  
#16 Оставлено : 1 июля 2021 г. 11:22:17(UTC)
Скобелев Дмитрий

Статус: Участник

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

Сказал(а) «Спасибо»: 1 раз
Добрый день.
Нашел ошибку.
hashData нужно не просто представлять в виде byteArray( hashData.toByteArray() ), а с помощью метода
Код:
fun hexStringToByteArray(s: String): ByteArray {
            val len = s.length
            val data = ByteArray(len / 2)
            var i = 0
            while (i < len) {
                data[i / 2] = ((Character.digit(s[i], 16) shl 4)
                        + Character.digit(s[i + 1], 16)).toByte()
                i += 2
            }
            return data
        }


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